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::error_reporting::unexpected_hidden_region_diagnostic;
6 use rustc_infer::infer::TyCtxtInferExt as _;
7 use rustc_infer::infer::{DefiningAnchor, InferCtxt};
8 use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine};
9 use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
10 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts};
11 use rustc_middle::ty::visit::TypeVisitable;
12 use rustc_middle::ty::{
13 self, OpaqueHiddenType, OpaqueTypeKey, ToPredicate, Ty, TyCtxt, TypeFoldable,
16 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
17 use rustc_trait_selection::traits::TraitEngineExt as _;
19 use super::RegionInferenceContext;
21 impl<'tcx> RegionInferenceContext<'tcx> {
22 /// Resolve any opaque types that were encountered while borrow checking
23 /// this item. This is then used to get the type in the `type_of` query.
25 /// For example consider `fn f<'a>(x: &'a i32) -> impl Sized + 'a { x }`.
26 /// This is lowered to give HIR something like
28 /// type f<'a>::_Return<'_a> = impl Sized + '_a;
29 /// fn f<'a>(x: &'a i32) -> f<'static>::_Return<'a> { x }
31 /// When checking the return type record the type from the return and the
32 /// type used in the return value. In this case they might be `_Return<'1>`
33 /// and `&'2 i32` respectively.
35 /// Once we to this method, we have completed region inference and want to
36 /// call `infer_opaque_definition_from_instantiation` to get the inferred
37 /// type of `_Return<'_a>`. `infer_opaque_definition_from_instantiation`
38 /// compares lifetimes directly, so we need to map the inference variables
39 /// back to concrete lifetimes: `'static`, `ReEarlyBound` or `ReFree`.
41 /// First we map all the lifetimes in the concrete type to an equal
42 /// universal region that occurs in the concrete type's substs, in this case
43 /// this would result in `&'1 i32`. We only consider regions in the substs
44 /// in case there is an equal region that does not. For example, this should
46 /// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }`
48 /// Then we map the regions in both the type and the subst to their
49 /// `external_name` giving `concrete_type = &'a i32`,
50 /// `substs = ['static, 'a]`. This will then allow
51 /// `infer_opaque_definition_from_instantiation` to determine that
52 /// `_Return<'_a> = &'_a i32`.
54 /// There's a slight complication around closures. Given
55 /// `fn f<'a: 'a>() { || {} }` the closure's type is something like
56 /// `f::<'a>::{{closure}}`. The region parameter from f is essentially
57 /// ignored by type checking so ends up being inferred to an empty region.
58 /// Calling `universal_upper_bound` for such a region gives `fr_fn_body`,
59 /// which has no `external_name` in which case we use `'empty` as the
60 /// region to pass to `infer_opaque_definition_from_instantiation`.
61 #[instrument(level = "debug", skip(self, infcx))]
62 pub(crate) fn infer_opaque_types(
64 infcx: &InferCtxt<'_, 'tcx>,
65 opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>,
66 ) -> VecMap<LocalDefId, OpaqueHiddenType<'tcx>> {
67 let mut result: VecMap<LocalDefId, OpaqueHiddenType<'tcx>> = VecMap::new();
68 for (opaque_type_key, (concrete_type, origin)) in opaque_ty_decls {
69 let substs = opaque_type_key.substs;
70 debug!(?concrete_type, ?substs);
72 let mut subst_regions = vec![self.universal_regions.fr_static];
73 let universal_substs = infcx.tcx.fold_regions(substs, |region, _| {
74 if let ty::RePlaceholder(..) = region.kind() {
75 // Higher kinded regions don't need remapping, they don't refer to anything outside of this the substs.
78 let vid = self.to_region_vid(region);
80 let scc = self.constraint_sccs.scc(vid);
82 match self.scc_values.universal_regions_outlived_by(scc).find_map(|lb| {
83 self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?)
86 let vid = self.universal_regions.to_region_vid(region);
87 subst_regions.push(vid);
91 subst_regions.push(vid);
92 infcx.tcx.sess.delay_span_bug(
94 "opaque type with non-universal region substs",
96 infcx.tcx.lifetimes.re_static
101 subst_regions.sort();
102 subst_regions.dedup();
104 let universal_concrete_type =
105 infcx.tcx.fold_regions(concrete_type, |region, _| match *region {
106 ty::ReVar(vid) => subst_regions
108 .find(|ur_vid| self.eval_equal(vid, **ur_vid))
109 .and_then(|ur_vid| self.definitions[*ur_vid].external_name)
110 .unwrap_or(infcx.tcx.lifetimes.re_root_empty),
114 debug!(?universal_concrete_type, ?universal_substs);
116 let opaque_type_key =
117 OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs };
118 let ty = infcx.infer_opaque_definition_from_instantiation(
120 universal_concrete_type,
123 // Sometimes two opaque types are the same only after we remap the generic parameters
124 // back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)`
125 // and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we only know that
126 // once we convert the generic parameters to those of the opaque type.
127 if let Some(prev) = result.get_mut(&opaque_type_key.def_id) {
129 if !ty.references_error() {
130 prev.report_mismatch(
131 &OpaqueHiddenType { ty, span: concrete_type.span },
135 prev.ty = infcx.tcx.ty_error();
137 // Pick a better span if there is one.
138 // FIXME(oli-obk): collect multiple spans for better diagnostics down the road.
139 prev.span = prev.span.substitute_dummy(concrete_type.span);
142 opaque_type_key.def_id,
143 OpaqueHiddenType { ty, span: concrete_type.span },
150 /// Map the regions in the type to named regions. This is similar to what
151 /// `infer_opaque_types` does, but can infer any universal region, not only
152 /// ones from the substs for the opaque type. It also doesn't double check
153 /// that the regions produced are in fact equal to the named region they are
154 /// replaced with. This is fine because this function is only to improve the
155 /// region names in error messages.
156 pub(crate) fn name_regions<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
158 T: TypeFoldable<'tcx>,
160 tcx.fold_regions(ty, |region, _| match *region {
162 // Find something that we can name
163 let upper_bound = self.approx_universal_upper_bound(vid);
164 let upper_bound = &self.definitions[upper_bound];
165 match upper_bound.external_name {
168 // Nothing exact found, so we pick the first one that we find.
169 let scc = self.constraint_sccs.scc(vid);
170 for vid in self.rev_scc_graph.as_ref().unwrap().upper_bounds(scc) {
171 match self.definitions[vid].external_name {
173 Some(region) if region.is_static() => {}
174 Some(region) => return region,
186 pub trait InferCtxtExt<'tcx> {
187 fn infer_opaque_definition_from_instantiation(
189 opaque_type_key: OpaqueTypeKey<'tcx>,
190 instantiated_ty: OpaqueHiddenType<'tcx>,
191 origin: OpaqueTyOrigin,
195 impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
196 /// Given the fully resolved, instantiated type for an opaque
197 /// type, i.e., the value of an inference variable like C1 or C2
198 /// (*), computes the "definition type" for an opaque type
199 /// definition -- that is, the inferred value of `Foo1<'x>` or
200 /// `Foo2<'x>` that we would conceptually use in its definition:
201 /// ```ignore (illustrative)
202 /// type Foo1<'x> = impl Bar<'x> = AAA; // <-- this type AAA
203 /// type Foo2<'x> = impl Bar<'x> = BBB; // <-- or this type BBB
204 /// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. }
206 /// Note that these values are defined in terms of a distinct set of
207 /// generic parameters (`'x` instead of `'a`) from C1 or C2. The main
208 /// purpose of this function is to do that translation.
210 /// (*) C1 and C2 were introduced in the comments on
211 /// `register_member_constraints`. Read that comment for more context.
215 /// - `def_id`, the `impl Trait` type
216 /// - `substs`, the substs used to instantiate this opaque type
217 /// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
218 /// `opaque_defn.concrete_ty`
219 #[instrument(level = "debug", skip(self))]
220 fn infer_opaque_definition_from_instantiation(
222 opaque_type_key: OpaqueTypeKey<'tcx>,
223 instantiated_ty: OpaqueHiddenType<'tcx>,
224 origin: OpaqueTyOrigin,
226 if self.is_tainted_by_errors() {
227 return self.tcx.ty_error();
230 let OpaqueTypeKey { def_id, substs } = opaque_type_key;
232 // Use substs to build up a reverse map from regions to their
233 // identity mappings. This is necessary because of `impl
234 // Trait` lifetimes are computed by replacing existing
235 // lifetimes with 'static and remapping only those used in the
236 // `impl Trait` return type, resulting in the parameters
238 let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id.to_def_id());
240 let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> =
241 substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect();
242 debug!("map = {:#?}", map);
244 // Convert the type from the function into a type valid outside
245 // the function, by replacing invalid regions with 'static,
246 // after producing an error for each of them.
247 let definition_ty = instantiated_ty.ty.fold_with(&mut ReverseMapper::new(
252 instantiated_ty.span,
254 debug!(?definition_ty);
256 if !check_opaque_type_parameter_valid(
260 instantiated_ty.span,
262 return self.tcx.ty_error();
265 // Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs`
266 // on stable and we'd break that.
267 if let OpaqueTyOrigin::TyAlias = origin {
268 // This logic duplicates most of `check_opaque_meets_bounds`.
269 // FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely.
270 let param_env = self.tcx.param_env(def_id);
271 let body_id = self.tcx.local_def_id_to_hir_id(def_id);
272 // HACK This bubble is required for this tests to pass:
273 // type-alias-impl-trait/issue-67844-nested-opaque.rs
274 self.tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter(
276 // Require the hidden type to be well-formed with only the generics of the opaque type.
277 // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
278 // hidden type is well formed even without those bounds.
280 ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()))
281 .to_predicate(infcx.tcx);
282 let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
284 // Require that the hidden type actually fulfills all the bounds of the opaque type, even without
285 // the bounds that the function supplies.
286 match infcx.register_hidden_type(
287 OpaqueTypeKey { def_id, substs: id_substs },
288 ObligationCause::misc(instantiated_ty.span, body_id),
294 for obligation in infer_ok.obligations {
295 fulfillment_cx.register_predicate_obligation(&infcx, obligation);
300 .report_mismatched_types(
301 &ObligationCause::misc(instantiated_ty.span, body_id),
302 self.tcx.mk_opaque(def_id.to_def_id(), id_substs),
310 fulfillment_cx.register_predicate_obligation(
312 Obligation::misc(instantiated_ty.span, body_id, param_env, predicate),
315 // Check that all obligations are satisfied by the implementation's
317 let errors = fulfillment_cx.select_all_or_error(&infcx);
319 // This is still required for many(half of the tests in ui/type-alias-impl-trait)
321 let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
323 if errors.is_empty() {
326 infcx.report_fulfillment_errors(&errors, None, false);
337 fn check_opaque_type_parameter_valid(
339 opaque_type_key: OpaqueTypeKey<'_>,
340 origin: OpaqueTyOrigin,
344 // No need to check return position impl trait (RPIT)
345 // because for type and const parameters they are correct
346 // by construction: we convert
348 // fn foo<P0..Pn>() -> impl Trait
353 // fn foo<P0..Pn>() -> Foo<P0...Pn>.
355 // For lifetime parameters we convert
357 // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
361 // type foo::<'p0..'pn>::Foo<'q0..'qm>
362 // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
364 // which would error here on all of the `'static` args.
365 OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true,
367 OpaqueTyOrigin::TyAlias => {}
369 let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
370 let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
371 for (i, arg) in opaque_type_key.substs.iter().enumerate() {
372 let arg_is_param = match arg.unpack() {
373 GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
374 GenericArgKind::Lifetime(lt) if lt.is_static() => {
376 .struct_span_err(span, "non-defining opaque type use in defining scope")
378 tcx.def_span(opaque_generics.param_at(i, tcx).def_id),
379 "cannot use static lifetime; use a bound lifetime \
380 instead or remove the lifetime parameter from the \
386 GenericArgKind::Lifetime(lt) => {
387 matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
389 GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)),
393 seen_params.entry(arg).or_default().push(i);
395 // Prevent `fn foo() -> Foo<u32>` from being defining.
396 let opaque_param = opaque_generics.param_at(i, tcx);
398 .struct_span_err(span, "non-defining opaque type use in defining scope")
400 tcx.def_span(opaque_param.def_id),
402 "used non-generic {} `{}` for generic parameter",
403 opaque_param.kind.descr(),
412 for (_, indices) in seen_params {
413 if indices.len() > 1 {
414 let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
415 let spans: Vec<_> = indices
417 .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
420 .struct_span_err(span, "non-defining opaque type use in defining scope")
421 .span_note(spans, &format!("{} used multiple times", descr))
429 struct ReverseMapper<'tcx> {
432 opaque_type_def_id: LocalDefId,
433 map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
434 map_missing_regions_to_empty: bool,
436 /// initially `Some`, set to `None` once error has been reported
437 hidden_ty: Option<Ty<'tcx>>,
439 /// Span of function being checked.
443 impl<'tcx> ReverseMapper<'tcx> {
446 opaque_type_def_id: LocalDefId,
447 map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
455 map_missing_regions_to_empty: false,
456 hidden_ty: Some(hidden_ty),
461 fn fold_kind_mapping_missing_regions_to_empty(
463 kind: GenericArg<'tcx>,
464 ) -> GenericArg<'tcx> {
465 assert!(!self.map_missing_regions_to_empty);
466 self.map_missing_regions_to_empty = true;
467 let kind = kind.fold_with(self);
468 self.map_missing_regions_to_empty = false;
472 fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
473 assert!(!self.map_missing_regions_to_empty);
478 impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
479 fn tcx(&self) -> TyCtxt<'tcx> {
483 #[instrument(skip(self), level = "debug")]
484 fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
486 // Ignore bound regions and `'static` regions that appear in the
487 // type, we only need to remap regions that reference lifetimes
488 // from the function declaration.
489 // This would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
490 ty::ReLateBound(..) | ty::ReStatic => return r,
492 // If regions have been erased (by writeback), don't try to unerase
494 ty::ReErased => return r,
496 // The regions that we expect from borrow checking.
497 ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {}
499 ty::ReEmpty(_) | ty::RePlaceholder(_) | ty::ReVar(_) => {
500 // All of the regions in the type should either have been
501 // erased by writeback, or mapped back to named regions by
503 bug!("unexpected region kind in opaque type: {:?}", r);
507 let generics = self.tcx().generics_of(self.opaque_type_def_id);
508 match self.map.get(&r.into()).map(|k| k.unpack()) {
509 Some(GenericArgKind::Lifetime(r1)) => r1,
510 Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
511 None if self.map_missing_regions_to_empty => self.tcx.lifetimes.re_root_empty,
512 None if generics.parent.is_some() => {
513 if let Some(hidden_ty) = self.hidden_ty.take() {
514 unexpected_hidden_region_diagnostic(
516 self.tcx.def_span(self.opaque_type_def_id),
522 self.tcx.lifetimes.re_root_empty
527 .struct_span_err(self.span, "non-defining opaque type use in defining scope")
531 "lifetime `{}` is part of concrete type but not used in \
532 parameter list of the `impl Trait` type alias",
538 self.tcx().lifetimes.re_static
543 fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
545 ty::Closure(def_id, substs) => {
546 // I am a horrible monster and I pray for death. When
547 // we encounter a closure here, it is always a closure
548 // from within the function that we are currently
549 // type-checking -- one that is now being encapsulated
550 // in an opaque type. Ideally, we would
551 // go through the types/lifetimes that it references
552 // and treat them just like we would any other type,
553 // which means we would error out if we find any
554 // reference to a type/region that is not in the
557 // **However,** in the case of closures, there is a
558 // somewhat subtle (read: hacky) consideration. The
559 // problem is that our closure types currently include
560 // all the lifetime parameters declared on the
561 // enclosing function, even if they are unused by the
562 // closure itself. We can't readily filter them out,
563 // so here we replace those values with `'empty`. This
564 // can't really make a difference to the rest of the
565 // compiler; those regions are ignored for the
566 // outlives relation, and hence don't affect trait
567 // selection or auto traits, and they are erased
570 let generics = self.tcx.generics_of(def_id);
571 let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
572 if index < generics.parent_count {
573 // Accommodate missing regions in the parent kinds...
574 self.fold_kind_mapping_missing_regions_to_empty(kind)
576 // ...but not elsewhere.
577 self.fold_kind_normally(kind)
581 self.tcx.mk_closure(def_id, substs)
584 ty::Generator(def_id, substs, movability) => {
585 let generics = self.tcx.generics_of(def_id);
586 let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
587 if index < generics.parent_count {
588 // Accommodate missing regions in the parent kinds...
589 self.fold_kind_mapping_missing_regions_to_empty(kind)
591 // ...but not elsewhere.
592 self.fold_kind_normally(kind)
596 self.tcx.mk_generator(def_id, substs, movability)
599 ty::Param(param) => {
600 // Look it up in the substitution list.
601 match self.map.get(&ty.into()).map(|k| k.unpack()) {
602 // Found it in the substitution list; replace with the parameter from the
604 Some(GenericArgKind::Type(t1)) => t1,
605 Some(u) => panic!("type mapped to unexpected kind: {:?}", u),
607 debug!(?param, ?self.map);
613 "type parameter `{}` is part of concrete type but not \
614 used in parameter list for the `impl Trait` type alias",
620 self.tcx().ty_error()
625 _ => ty.super_fold_with(self),
629 fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
630 trace!("checking const {:?}", ct);
631 // Find a const parameter
633 ty::ConstKind::Param(..) => {
634 // Look it up in the substitution list.
635 match self.map.get(&ct.into()).map(|k| k.unpack()) {
636 // Found it in the substitution list, replace with the parameter from the
638 Some(GenericArgKind::Const(c1)) => c1,
639 Some(u) => panic!("const mapped to unexpected kind: {:?}", u),
646 "const parameter `{}` is part of concrete type but not \
647 used in parameter list for the `impl Trait` type alias",
653 self.tcx().const_error(ct.ty())