]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_borrowck/src/region_infer/opaque_types.rs
Rollup merge of #104433 - TaKO8Ki:fix-104392, r=estebank
[rust.git] / compiler / rustc_borrowck / src / region_infer / opaque_types.rs
1 use rustc_data_structures::fx::FxHashMap;
2 use rustc_data_structures::vec_map::VecMap;
3 use rustc_hir::def_id::LocalDefId;
4 use rustc_hir::OpaqueTyOrigin;
5 use rustc_infer::infer::TyCtxtInferExt as _;
6 use rustc_infer::infer::{DefiningAnchor, InferCtxt};
7 use rustc_infer::traits::{Obligation, ObligationCause};
8 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
9 use rustc_middle::ty::visit::TypeVisitable;
10 use rustc_middle::ty::{
11     self, OpaqueHiddenType, OpaqueTypeKey, ToPredicate, Ty, TyCtxt, TypeFoldable,
12 };
13 use rustc_span::Span;
14 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
15 use rustc_trait_selection::traits::ObligationCtxt;
16
17 use super::RegionInferenceContext;
18
19 impl<'tcx> RegionInferenceContext<'tcx> {
20     /// Resolve any opaque types that were encountered while borrow checking
21     /// this item. This is then used to get the type in the `type_of` query.
22     ///
23     /// For example consider `fn f<'a>(x: &'a i32) -> impl Sized + 'a { x }`.
24     /// This is lowered to give HIR something like
25     ///
26     /// type f<'a>::_Return<'_a> = impl Sized + '_a;
27     /// fn f<'a>(x: &'a i32) -> f<'static>::_Return<'a> { x }
28     ///
29     /// When checking the return type record the type from the return and the
30     /// type used in the return value. In this case they might be `_Return<'1>`
31     /// and `&'2 i32` respectively.
32     ///
33     /// Once we to this method, we have completed region inference and want to
34     /// call `infer_opaque_definition_from_instantiation` to get the inferred
35     /// type of `_Return<'_a>`. `infer_opaque_definition_from_instantiation`
36     /// compares lifetimes directly, so we need to map the inference variables
37     /// back to concrete lifetimes: `'static`, `ReEarlyBound` or `ReFree`.
38     ///
39     /// First we map all the lifetimes in the concrete type to an equal
40     /// universal region that occurs in the concrete type's substs, in this case
41     /// this would result in `&'1 i32`. We only consider regions in the substs
42     /// in case there is an equal region that does not. For example, this should
43     /// be allowed:
44     /// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }`
45     ///
46     /// Then we map the regions in both the type and the subst to their
47     /// `external_name` giving `concrete_type = &'a i32`,
48     /// `substs = ['static, 'a]`. This will then allow
49     /// `infer_opaque_definition_from_instantiation` to determine that
50     /// `_Return<'_a> = &'_a i32`.
51     ///
52     /// There's a slight complication around closures. Given
53     /// `fn f<'a: 'a>() { || {} }` the closure's type is something like
54     /// `f::<'a>::{{closure}}`. The region parameter from f is essentially
55     /// ignored by type checking so ends up being inferred to an empty region.
56     /// Calling `universal_upper_bound` for such a region gives `fr_fn_body`,
57     /// which has no `external_name` in which case we use `'empty` as the
58     /// region to pass to `infer_opaque_definition_from_instantiation`.
59     #[instrument(level = "debug", skip(self, infcx), ret)]
60     pub(crate) fn infer_opaque_types(
61         &self,
62         infcx: &InferCtxt<'tcx>,
63         opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
64     ) -> VecMap<LocalDefId, OpaqueHiddenType<'tcx>> {
65         let mut result: VecMap<LocalDefId, OpaqueHiddenType<'tcx>> = VecMap::new();
66         for (opaque_type_key, (concrete_type, origin)) in opaque_ty_decls {
67             let substs = opaque_type_key.substs;
68             debug!(?concrete_type, ?substs);
69
70             let mut subst_regions = vec![self.universal_regions.fr_static];
71             let universal_substs = infcx.tcx.fold_regions(substs, |region, _| {
72                 if let ty::RePlaceholder(..) = region.kind() {
73                     // Higher kinded regions don't need remapping, they don't refer to anything outside of this the substs.
74                     return region;
75                 }
76                 let vid = self.to_region_vid(region);
77                 trace!(?vid);
78                 let scc = self.constraint_sccs.scc(vid);
79                 trace!(?scc);
80                 match self.scc_values.universal_regions_outlived_by(scc).find_map(|lb| {
81                     self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?)
82                 }) {
83                     Some(region) => {
84                         let vid = self.universal_regions.to_region_vid(region);
85                         subst_regions.push(vid);
86                         region
87                     }
88                     None => {
89                         subst_regions.push(vid);
90                         infcx.tcx.sess.delay_span_bug(
91                             concrete_type.span,
92                             "opaque type with non-universal region substs",
93                         );
94                         infcx.tcx.lifetimes.re_static
95                     }
96                 }
97             });
98
99             subst_regions.sort();
100             subst_regions.dedup();
101
102             let universal_concrete_type =
103                 infcx.tcx.fold_regions(concrete_type, |region, _| match *region {
104                     ty::ReVar(vid) => subst_regions
105                         .iter()
106                         .find(|ur_vid| self.eval_equal(vid, **ur_vid))
107                         .and_then(|ur_vid| self.definitions[*ur_vid].external_name)
108                         .unwrap_or(infcx.tcx.lifetimes.re_erased),
109                     _ => region,
110                 });
111
112             debug!(?universal_concrete_type, ?universal_substs);
113
114             let opaque_type_key =
115                 OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs };
116             let ty = infcx.infer_opaque_definition_from_instantiation(
117                 opaque_type_key,
118                 universal_concrete_type,
119                 origin,
120             );
121             // Sometimes two opaque types are the same only after we remap the generic parameters
122             // back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)`
123             // and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we only know that
124             // once we convert the generic parameters to those of the opaque type.
125             if let Some(prev) = result.get_mut(&opaque_type_key.def_id) {
126                 if prev.ty != ty {
127                     if !ty.references_error() {
128                         prev.report_mismatch(
129                             &OpaqueHiddenType { ty, span: concrete_type.span },
130                             infcx.tcx,
131                         );
132                     }
133                     prev.ty = infcx.tcx.ty_error();
134                 }
135                 // Pick a better span if there is one.
136                 // FIXME(oli-obk): collect multiple spans for better diagnostics down the road.
137                 prev.span = prev.span.substitute_dummy(concrete_type.span);
138             } else {
139                 result.insert(
140                     opaque_type_key.def_id,
141                     OpaqueHiddenType { ty, span: concrete_type.span },
142                 );
143             }
144         }
145         result
146     }
147
148     /// Map the regions in the type to named regions. This is similar to what
149     /// `infer_opaque_types` does, but can infer any universal region, not only
150     /// ones from the substs for the opaque type. It also doesn't double check
151     /// that the regions produced are in fact equal to the named region they are
152     /// replaced with. This is fine because this function is only to improve the
153     /// region names in error messages.
154     pub(crate) fn name_regions<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
155     where
156         T: TypeFoldable<'tcx>,
157     {
158         tcx.fold_regions(ty, |region, _| match *region {
159             ty::ReVar(vid) => {
160                 // Find something that we can name
161                 let upper_bound = self.approx_universal_upper_bound(vid);
162                 let upper_bound = &self.definitions[upper_bound];
163                 match upper_bound.external_name {
164                     Some(reg) => reg,
165                     None => {
166                         // Nothing exact found, so we pick the first one that we find.
167                         let scc = self.constraint_sccs.scc(vid);
168                         for vid in self.rev_scc_graph.as_ref().unwrap().upper_bounds(scc) {
169                             match self.definitions[vid].external_name {
170                                 None => {}
171                                 Some(region) if region.is_static() => {}
172                                 Some(region) => return region,
173                             }
174                         }
175                         region
176                     }
177                 }
178             }
179             _ => region,
180         })
181     }
182 }
183
184 pub trait InferCtxtExt<'tcx> {
185     fn infer_opaque_definition_from_instantiation(
186         &self,
187         opaque_type_key: OpaqueTypeKey<'tcx>,
188         instantiated_ty: OpaqueHiddenType<'tcx>,
189         origin: OpaqueTyOrigin,
190     ) -> Ty<'tcx>;
191 }
192
193 impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
194     /// Given the fully resolved, instantiated type for an opaque
195     /// type, i.e., the value of an inference variable like C1 or C2
196     /// (*), computes the "definition type" for an opaque type
197     /// definition -- that is, the inferred value of `Foo1<'x>` or
198     /// `Foo2<'x>` that we would conceptually use in its definition:
199     /// ```ignore (illustrative)
200     /// type Foo1<'x> = impl Bar<'x> = AAA;  // <-- this type AAA
201     /// type Foo2<'x> = impl Bar<'x> = BBB;  // <-- or this type BBB
202     /// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. }
203     /// ```
204     /// Note that these values are defined in terms of a distinct set of
205     /// generic parameters (`'x` instead of `'a`) from C1 or C2. The main
206     /// purpose of this function is to do that translation.
207     ///
208     /// (*) C1 and C2 were introduced in the comments on
209     /// `register_member_constraints`. Read that comment for more context.
210     ///
211     /// # Parameters
212     ///
213     /// - `def_id`, the `impl Trait` type
214     /// - `substs`, the substs  used to instantiate this opaque type
215     /// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
216     ///   `opaque_defn.concrete_ty`
217     #[instrument(level = "debug", skip(self))]
218     fn infer_opaque_definition_from_instantiation(
219         &self,
220         opaque_type_key: OpaqueTypeKey<'tcx>,
221         instantiated_ty: OpaqueHiddenType<'tcx>,
222         origin: OpaqueTyOrigin,
223     ) -> Ty<'tcx> {
224         if self.is_tainted_by_errors() {
225             return self.tcx.ty_error();
226         }
227
228         let definition_ty = instantiated_ty
229             .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false, origin)
230             .ty;
231
232         if !check_opaque_type_parameter_valid(
233             self.tcx,
234             opaque_type_key,
235             origin,
236             instantiated_ty.span,
237         ) {
238             return self.tcx.ty_error();
239         }
240
241         // Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs`
242         // on stable and we'd break that.
243         let OpaqueTyOrigin::TyAlias = origin else {
244             return definition_ty;
245         };
246         let def_id = opaque_type_key.def_id;
247         // This logic duplicates most of `check_opaque_meets_bounds`.
248         // FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely.
249         let param_env = self.tcx.param_env(def_id);
250         let body_id = self.tcx.local_def_id_to_hir_id(def_id);
251         // HACK This bubble is required for this tests to pass:
252         // type-alias-impl-trait/issue-67844-nested-opaque.rs
253         let infcx =
254             self.tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).build();
255         let ocx = ObligationCtxt::new(&infcx);
256         // Require the hidden type to be well-formed with only the generics of the opaque type.
257         // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
258         // hidden type is well formed even without those bounds.
259         let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()))
260             .to_predicate(infcx.tcx);
261
262         let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id.to_def_id());
263
264         // Require that the hidden type actually fulfills all the bounds of the opaque type, even without
265         // the bounds that the function supplies.
266         let opaque_ty = self.tcx.mk_opaque(def_id.to_def_id(), id_substs);
267         if let Err(err) = ocx.eq(
268             &ObligationCause::misc(instantiated_ty.span, body_id),
269             param_env,
270             opaque_ty,
271             definition_ty,
272         ) {
273             infcx
274                 .err_ctxt()
275                 .report_mismatched_types(
276                     &ObligationCause::misc(instantiated_ty.span, body_id),
277                     opaque_ty,
278                     definition_ty,
279                     err,
280                 )
281                 .emit();
282         }
283
284         ocx.register_obligation(Obligation::misc(
285             instantiated_ty.span,
286             body_id,
287             param_env,
288             predicate,
289         ));
290
291         // Check that all obligations are satisfied by the implementation's
292         // version.
293         let errors = ocx.select_all_or_error();
294
295         // This is still required for many(half of the tests in ui/type-alias-impl-trait)
296         // tests to pass
297         let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
298
299         if errors.is_empty() {
300             definition_ty
301         } else {
302             let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
303             self.tcx.ty_error_with_guaranteed(reported)
304         }
305     }
306 }
307
308 fn check_opaque_type_parameter_valid(
309     tcx: TyCtxt<'_>,
310     opaque_type_key: OpaqueTypeKey<'_>,
311     origin: OpaqueTyOrigin,
312     span: Span,
313 ) -> bool {
314     match origin {
315         // No need to check return position impl trait (RPIT)
316         // because for type and const parameters they are correct
317         // by construction: we convert
318         //
319         // fn foo<P0..Pn>() -> impl Trait
320         //
321         // into
322         //
323         // type Foo<P0...Pn>
324         // fn foo<P0..Pn>() -> Foo<P0...Pn>.
325         //
326         // For lifetime parameters we convert
327         //
328         // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
329         //
330         // into
331         //
332         // type foo::<'p0..'pn>::Foo<'q0..'qm>
333         // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
334         //
335         // which would error here on all of the `'static` args.
336         OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true,
337         // Check these
338         OpaqueTyOrigin::TyAlias => {}
339     }
340     let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
341     let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
342     for (i, arg) in opaque_type_key.substs.iter().enumerate() {
343         let arg_is_param = match arg.unpack() {
344             GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
345             GenericArgKind::Lifetime(lt) if lt.is_static() => {
346                 tcx.sess
347                     .struct_span_err(span, "non-defining opaque type use in defining scope")
348                     .span_label(
349                         tcx.def_span(opaque_generics.param_at(i, tcx).def_id),
350                         "cannot use static lifetime; use a bound lifetime \
351                                     instead or remove the lifetime parameter from the \
352                                     opaque type",
353                     )
354                     .emit();
355                 return false;
356             }
357             GenericArgKind::Lifetime(lt) => {
358                 matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
359             }
360             GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)),
361         };
362
363         if arg_is_param {
364             seen_params.entry(arg).or_default().push(i);
365         } else {
366             // Prevent `fn foo() -> Foo<u32>` from being defining.
367             let opaque_param = opaque_generics.param_at(i, tcx);
368             tcx.sess
369                 .struct_span_err(span, "non-defining opaque type use in defining scope")
370                 .span_note(
371                     tcx.def_span(opaque_param.def_id),
372                     &format!(
373                         "used non-generic {} `{}` for generic parameter",
374                         opaque_param.kind.descr(),
375                         arg,
376                     ),
377                 )
378                 .emit();
379             return false;
380         }
381     }
382
383     for (_, indices) in seen_params {
384         if indices.len() > 1 {
385             let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
386             let spans: Vec<_> = indices
387                 .into_iter()
388                 .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
389                 .collect();
390             tcx.sess
391                 .struct_span_err(span, "non-defining opaque type use in defining scope")
392                 .span_note(spans, &format!("{} used multiple times", descr))
393                 .emit();
394             return false;
395         }
396     }
397     true
398 }