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