rustc_borrowck/region_infer/opaque_types/
mod.rs

1use std::iter;
2use std::rc::Rc;
3
4use rustc_data_structures::frozen::Frozen;
5use rustc_data_structures::fx::FxIndexMap;
6use rustc_hir::def_id::DefId;
7use rustc_infer::infer::outlives::env::RegionBoundPairs;
8use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, OpaqueTypeStorageEntries};
9use rustc_infer::traits::ObligationCause;
10use rustc_macros::extension;
11use rustc_middle::mir::{Body, ConstraintCategory};
12use rustc_middle::ty::{
13    self, DefiningScopeKind, FallibleTypeFolder, GenericArg, GenericArgsRef, OpaqueHiddenType,
14    OpaqueTypeKey, Region, RegionVid, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
15    TypeVisitableExt, fold_regions,
16};
17use rustc_mir_dataflow::points::DenseLocationMap;
18use rustc_span::Span;
19use rustc_trait_selection::opaque_types::{
20    InvalidOpaqueTypeArgs, check_opaque_type_parameter_valid,
21};
22use rustc_trait_selection::solve::NoSolution;
23use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
24use tracing::{debug, instrument};
25
26use super::reverse_sccs::ReverseSccGraph;
27use crate::consumers::RegionInferenceContext;
28use crate::session_diagnostics::LifetimeMismatchOpaqueParam;
29use crate::type_check::canonical::fully_perform_op_raw;
30use crate::type_check::free_region_relations::UniversalRegionRelations;
31use crate::type_check::{Locations, MirTypeckRegionConstraints};
32use crate::universal_regions::{RegionClassification, UniversalRegions};
33use crate::{BorrowCheckRootCtxt, BorrowckInferCtxt};
34
35mod member_constraints;
36mod region_ctxt;
37
38use member_constraints::apply_member_constraints;
39use region_ctxt::RegionCtxt;
40
41/// We defer errors from [fn handle_opaque_type_uses] and only report them
42/// if there are no `RegionErrors`. If there are region errors, it's likely
43/// that errors here are caused by them and don't need to be handled separately.
44pub(crate) enum DeferredOpaqueTypeError<'tcx> {
45    InvalidOpaqueTypeArgs(InvalidOpaqueTypeArgs<'tcx>),
46    LifetimeMismatchOpaqueParam(LifetimeMismatchOpaqueParam<'tcx>),
47    UnexpectedHiddenRegion {
48        /// The opaque type.
49        opaque_type_key: OpaqueTypeKey<'tcx>,
50        /// The hidden type containing the member region.
51        hidden_type: OpaqueHiddenType<'tcx>,
52        /// The unexpected region.
53        member_region: Region<'tcx>,
54    },
55    NonDefiningUseInDefiningScope {
56        span: Span,
57        opaque_type_key: OpaqueTypeKey<'tcx>,
58    },
59}
60
61/// This looks at all uses of opaque types in their defining scope inside
62/// of this function.
63///
64/// It first uses all defining uses to compute the actual concrete type of each
65/// opaque type definition.
66///
67/// We then apply this inferred type to actually check all uses of the opaque.
68pub(crate) fn handle_opaque_type_uses<'tcx>(
69    root_cx: &mut BorrowCheckRootCtxt<'tcx>,
70    infcx: &BorrowckInferCtxt<'tcx>,
71    body: &Body<'tcx>,
72    universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>,
73    region_bound_pairs: &RegionBoundPairs<'tcx>,
74    known_type_outlives_obligations: &[ty::PolyTypeOutlivesPredicate<'tcx>],
75    location_map: &Rc<DenseLocationMap>,
76    constraints: &mut MirTypeckRegionConstraints<'tcx>,
77) -> Vec<DeferredOpaqueTypeError<'tcx>> {
78    let tcx = infcx.tcx;
79    let opaque_types = infcx.clone_opaque_types();
80    if opaque_types.is_empty() {
81        return Vec::new();
82    }
83
84    // We need to eagerly map all regions to NLL vars here, as we need to make sure we've
85    // introduced nll vars for all used placeholders.
86    //
87    // We need to resolve inference vars as even though we're in MIR typeck, we may still
88    // encounter inference variables, e.g. when checking user types.
89    let opaque_types_storage_num_entries = infcx.inner.borrow_mut().opaque_types().num_entries();
90    let opaque_types = opaque_types
91        .into_iter()
92        .map(|entry| {
93            fold_regions(tcx, infcx.resolve_vars_if_possible(entry), |r, _| {
94                let vid = if let ty::RePlaceholder(placeholder) = r.kind() {
95                    constraints.placeholder_region(infcx, placeholder).as_var()
96                } else {
97                    universal_region_relations.universal_regions.to_region_vid(r)
98                };
99                Region::new_var(tcx, vid)
100            })
101        })
102        .collect::<Vec<_>>();
103
104    debug!(?opaque_types);
105
106    let errors = compute_concrete_opaque_types(
107        root_cx,
108        infcx,
109        constraints,
110        universal_region_relations,
111        Rc::clone(location_map),
112        &opaque_types,
113    );
114
115    if !errors.is_empty() {
116        return errors;
117    }
118
119    let errors = apply_computed_concrete_opaque_types(
120        root_cx,
121        infcx,
122        body,
123        &universal_region_relations.universal_regions,
124        region_bound_pairs,
125        known_type_outlives_obligations,
126        constraints,
127        &opaque_types,
128    );
129
130    detect_opaque_types_added_while_handling_opaque_types(infcx, opaque_types_storage_num_entries);
131
132    errors
133}
134
135/// Maps an NLL var to a deterministically chosen equal universal region.
136///
137/// See the corresponding [rustc-dev-guide chapter] for more details. This
138/// ignores changes to the region values due to member constraints. Applying
139/// member constraints does not impact the result of this function.
140///
141/// [rustc-dev-guide chapter]: https://rustc-dev-guide.rust-lang.org/borrow_check/opaque-types-region-inference-restrictions.html
142fn nll_var_to_universal_region<'tcx>(
143    rcx: &RegionCtxt<'_, 'tcx>,
144    r: RegionVid,
145) -> Option<Region<'tcx>> {
146    // Use the SCC representative instead of directly using `region`.
147    // See [rustc-dev-guide chapter] § "Strict lifetime equality".
148    let vid = rcx.representative(r).rvid();
149    match rcx.definitions[vid].origin {
150        // Iterate over all universal regions in a consistent order and find the
151        // *first* equal region. This makes sure that equal lifetimes will have
152        // the same name and simplifies subsequent handling.
153        // See [rustc-dev-guide chapter] § "Semantic lifetime equality".
154        NllRegionVariableOrigin::FreeRegion => rcx
155            .universal_regions()
156            .universal_regions_iter()
157            .filter(|&ur| {
158                // See [rustc-dev-guide chapter] § "Closure restrictions".
159                !matches!(
160                    rcx.universal_regions().region_classification(ur),
161                    Some(RegionClassification::External)
162                )
163            })
164            .find(|&ur| rcx.universal_region_relations.equal(vid, ur))
165            .map(|ur| rcx.definitions[ur].external_name.unwrap()),
166        NllRegionVariableOrigin::Placeholder(placeholder) => {
167            Some(ty::Region::new_placeholder(rcx.infcx.tcx, placeholder))
168        }
169        // If `r` were equal to any universal region, its SCC representative
170        // would have been set to a free region.
171        NllRegionVariableOrigin::Existential { .. } => None,
172    }
173}
174
175#[derive(Debug)]
176struct DefiningUse<'tcx> {
177    /// The opaque type using non NLL vars. This uses the actual
178    /// free regions and placeholders. This is necessary
179    /// to interact with code outside of `rustc_borrowck`.
180    opaque_type_key: OpaqueTypeKey<'tcx>,
181    arg_regions: Vec<RegionVid>,
182    hidden_type: OpaqueHiddenType<'tcx>,
183}
184
185/// This computes the actual hidden types of the opaque types and maps them to their
186/// definition sites. Outside of registering the computed concrete types this function
187/// does not mutate the current borrowck state.
188///
189/// While it may fail to infer the hidden type and return errors, we always apply
190/// the computed concrete hidden type to all opaque type uses to check whether they
191/// are correct. This is necessary to support non-defining uses of opaques in their
192/// defining scope.
193///
194/// It also means that this whole function is not really soundness critical as we
195/// recheck all uses of the opaques regardless.
196fn compute_concrete_opaque_types<'tcx>(
197    root_cx: &mut BorrowCheckRootCtxt<'tcx>,
198    infcx: &BorrowckInferCtxt<'tcx>,
199    constraints: &MirTypeckRegionConstraints<'tcx>,
200    universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>,
201    location_map: Rc<DenseLocationMap>,
202    opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
203) -> Vec<DeferredOpaqueTypeError<'tcx>> {
204    let mut errors = Vec::new();
205    // When computing the hidden type we need to track member constraints.
206    // We don't mutate the region graph used by `fn compute_regions` but instead
207    // manually track region information via a `RegionCtxt`. We discard this
208    // information at the end of this function.
209    let mut rcx = RegionCtxt::new(infcx, universal_region_relations, location_map, constraints);
210
211    // We start by checking each use of an opaque type during type check and
212    // check whether the generic arguments of the opaque type are fully
213    // universal, if so, it's a defining use.
214    let defining_uses = collect_defining_uses(root_cx, &mut rcx, opaque_types, &mut errors);
215
216    // We now compute and apply member constraints for all regions in the hidden
217    // types of each defining use. This mutates the region values of the `rcx` which
218    // is used when mapping the defining uses to the definition site.
219    apply_member_constraints(&mut rcx, &defining_uses);
220
221    // After applying member constraints, we now check whether all member regions ended
222    // up equal to one of their choice regions and compute the actual concrete type of
223    // the opaque type definition. This is stored in the `root_cx`.
224    compute_concrete_types_from_defining_uses(root_cx, &rcx, &defining_uses, &mut errors);
225    errors
226}
227
228#[instrument(level = "debug", skip_all, ret)]
229fn collect_defining_uses<'tcx>(
230    root_cx: &mut BorrowCheckRootCtxt<'tcx>,
231    rcx: &mut RegionCtxt<'_, 'tcx>,
232    opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
233    errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>,
234) -> Vec<DefiningUse<'tcx>> {
235    let infcx = rcx.infcx;
236    let mut defining_uses = vec![];
237    for &(opaque_type_key, hidden_type) in opaque_types {
238        let non_nll_opaque_type_key = opaque_type_key.fold_captured_lifetime_args(infcx.tcx, |r| {
239            nll_var_to_universal_region(&rcx, r.as_var()).unwrap_or(r)
240        });
241        if let Err(err) = check_opaque_type_parameter_valid(
242            infcx,
243            non_nll_opaque_type_key,
244            hidden_type.span,
245            DefiningScopeKind::MirBorrowck,
246        ) {
247            // A non-defining use. This is a hard error on stable and gets ignored
248            // with `TypingMode::Borrowck`.
249            if infcx.tcx.use_typing_mode_borrowck() {
250                match err {
251                    InvalidOpaqueTypeArgs::AlreadyReported(guar) => root_cx
252                        .add_concrete_opaque_type(
253                            opaque_type_key.def_id,
254                            OpaqueHiddenType::new_error(infcx.tcx, guar),
255                        ),
256                    _ => debug!(?non_nll_opaque_type_key, ?err, "ignoring non-defining use"),
257                }
258            } else {
259                errors.push(DeferredOpaqueTypeError::InvalidOpaqueTypeArgs(err));
260            }
261            continue;
262        }
263
264        // We use the original `opaque_type_key` to compute the `arg_regions`.
265        let arg_regions = iter::once(rcx.universal_regions().fr_static)
266            .chain(
267                opaque_type_key
268                    .iter_captured_args(infcx.tcx)
269                    .filter_map(|(_, arg)| arg.as_region())
270                    .map(Region::as_var),
271            )
272            .collect();
273        defining_uses.push(DefiningUse {
274            opaque_type_key: non_nll_opaque_type_key,
275            arg_regions,
276            hidden_type,
277        });
278    }
279
280    defining_uses
281}
282
283fn compute_concrete_types_from_defining_uses<'tcx>(
284    root_cx: &mut BorrowCheckRootCtxt<'tcx>,
285    rcx: &RegionCtxt<'_, 'tcx>,
286    defining_uses: &[DefiningUse<'tcx>],
287    errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>,
288) {
289    let infcx = rcx.infcx;
290    let tcx = infcx.tcx;
291    let mut decls_modulo_regions: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueTypeKey<'tcx>, Span)> =
292        FxIndexMap::default();
293    for &DefiningUse { opaque_type_key, ref arg_regions, hidden_type } in defining_uses {
294        // After applying member constraints, we now map all regions in the hidden type
295        // to the `arg_regions` of this defining use. In case a region in the hidden type
296        // ended up not being equal to any such region, we error.
297        let hidden_type =
298            match hidden_type.try_fold_with(&mut ToArgRegionsFolder::new(rcx, arg_regions)) {
299                Ok(hidden_type) => hidden_type,
300                Err(r) => {
301                    errors.push(DeferredOpaqueTypeError::UnexpectedHiddenRegion {
302                        hidden_type,
303                        opaque_type_key,
304                        member_region: ty::Region::new_var(tcx, r),
305                    });
306                    let guar = tcx.dcx().span_delayed_bug(
307                        hidden_type.span,
308                        "opaque type with non-universal region args",
309                    );
310                    ty::OpaqueHiddenType::new_error(tcx, guar)
311                }
312            };
313
314        // Now that we mapped the member regions to their final value,
315        // map the arguments of the opaque type key back to the parameters
316        // of the opaque type definition.
317        let ty = infcx
318            .infer_opaque_definition_from_instantiation(opaque_type_key, hidden_type)
319            .unwrap_or_else(|_| {
320                Ty::new_error_with_message(
321                    rcx.infcx.tcx,
322                    hidden_type.span,
323                    "deferred invalid opaque type args",
324                )
325            });
326
327        // Sometimes, when the hidden type is an inference variable, it can happen that
328        // the hidden type becomes the opaque type itself. In this case, this was an opaque
329        // usage of the opaque type and we can ignore it. This check is mirrored in typeck's
330        // writeback.
331        if !rcx.infcx.tcx.use_typing_mode_borrowck() {
332            if let ty::Alias(ty::Opaque, alias_ty) = ty.kind()
333                && alias_ty.def_id == opaque_type_key.def_id.to_def_id()
334                && alias_ty.args == opaque_type_key.args
335            {
336                continue;
337            }
338        }
339
340        // Check that all opaque types have the same region parameters if they have the same
341        // non-region parameters. This is necessary because within the new solver we perform
342        // various query operations modulo regions, and thus could unsoundly select some impls
343        // that don't hold.
344        //
345        // FIXME(-Znext-solver): This isn't necessary after all. We can remove this check again.
346        if let Some((prev_decl_key, prev_span)) = decls_modulo_regions.insert(
347            rcx.infcx.tcx.erase_regions(opaque_type_key),
348            (opaque_type_key, hidden_type.span),
349        ) && let Some((arg1, arg2)) = std::iter::zip(
350            prev_decl_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
351            opaque_type_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
352        )
353        .find(|(arg1, arg2)| arg1 != arg2)
354        {
355            errors.push(DeferredOpaqueTypeError::LifetimeMismatchOpaqueParam(
356                LifetimeMismatchOpaqueParam {
357                    arg: arg1,
358                    prev: arg2,
359                    span: prev_span,
360                    prev_span: hidden_type.span,
361                },
362            ));
363        }
364        root_cx.add_concrete_opaque_type(
365            opaque_type_key.def_id,
366            OpaqueHiddenType { span: hidden_type.span, ty },
367        );
368    }
369}
370
371/// A folder to map the regions in the hidden type to their corresponding `arg_regions`.
372///
373/// This folder has to differentiate between member regions and other regions in the hidden
374/// type. Member regions have to be equal to one of the `arg_regions` while other regions simply
375/// get treated as an existential region in the opaque if they are not. Existential
376/// regions are currently represented using `'erased`.
377struct ToArgRegionsFolder<'a, 'tcx> {
378    rcx: &'a RegionCtxt<'a, 'tcx>,
379    // When folding closure args or bivariant alias arguments, we simply
380    // ignore non-member regions. However, we still need to map member
381    // regions to their arg region even if its in a closure argument.
382    //
383    // See tests/ui/type-alias-impl-trait/closure_wf_outlives.rs for an example.
384    erase_unknown_regions: bool,
385    arg_regions: &'a [RegionVid],
386}
387
388impl<'a, 'tcx> ToArgRegionsFolder<'a, 'tcx> {
389    fn new(
390        rcx: &'a RegionCtxt<'a, 'tcx>,
391        arg_regions: &'a [RegionVid],
392    ) -> ToArgRegionsFolder<'a, 'tcx> {
393        ToArgRegionsFolder { rcx, erase_unknown_regions: false, arg_regions }
394    }
395
396    fn fold_non_member_arg(&mut self, arg: GenericArg<'tcx>) -> GenericArg<'tcx> {
397        let prev = self.erase_unknown_regions;
398        self.erase_unknown_regions = true;
399        let res = arg.try_fold_with(self).unwrap();
400        self.erase_unknown_regions = prev;
401        res
402    }
403
404    fn fold_closure_args(
405        &mut self,
406        def_id: DefId,
407        args: GenericArgsRef<'tcx>,
408    ) -> Result<GenericArgsRef<'tcx>, RegionVid> {
409        let generics = self.cx().generics_of(def_id);
410        self.cx().mk_args_from_iter(args.iter().enumerate().map(|(index, arg)| {
411            if index < generics.parent_count {
412                Ok(self.fold_non_member_arg(arg))
413            } else {
414                arg.try_fold_with(self)
415            }
416        }))
417    }
418}
419impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for ToArgRegionsFolder<'_, 'tcx> {
420    type Error = RegionVid;
421    fn cx(&self) -> TyCtxt<'tcx> {
422        self.rcx.infcx.tcx
423    }
424
425    fn try_fold_region(&mut self, r: Region<'tcx>) -> Result<Region<'tcx>, RegionVid> {
426        match r.kind() {
427            // ignore bound regions, keep visiting
428            ty::ReBound(_, _) => Ok(r),
429            _ => {
430                let r = r.as_var();
431                if let Some(arg_region) = self
432                    .arg_regions
433                    .iter()
434                    .copied()
435                    .find(|&arg_vid| self.rcx.eval_equal(r, arg_vid))
436                    .and_then(|r| nll_var_to_universal_region(self.rcx, r))
437                {
438                    Ok(arg_region)
439                } else if self.erase_unknown_regions {
440                    Ok(self.cx().lifetimes.re_erased)
441                } else {
442                    Err(r)
443                }
444            }
445        }
446    }
447
448    fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, RegionVid> {
449        if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) {
450            return Ok(ty);
451        }
452
453        let tcx = self.cx();
454        Ok(match *ty.kind() {
455            ty::Closure(def_id, args) => {
456                Ty::new_closure(tcx, def_id, self.fold_closure_args(def_id, args)?)
457            }
458
459            ty::CoroutineClosure(def_id, args) => {
460                Ty::new_coroutine_closure(tcx, def_id, self.fold_closure_args(def_id, args)?)
461            }
462
463            ty::Coroutine(def_id, args) => {
464                Ty::new_coroutine(tcx, def_id, self.fold_closure_args(def_id, args)?)
465            }
466
467            ty::Alias(kind, ty::AliasTy { def_id, args, .. })
468                if let Some(variances) = tcx.opt_alias_variances(kind, def_id) =>
469            {
470                let args = tcx.mk_args_from_iter(std::iter::zip(variances, args.iter()).map(
471                    |(&v, s)| {
472                        if v == ty::Bivariant {
473                            Ok(self.fold_non_member_arg(s))
474                        } else {
475                            s.try_fold_with(self)
476                        }
477                    },
478                ))?;
479                ty::AliasTy::new_from_args(tcx, def_id, args).to_ty(tcx)
480            }
481
482            _ => ty.try_super_fold_with(self)?,
483        })
484    }
485}
486
487/// This function is what actually applies member constraints to the borrowck
488/// state. It is also responsible to check all uses of the opaques in their
489/// defining scope.
490///
491/// It does this by equating the hidden type of each use with the instantiated final
492/// hidden type of the opaque.
493fn apply_computed_concrete_opaque_types<'tcx>(
494    root_cx: &mut BorrowCheckRootCtxt<'tcx>,
495    infcx: &BorrowckInferCtxt<'tcx>,
496    body: &Body<'tcx>,
497    universal_regions: &UniversalRegions<'tcx>,
498    region_bound_pairs: &RegionBoundPairs<'tcx>,
499    known_type_outlives_obligations: &[ty::PolyTypeOutlivesPredicate<'tcx>],
500    constraints: &mut MirTypeckRegionConstraints<'tcx>,
501    opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
502) -> Vec<DeferredOpaqueTypeError<'tcx>> {
503    let tcx = infcx.tcx;
504    let mut errors = Vec::new();
505    for &(key, hidden_type) in opaque_types {
506        let Some(expected) = root_cx.get_concrete_opaque_type(key.def_id) else {
507            assert!(tcx.use_typing_mode_borrowck(), "non-defining use in defining scope");
508            errors.push(DeferredOpaqueTypeError::NonDefiningUseInDefiningScope {
509                span: hidden_type.span,
510                opaque_type_key: key,
511            });
512            let guar = tcx.dcx().span_delayed_bug(
513                hidden_type.span,
514                "non-defining use in the defining scope with no defining uses",
515            );
516            root_cx.add_concrete_opaque_type(key.def_id, OpaqueHiddenType::new_error(tcx, guar));
517            continue;
518        };
519
520        // We erase all non-member region of the opaque and need to treat these as existentials.
521        let expected = ty::fold_regions(tcx, expected.instantiate(tcx, key.args), |re, _dbi| {
522            match re.kind() {
523                ty::ReErased => infcx.next_nll_region_var(
524                    NllRegionVariableOrigin::Existential { name: None },
525                    || crate::RegionCtxt::Existential(None),
526                ),
527                _ => re,
528            }
529        });
530
531        // We now simply equate the expected with the actual hidden type.
532        let locations = Locations::All(hidden_type.span);
533        if let Err(guar) = fully_perform_op_raw(
534            infcx,
535            body,
536            universal_regions,
537            region_bound_pairs,
538            known_type_outlives_obligations,
539            constraints,
540            locations,
541            ConstraintCategory::OpaqueType,
542            CustomTypeOp::new(
543                |ocx| {
544                    let cause = ObligationCause::misc(
545                        hidden_type.span,
546                        body.source.def_id().expect_local(),
547                    );
548                    // We need to normalize both types in the old solver before equatingt them.
549                    let actual_ty = ocx.normalize(&cause, infcx.param_env, hidden_type.ty);
550                    let expected_ty = ocx.normalize(&cause, infcx.param_env, expected.ty);
551                    ocx.eq(&cause, infcx.param_env, actual_ty, expected_ty).map_err(|_| NoSolution)
552                },
553                "equating opaque types",
554            ),
555        ) {
556            root_cx.add_concrete_opaque_type(key.def_id, OpaqueHiddenType::new_error(tcx, guar));
557        }
558    }
559    errors
560}
561
562/// In theory `apply_concrete_opaque_types` could introduce new uses of opaque types.
563/// We do not check these new uses so this could be unsound.
564///
565/// We detect any new uses and simply delay a bug if they occur. If this results in
566/// an ICE we can properly handle this, but we haven't encountered any such test yet.
567///
568/// See the related comment in `FnCtxt::detect_opaque_types_added_during_writeback`.
569fn detect_opaque_types_added_while_handling_opaque_types<'tcx>(
570    infcx: &InferCtxt<'tcx>,
571    opaque_types_storage_num_entries: OpaqueTypeStorageEntries,
572) {
573    for (key, hidden_type) in infcx
574        .inner
575        .borrow_mut()
576        .opaque_types()
577        .opaque_types_added_since(opaque_types_storage_num_entries)
578    {
579        let opaque_type_string = infcx.tcx.def_path_str(key.def_id);
580        let msg = format!("unexpected cyclic definition of `{opaque_type_string}`");
581        infcx.dcx().span_delayed_bug(hidden_type.span, msg);
582    }
583
584    let _ = infcx.take_opaque_types();
585}
586
587impl<'tcx> RegionInferenceContext<'tcx> {
588    /// Map the regions in the type to named regions. This is similar to what
589    /// `infer_opaque_types` does, but can infer any universal region, not only
590    /// ones from the args for the opaque type. It also doesn't double check
591    /// that the regions produced are in fact equal to the named region they are
592    /// replaced with. This is fine because this function is only to improve the
593    /// region names in error messages.
594    ///
595    /// This differs from `MirBorrowckCtxt::name_regions` since it is particularly
596    /// lax with mapping region vids that are *shorter* than a universal region to
597    /// that universal region. This is useful for member region constraints since
598    /// we want to suggest a universal region name to capture even if it's technically
599    /// not equal to the error region.
600    pub(crate) fn name_regions_for_member_constraint<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
601    where
602        T: TypeFoldable<TyCtxt<'tcx>>,
603    {
604        fold_regions(tcx, ty, |region, _| match region.kind() {
605            ty::ReVar(vid) => {
606                let scc = self.constraint_sccs.scc(vid);
607
608                // Special handling of higher-ranked regions.
609                if !self.max_nameable_universe(scc).is_root() {
610                    match self.scc_values.placeholders_contained_in(scc).enumerate().last() {
611                        // If the region contains a single placeholder then they're equal.
612                        Some((0, placeholder)) => {
613                            return ty::Region::new_placeholder(tcx, placeholder);
614                        }
615
616                        // Fallback: this will produce a cryptic error message.
617                        _ => return region,
618                    }
619                }
620
621                // Find something that we can name
622                let upper_bound = self.approx_universal_upper_bound(vid);
623                if let Some(universal_region) = self.definitions[upper_bound].external_name {
624                    return universal_region;
625                }
626
627                // Nothing exact found, so we pick a named upper bound, if there's only one.
628                // If there's >1 universal region, then we probably are dealing w/ an intersection
629                // region which cannot be mapped back to a universal.
630                // FIXME: We could probably compute the LUB if there is one.
631                let scc = self.constraint_sccs.scc(vid);
632                let rev_scc_graph =
633                    ReverseSccGraph::compute(&self.constraint_sccs, self.universal_regions());
634                let upper_bounds: Vec<_> = rev_scc_graph
635                    .upper_bounds(scc)
636                    .filter_map(|vid| self.definitions[vid].external_name)
637                    .filter(|r| !r.is_static())
638                    .collect();
639                match &upper_bounds[..] {
640                    [universal_region] => *universal_region,
641                    _ => region,
642                }
643            }
644            _ => region,
645        })
646    }
647}
648
649#[extension(pub trait InferCtxtExt<'tcx>)]
650impl<'tcx> InferCtxt<'tcx> {
651    /// Given the fully resolved, instantiated type for an opaque
652    /// type, i.e., the value of an inference variable like C1 or C2
653    /// (*), computes the "definition type" for an opaque type
654    /// definition -- that is, the inferred value of `Foo1<'x>` or
655    /// `Foo2<'x>` that we would conceptually use in its definition:
656    /// ```ignore (illustrative)
657    /// type Foo1<'x> = impl Bar<'x> = AAA;  // <-- this type AAA
658    /// type Foo2<'x> = impl Bar<'x> = BBB;  // <-- or this type BBB
659    /// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. }
660    /// ```
661    /// Note that these values are defined in terms of a distinct set of
662    /// generic parameters (`'x` instead of `'a`) from C1 or C2. The main
663    /// purpose of this function is to do that translation.
664    ///
665    /// (*) C1 and C2 were introduced in the comments on
666    /// `register_member_constraints`. Read that comment for more context.
667    ///
668    /// # Parameters
669    ///
670    /// - `def_id`, the `impl Trait` type
671    /// - `args`, the args used to instantiate this opaque type
672    /// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
673    ///   `opaque_defn.concrete_ty`
674    #[instrument(level = "debug", skip(self))]
675    fn infer_opaque_definition_from_instantiation(
676        &self,
677        opaque_type_key: OpaqueTypeKey<'tcx>,
678        instantiated_ty: OpaqueHiddenType<'tcx>,
679    ) -> Result<Ty<'tcx>, InvalidOpaqueTypeArgs<'tcx>> {
680        check_opaque_type_parameter_valid(
681            self,
682            opaque_type_key,
683            instantiated_ty.span,
684            DefiningScopeKind::MirBorrowck,
685        )?;
686
687        let definition_ty = instantiated_ty
688            .remap_generic_params_to_declaration_params(
689                opaque_type_key,
690                self.tcx,
691                DefiningScopeKind::MirBorrowck,
692            )
693            .ty;
694
695        definition_ty.error_reported()?;
696        Ok(definition_ty)
697    }
698}