1 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
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::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
12 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
13 use rustc_trait_selection::traits::ObligationCtxt;
15 use crate::session_diagnostics::NonGenericOpaqueTypeParam;
17 use super::RegionInferenceContext;
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.
23 /// For example consider `fn f<'a>(x: &'a i32) -> impl Sized + 'a { x }`.
24 /// This is lowered to give HIR something like
26 /// type f<'a>::_Return<'_a> = impl Sized + '_a;
27 /// fn f<'a>(x: &'a i32) -> f<'static>::_Return<'a> { x }
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.
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`.
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
44 /// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }`
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`.
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(
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();
67 let member_constraints: FxHashMap<_, _> = self
70 .map(|ci| (self.member_constraints[ci].key, ci))
72 debug!(?member_constraints);
74 for (opaque_type_key, (concrete_type, origin)) in opaque_ty_decls {
75 let substs = opaque_type_key.substs;
76 debug!(?concrete_type, ?substs);
78 let mut subst_regions = vec![self.universal_regions.fr_static];
80 let to_universal_region = |vid, subst_regions: &mut Vec<_>| {
82 let scc = self.constraint_sccs.scc(vid);
84 match self.scc_values.universal_regions_outlived_by(scc).find_map(|lb| {
85 self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?)
88 let vid = self.universal_regions.to_region_vid(region);
89 subst_regions.push(vid);
93 subst_regions.push(vid);
94 infcx.tcx.sess.delay_span_bug(
96 "opaque type with non-universal region substs",
98 infcx.tcx.lifetimes.re_static
103 // Start by inserting universal regions from the member_constraint choice regions.
104 // This will ensure they get precedence when folding the regions in the concrete type.
105 if let Some(&ci) = member_constraints.get(&opaque_type_key) {
106 for &vid in self.member_constraints.choice_regions(ci) {
107 to_universal_region(vid, &mut subst_regions);
110 debug!(?subst_regions);
112 // Next, insert universal regions from substs, so we can translate regions that appear
113 // in them but are not subject to member constraints, for instance closure substs.
114 let universal_substs = infcx.tcx.fold_regions(substs, |region, _| {
115 if let ty::RePlaceholder(..) = region.kind() {
116 // Higher kinded regions don't need remapping, they don't refer to anything outside of this the substs.
119 let vid = self.to_region_vid(region);
120 to_universal_region(vid, &mut subst_regions)
122 debug!(?universal_substs);
123 debug!(?subst_regions);
125 // Deduplicate the set of regions while keeping the chosen order.
126 let subst_regions = subst_regions.into_iter().collect::<FxIndexSet<_>>();
127 debug!(?subst_regions);
129 let universal_concrete_type =
130 infcx.tcx.fold_regions(concrete_type, |region, _| match *region {
131 ty::ReVar(vid) => subst_regions
133 .find(|ur_vid| self.eval_equal(vid, **ur_vid))
134 .and_then(|ur_vid| self.definitions[*ur_vid].external_name)
135 .unwrap_or(infcx.tcx.lifetimes.re_erased),
138 debug!(?universal_concrete_type);
140 let opaque_type_key =
141 OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs };
142 let ty = infcx.infer_opaque_definition_from_instantiation(
144 universal_concrete_type,
147 // Sometimes two opaque types are the same only after we remap the generic parameters
148 // back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)`
149 // and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we only know that
150 // once we convert the generic parameters to those of the opaque type.
151 if let Some(prev) = result.get_mut(&opaque_type_key.def_id) {
153 if !ty.references_error() {
154 prev.report_mismatch(
155 &OpaqueHiddenType { ty, span: concrete_type.span },
159 prev.ty = infcx.tcx.ty_error();
161 // Pick a better span if there is one.
162 // FIXME(oli-obk): collect multiple spans for better diagnostics down the road.
163 prev.span = prev.span.substitute_dummy(concrete_type.span);
166 opaque_type_key.def_id,
167 OpaqueHiddenType { ty, span: concrete_type.span },
174 /// Map the regions in the type to named regions. This is similar to what
175 /// `infer_opaque_types` does, but can infer any universal region, not only
176 /// ones from the substs for the opaque type. It also doesn't double check
177 /// that the regions produced are in fact equal to the named region they are
178 /// replaced with. This is fine because this function is only to improve the
179 /// region names in error messages.
180 pub(crate) fn name_regions<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
182 T: TypeFoldable<'tcx>,
184 tcx.fold_regions(ty, |region, _| match *region {
186 // Find something that we can name
187 let upper_bound = self.approx_universal_upper_bound(vid);
188 let upper_bound = &self.definitions[upper_bound];
189 match upper_bound.external_name {
192 // Nothing exact found, so we pick the first one that we find.
193 let scc = self.constraint_sccs.scc(vid);
194 for vid in self.rev_scc_graph.as_ref().unwrap().upper_bounds(scc) {
195 match self.definitions[vid].external_name {
197 Some(region) if region.is_static() => {}
198 Some(region) => return region,
210 pub trait InferCtxtExt<'tcx> {
211 fn infer_opaque_definition_from_instantiation(
213 opaque_type_key: OpaqueTypeKey<'tcx>,
214 instantiated_ty: OpaqueHiddenType<'tcx>,
215 origin: OpaqueTyOrigin,
219 impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
220 /// Given the fully resolved, instantiated type for an opaque
221 /// type, i.e., the value of an inference variable like C1 or C2
222 /// (*), computes the "definition type" for an opaque type
223 /// definition -- that is, the inferred value of `Foo1<'x>` or
224 /// `Foo2<'x>` that we would conceptually use in its definition:
225 /// ```ignore (illustrative)
226 /// type Foo1<'x> = impl Bar<'x> = AAA; // <-- this type AAA
227 /// type Foo2<'x> = impl Bar<'x> = BBB; // <-- or this type BBB
228 /// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. }
230 /// Note that these values are defined in terms of a distinct set of
231 /// generic parameters (`'x` instead of `'a`) from C1 or C2. The main
232 /// purpose of this function is to do that translation.
234 /// (*) C1 and C2 were introduced in the comments on
235 /// `register_member_constraints`. Read that comment for more context.
239 /// - `def_id`, the `impl Trait` type
240 /// - `substs`, the substs used to instantiate this opaque type
241 /// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
242 /// `opaque_defn.concrete_ty`
243 #[instrument(level = "debug", skip(self))]
244 fn infer_opaque_definition_from_instantiation(
246 opaque_type_key: OpaqueTypeKey<'tcx>,
247 instantiated_ty: OpaqueHiddenType<'tcx>,
248 origin: OpaqueTyOrigin,
250 if let Some(e) = self.tainted_by_errors() {
251 return self.tcx.ty_error_with_guaranteed(e);
254 let definition_ty = instantiated_ty
255 .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false)
258 if !check_opaque_type_parameter_valid(
262 instantiated_ty.span,
264 return self.tcx.ty_error();
267 // Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs`
268 // on stable and we'd break that.
269 let OpaqueTyOrigin::TyAlias = origin else {
270 return definition_ty;
272 let def_id = opaque_type_key.def_id;
273 // This logic duplicates most of `check_opaque_meets_bounds`.
274 // FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely.
275 let param_env = self.tcx.param_env(def_id);
276 let body_id = self.tcx.local_def_id_to_hir_id(def_id);
277 // HACK This bubble is required for this tests to pass:
278 // type-alias-impl-trait/issue-67844-nested-opaque.rs
280 self.tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).build();
281 let ocx = ObligationCtxt::new(&infcx);
282 // Require the hidden type to be well-formed with only the generics of the opaque type.
283 // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
284 // hidden type is well formed even without those bounds.
285 let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()));
287 let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id.to_def_id());
289 // Require that the hidden type actually fulfills all the bounds of the opaque type, even without
290 // the bounds that the function supplies.
291 let opaque_ty = self.tcx.mk_opaque(def_id.to_def_id(), id_substs);
292 if let Err(err) = ocx.eq(
293 &ObligationCause::misc(instantiated_ty.span, body_id),
300 .report_mismatched_types(
301 &ObligationCause::misc(instantiated_ty.span, body_id),
309 ocx.register_obligation(Obligation::misc(
311 instantiated_ty.span,
317 // Check that all obligations are satisfied by the implementation's
319 let errors = ocx.select_all_or_error();
321 // This is still required for many(half of the tests in ui/type-alias-impl-trait)
323 let _ = infcx.take_opaque_types();
325 if errors.is_empty() {
328 let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
329 self.tcx.ty_error_with_guaranteed(reported)
334 fn check_opaque_type_parameter_valid(
336 opaque_type_key: OpaqueTypeKey<'_>,
337 origin: OpaqueTyOrigin,
341 // No need to check return position impl trait (RPIT)
342 // because for type and const parameters they are correct
343 // by construction: we convert
345 // fn foo<P0..Pn>() -> impl Trait
350 // fn foo<P0..Pn>() -> Foo<P0...Pn>.
352 // For lifetime parameters we convert
354 // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
358 // type foo::<'p0..'pn>::Foo<'q0..'qm>
359 // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
361 // which would error here on all of the `'static` args.
362 OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true,
364 OpaqueTyOrigin::TyAlias => {}
366 let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
367 let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
368 for (i, arg) in opaque_type_key.substs.iter().enumerate() {
369 let arg_is_param = match arg.unpack() {
370 GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
371 GenericArgKind::Lifetime(lt) if lt.is_static() => {
373 .struct_span_err(span, "non-defining opaque type use in defining scope")
375 tcx.def_span(opaque_generics.param_at(i, tcx).def_id),
376 "cannot use static lifetime; use a bound lifetime \
377 instead or remove the lifetime parameter from the \
383 GenericArgKind::Lifetime(lt) => {
384 matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
386 GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)),
390 seen_params.entry(arg).or_default().push(i);
392 // Prevent `fn foo() -> Foo<u32>` from being defining.
393 let opaque_param = opaque_generics.param_at(i, tcx);
394 let kind = opaque_param.kind.descr();
395 tcx.sess.emit_err(NonGenericOpaqueTypeParam {
399 param_span: tcx.def_span(opaque_param.def_id),
405 for (_, indices) in seen_params {
406 if indices.len() > 1 {
407 let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
408 let spans: Vec<_> = indices
410 .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
413 .struct_span_err(span, "non-defining opaque type use in defining scope")
414 .span_note(spans, &format!("{} used multiple times", descr))