]>
Commit | Line | Data |
---|---|---|
c295e0f8 | 1 | use rustc_data_structures::fx::FxHashMap; |
17df50a5 | 2 | use rustc_data_structures::vec_map::VecMap; |
c295e0f8 XL |
3 | use rustc_hir::OpaqueTyOrigin; |
4 | use rustc_infer::infer::opaque_types::OpaqueTypeDecl; | |
74b04a01 | 5 | use rustc_infer::infer::InferCtxt; |
c295e0f8 | 6 | use rustc_middle::ty::subst::GenericArgKind; |
17df50a5 | 7 | use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable}; |
74b04a01 | 8 | use rustc_span::Span; |
ba9703b0 | 9 | use rustc_trait_selection::opaque_types::InferCtxtExt; |
74b04a01 XL |
10 | |
11 | use super::RegionInferenceContext; | |
12 | ||
13 | impl<'tcx> RegionInferenceContext<'tcx> { | |
14 | /// Resolve any opaque types that were encountered while borrow checking | |
15 | /// this item. This is then used to get the type in the `type_of` query. | |
16 | /// | |
17 | /// For example consider `fn f<'a>(x: &'a i32) -> impl Sized + 'a { x }`. | |
18 | /// This is lowered to give HIR something like | |
19 | /// | |
20 | /// type f<'a>::_Return<'_a> = impl Sized + '_a; | |
21 | /// fn f<'a>(x: &'a i32) -> f<'static>::_Return<'a> { x } | |
22 | /// | |
23 | /// When checking the return type record the type from the return and the | |
24 | /// type used in the return value. In this case they might be `_Return<'1>` | |
25 | /// and `&'2 i32` respectively. | |
26 | /// | |
27 | /// Once we to this method, we have completed region inference and want to | |
28 | /// call `infer_opaque_definition_from_instantiation` to get the inferred | |
29 | /// type of `_Return<'_a>`. `infer_opaque_definition_from_instantiation` | |
30 | /// compares lifetimes directly, so we need to map the inference variables | |
31 | /// back to concrete lifetimes: `'static`, `ReEarlyBound` or `ReFree`. | |
32 | /// | |
33 | /// First we map all the lifetimes in the concrete type to an equal | |
34 | /// universal region that occurs in the concrete type's substs, in this case | |
35 | /// this would result in `&'1 i32`. We only consider regions in the substs | |
36 | /// in case there is an equal region that does not. For example, this should | |
37 | /// be allowed: | |
38 | /// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }` | |
39 | /// | |
40 | /// Then we map the regions in both the type and the subst to their | |
41 | /// `external_name` giving `concrete_type = &'a i32`, | |
42 | /// `substs = ['static, 'a]`. This will then allow | |
43 | /// `infer_opaque_definition_from_instantiation` to determine that | |
44 | /// `_Return<'_a> = &'_a i32`. | |
45 | /// | |
46 | /// There's a slight complication around closures. Given | |
47 | /// `fn f<'a: 'a>() { || {} }` the closure's type is something like | |
48 | /// `f::<'a>::{{closure}}`. The region parameter from f is essentially | |
49 | /// ignored by type checking so ends up being inferred to an empty region. | |
50 | /// Calling `universal_upper_bound` for such a region gives `fr_fn_body`, | |
51 | /// which has no `external_name` in which case we use `'empty` as the | |
52 | /// region to pass to `infer_opaque_definition_from_instantiation`. | |
c295e0f8 XL |
53 | #[instrument(level = "debug", skip(self, infcx))] |
54 | pub(crate) fn infer_opaque_types( | |
74b04a01 XL |
55 | &self, |
56 | infcx: &InferCtxt<'_, 'tcx>, | |
c295e0f8 | 57 | opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>, |
74b04a01 | 58 | span: Span, |
17df50a5 | 59 | ) -> VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>> { |
74b04a01 XL |
60 | opaque_ty_decls |
61 | .into_iter() | |
c295e0f8 | 62 | .filter_map(|(opaque_type_key, decl)| { |
17df50a5 | 63 | let substs = opaque_type_key.substs; |
c295e0f8 | 64 | let concrete_type = decl.concrete_ty; |
6a06907d | 65 | debug!(?concrete_type, ?substs); |
74b04a01 XL |
66 | |
67 | let mut subst_regions = vec![self.universal_regions.fr_static]; | |
136023e0 XL |
68 | let universal_substs = infcx.tcx.fold_regions(substs, &mut false, |region, _| { |
69 | let vid = self.universal_regions.to_region_vid(region); | |
70 | subst_regions.push(vid); | |
71 | self.definitions[vid].external_name.unwrap_or_else(|| { | |
72 | infcx | |
73 | .tcx | |
74 | .sess | |
75 | .delay_span_bug(span, "opaque type with non-universal region substs"); | |
76 | infcx.tcx.lifetimes.re_static | |
77 | }) | |
78 | }); | |
74b04a01 XL |
79 | |
80 | subst_regions.sort(); | |
81 | subst_regions.dedup(); | |
82 | ||
83 | let universal_concrete_type = | |
fc512014 | 84 | infcx.tcx.fold_regions(concrete_type, &mut false, |region, _| match *region { |
74b04a01 XL |
85 | ty::ReVar(vid) => subst_regions |
86 | .iter() | |
87 | .find(|ur_vid| self.eval_equal(vid, **ur_vid)) | |
88 | .and_then(|ur_vid| self.definitions[*ur_vid].external_name) | |
89 | .unwrap_or(infcx.tcx.lifetimes.re_root_empty), | |
136023e0 | 90 | _ => region, |
74b04a01 XL |
91 | }); |
92 | ||
6a06907d | 93 | debug!(?universal_concrete_type, ?universal_substs); |
74b04a01 | 94 | |
17df50a5 XL |
95 | let opaque_type_key = |
96 | OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs }; | |
74b04a01 | 97 | let remapped_type = infcx.infer_opaque_definition_from_instantiation( |
17df50a5 | 98 | opaque_type_key, |
74b04a01 XL |
99 | universal_concrete_type, |
100 | span, | |
101 | ); | |
c295e0f8 XL |
102 | |
103 | check_opaque_type_parameter_valid( | |
104 | infcx.tcx, | |
105 | opaque_type_key, | |
106 | OpaqueTypeDecl { concrete_ty: remapped_type, ..decl }, | |
107 | ) | |
108 | .then_some((opaque_type_key, remapped_type)) | |
74b04a01 XL |
109 | }) |
110 | .collect() | |
111 | } | |
112 | ||
113 | /// Map the regions in the type to named regions. This is similar to what | |
114 | /// `infer_opaque_types` does, but can infer any universal region, not only | |
115 | /// ones from the substs for the opaque type. It also doesn't double check | |
116 | /// that the regions produced are in fact equal to the named region they are | |
117 | /// replaced with. This is fine because this function is only to improve the | |
118 | /// region names in error messages. | |
c295e0f8 | 119 | pub(crate) fn name_regions<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T |
74b04a01 XL |
120 | where |
121 | T: TypeFoldable<'tcx>, | |
122 | { | |
fc512014 | 123 | tcx.fold_regions(ty, &mut false, |region, _| match *region { |
74b04a01 | 124 | ty::ReVar(vid) => { |
f035d41b XL |
125 | // Find something that we can name |
126 | let upper_bound = self.approx_universal_upper_bound(vid); | |
c295e0f8 XL |
127 | let upper_bound = &self.definitions[upper_bound]; |
128 | match upper_bound.external_name { | |
129 | Some(reg) => reg, | |
130 | None => { | |
131 | // Nothing exact found, so we pick the first one that we find. | |
132 | let scc = self.constraint_sccs.scc(vid); | |
133 | for vid in self.rev_scc_graph.as_ref().unwrap().upper_bounds(scc) { | |
134 | match self.definitions[vid].external_name { | |
135 | None => {} | |
136 | Some(&ty::ReStatic) => {} | |
137 | Some(region) => return region, | |
138 | } | |
139 | } | |
140 | region | |
141 | } | |
142 | } | |
74b04a01 XL |
143 | } |
144 | _ => region, | |
145 | }) | |
146 | } | |
147 | } | |
c295e0f8 XL |
148 | |
149 | fn check_opaque_type_parameter_valid( | |
150 | tcx: TyCtxt<'_>, | |
151 | opaque_type_key: OpaqueTypeKey<'_>, | |
152 | decl: OpaqueTypeDecl<'_>, | |
153 | ) -> bool { | |
154 | match decl.origin { | |
155 | // No need to check return position impl trait (RPIT) | |
156 | // because for type and const parameters they are correct | |
157 | // by construction: we convert | |
158 | // | |
159 | // fn foo<P0..Pn>() -> impl Trait | |
160 | // | |
161 | // into | |
162 | // | |
163 | // type Foo<P0...Pn> | |
164 | // fn foo<P0..Pn>() -> Foo<P0...Pn>. | |
165 | // | |
166 | // For lifetime parameters we convert | |
167 | // | |
168 | // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm> | |
169 | // | |
170 | // into | |
171 | // | |
172 | // type foo::<'p0..'pn>::Foo<'q0..'qm> | |
173 | // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>. | |
174 | // | |
175 | // which would error here on all of the `'static` args. | |
176 | OpaqueTyOrigin::FnReturn | OpaqueTyOrigin::AsyncFn => return true, | |
177 | // Check these | |
178 | OpaqueTyOrigin::TyAlias => {} | |
179 | } | |
180 | let span = decl.definition_span; | |
181 | let opaque_generics = tcx.generics_of(opaque_type_key.def_id); | |
182 | let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default(); | |
183 | for (i, arg) in opaque_type_key.substs.iter().enumerate() { | |
184 | let arg_is_param = match arg.unpack() { | |
185 | GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), | |
186 | GenericArgKind::Lifetime(ty::ReStatic) => { | |
187 | tcx.sess | |
188 | .struct_span_err(span, "non-defining opaque type use in defining scope") | |
189 | .span_label( | |
190 | tcx.def_span(opaque_generics.param_at(i, tcx).def_id), | |
191 | "cannot use static lifetime; use a bound lifetime \ | |
192 | instead or remove the lifetime parameter from the \ | |
193 | opaque type", | |
194 | ) | |
195 | .emit(); | |
196 | return false; | |
197 | } | |
198 | GenericArgKind::Lifetime(lt) => { | |
199 | matches!(lt, ty::ReEarlyBound(_) | ty::ReFree(_)) | |
200 | } | |
201 | GenericArgKind::Const(ct) => matches!(ct.val, ty::ConstKind::Param(_)), | |
202 | }; | |
203 | ||
204 | if arg_is_param { | |
205 | seen_params.entry(arg).or_default().push(i); | |
206 | } else { | |
207 | // Prevent `fn foo() -> Foo<u32>` from being defining. | |
208 | let opaque_param = opaque_generics.param_at(i, tcx); | |
209 | tcx.sess | |
210 | .struct_span_err(span, "non-defining opaque type use in defining scope") | |
211 | .span_note( | |
212 | tcx.def_span(opaque_param.def_id), | |
213 | &format!( | |
214 | "used non-generic {} `{}` for generic parameter", | |
215 | opaque_param.kind.descr(), | |
216 | arg, | |
217 | ), | |
218 | ) | |
219 | .emit(); | |
220 | return false; | |
221 | } | |
222 | } | |
223 | ||
224 | for (_, indices) in seen_params { | |
225 | if indices.len() > 1 { | |
226 | let descr = opaque_generics.param_at(indices[0], tcx).kind.descr(); | |
227 | let spans: Vec<_> = indices | |
228 | .into_iter() | |
229 | .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id)) | |
230 | .collect(); | |
231 | tcx.sess | |
232 | .struct_span_err(span, "non-defining opaque type use in defining scope") | |
233 | .span_note(spans, &format!("{} used multiple times", descr)) | |
234 | .emit(); | |
235 | return false; | |
236 | } | |
237 | } | |
238 | true | |
239 | } |