Skip to main content

rustc_type_ir/
region_constraint.rs

1//! The bulk of the logic for implementing `-Zassumptions-on-binders`
2
3use derive_where::derive_where;
4use indexmap::IndexSet;
5#[cfg(feature = "nightly")]
6use rustc_data_structures::stable_hash::{StableHash, StableHashCtxt, StableHasher};
7#[cfg(feature = "nightly")]
8use rustc_data_structures::transitive_relation::{TransitiveRelation, TransitiveRelationBuilder};
9use tracing::{debug, instrument};
10
11// Workaround for TransitiveRelation being in rustc_data_structures which isn't accessible on stable
12#[cfg(not(feature = "nightly"))]
13#[derive(Default, Clone, Debug)]
14pub struct TransitiveRelation<T>(T);
15#[cfg(not(feature = "nightly"))]
16impl<T> TransitiveRelation<T> {
17    pub fn reachable_from(&self, _data: T) -> Vec<T> {
18        unreachable!("-Zassumptions-on-binders is not supported for r-a")
19    }
20
21    pub fn base_edges(&self) -> impl Iterator<Item = (T, T)> {
22        unreachable!("-Zassumptions-on-binders is not supported for r-a");
23
24        #[allow(unreachable_code)]
25        [].into_iter()
26    }
27}
28#[derive(Clone, Debug)]
29#[cfg(not(feature = "nightly"))]
30pub struct TransitiveRelationBuilder<T>(T);
31#[cfg(not(feature = "nightly"))]
32impl<T> TransitiveRelationBuilder<T> {
33    pub fn freeze(self) -> TransitiveRelation<T> {
34        unreachable!("-Zassumptions-on-binders is not supported for r-a")
35    }
36
37    pub fn add(&mut self, _: T, _: T) {
38        unreachable!("-Zassumptions-on-binders is not supported for r-a")
39    }
40}
41#[cfg(not(feature = "nightly"))]
42impl<T> Default for TransitiveRelationBuilder<T> {
43    fn default() -> Self {
44        unreachable!("-Zassumptions-on-binders is not supported for r-a")
45    }
46}
47
48use crate::data_structures::IndexMap;
49use crate::fold::TypeSuperFoldable;
50use crate::inherent::*;
51use crate::relate::{Relate, RelateResult, TypeRelation, VarianceDiagInfo};
52use crate::visit::TypeSuperVisitable;
53use crate::{
54    AliasTy, Binder, BoundRegion, BoundVar, BoundVariableKind, ConstKind, DebruijnIndex,
55    FallibleTypeFolder, InferCtxtLike, InferTy, Interner, OutlivesPredicate, RegionKind, TyKind,
56    TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, TypingMode, UniverseIndex, Variance,
57    VisitorResult,
58};
59
60#[automatically_derived]
impl<I: Interner> ::core::fmt::Debug for Assumptions<I> where I: Interner {
    fn fmt(&self, __f: &mut ::core::fmt::Formatter<'_>)
        -> ::core::fmt::Result {
        match self {
            Assumptions {
                type_outlives: ref __field_type_outlives,
                region_outlives: ref __field_region_outlives,
                inverse_region_outlives: ref __field_inverse_region_outlives }
                => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_struct(__f, "Assumptions");
                ::core::fmt::DebugStruct::field(&mut __builder,
                    "type_outlives", __field_type_outlives);
                ::core::fmt::DebugStruct::field(&mut __builder,
                    "region_outlives", __field_region_outlives);
                ::core::fmt::DebugStruct::field(&mut __builder,
                    "inverse_region_outlives", __field_inverse_region_outlives);
                ::core::fmt::DebugStruct::finish(&mut __builder)
            }
        }
    }
}#[derive_where(Clone, Debug; I: Interner)]
61pub struct Assumptions<I: Interner> {
62    pub type_outlives: Vec<Binder<I, OutlivesPredicate<I, I::Ty>>>,
63    pub region_outlives: TransitiveRelation<I::Region>,
64    pub inverse_region_outlives: TransitiveRelation<I::Region>,
65}
66
67impl<I: Interner> Assumptions<I> {
68    pub fn empty() -> Self {
69        Self {
70            type_outlives: Vec::new(),
71            region_outlives: TransitiveRelationBuilder::default().freeze(),
72            inverse_region_outlives: TransitiveRelationBuilder::default().freeze(),
73        }
74    }
75
76    pub fn new(
77        type_outlives: Vec<Binder<I, OutlivesPredicate<I, I::Ty>>>,
78        region_outlives: TransitiveRelation<I::Region>,
79    ) -> Self {
80        Self {
81            inverse_region_outlives: {
82                let mut builder = TransitiveRelationBuilder::default();
83                for (r1, r2) in region_outlives.base_edges() {
84                    builder.add(r2, r1);
85                }
86                builder.freeze()
87            },
88            type_outlives,
89            region_outlives,
90        }
91    }
92}
93
94#[automatically_derived]
impl<I: Interner> ::core::fmt::Debug for RegionConstraint<I> where I: Interner
    {
    fn fmt(&self, __f: &mut ::core::fmt::Formatter<'_>)
        -> ::core::fmt::Result {
        match self {
            RegionConstraint::Ambiguity =>
                ::core::fmt::Formatter::write_str(__f, "Ambiguity"),
            RegionConstraint::RegionOutlives(ref __field_0, ref __field_1) =>
                {
                let mut __builder =
                    ::core::fmt::Formatter::debug_tuple(__f, "RegionOutlives");
                ::core::fmt::DebugTuple::field(&mut __builder, __field_0);
                ::core::fmt::DebugTuple::field(&mut __builder, __field_1);
                ::core::fmt::DebugTuple::finish(&mut __builder)
            }
            RegionConstraint::AliasTyOutlivesViaEnv(ref __field_0) => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_tuple(__f,
                        "AliasTyOutlivesViaEnv");
                ::core::fmt::DebugTuple::field(&mut __builder, __field_0);
                ::core::fmt::DebugTuple::finish(&mut __builder)
            }
            RegionConstraint::PlaceholderTyOutlives(ref __field_0,
                ref __field_1) => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_tuple(__f,
                        "PlaceholderTyOutlives");
                ::core::fmt::DebugTuple::field(&mut __builder, __field_0);
                ::core::fmt::DebugTuple::field(&mut __builder, __field_1);
                ::core::fmt::DebugTuple::finish(&mut __builder)
            }
            RegionConstraint::And(ref __field_0) => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_tuple(__f, "And");
                ::core::fmt::DebugTuple::field(&mut __builder, __field_0);
                ::core::fmt::DebugTuple::finish(&mut __builder)
            }
            RegionConstraint::Or(ref __field_0) => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_tuple(__f, "Or");
                ::core::fmt::DebugTuple::field(&mut __builder, __field_0);
                ::core::fmt::DebugTuple::finish(&mut __builder)
            }
        }
    }
}#[derive_where(Clone, Hash, PartialEq, Debug; I: Interner)]
95pub enum RegionConstraint<I: Interner> {
96    Ambiguity,
97    RegionOutlives(I::Region, I::Region),
98    /// Requirement that a (potentially higher ranked) alias outlives some (potentially higher ranked)
99    /// region due to an assumption in the environment. This cannot be satisfied via component outlives
100    /// or item bounds.
101    ///
102    /// We cannot eagerly look at assumptions as we are usually working with an incomplete set of assumptions
103    /// and there may wind up being assumptions we can use to prove this when we're in a smaller universe.
104    ///
105    /// We eagerly destructure alias outlives requirements into region outlives requirements corresponding to
106    /// component outlives & item bound outlives rules, leaving only param env candidates.
107    AliasTyOutlivesViaEnv(Binder<I, (AliasTy<I>, I::Region)>),
108    /// This is an `I::Ty` for two reasons:
109    /// 1. We need the type visitable impl to be able to `visit_ty` on this so canonicalization
110    ///    knows about the placeholder
111    /// 2. When exiting the trait solver there may be placeholder outlives corresponding to params
112    ///    from the root universe. These need to be changed from a `Placeholder` to the original
113    ///    `Param`.
114    ///
115    /// We cannot eagerly look at assumptions as we are usually working with an incomplete set of assumptions
116    /// and there may wind up being assumptions we can use to prove this when we're in a smaller universe.
117    PlaceholderTyOutlives(I::Ty, I::Region),
118
119    And(Box<[RegionConstraint<I>]>),
120    Or(Box<[RegionConstraint<I>]>),
121}
122
123// This is not a derived impl because a perfect derive leads to inductive
124// cycle causing the trait to never actually be implemented
125#[cfg(feature = "nightly")]
126impl<I: Interner> StableHash for RegionConstraint<I>
127where
128    I::Region: StableHash,
129    I::Ty: StableHash,
130    I::GenericArgs: StableHash,
131    I::TraitAssocTyId: StableHash,
132    I::InherentAssocTyId: StableHash,
133    I::OpaqueTyId: StableHash,
134    I::FreeTyAliasId: StableHash,
135    I::BoundVarKinds: StableHash,
136{
137    #[inline]
138    fn stable_hash<CTX: StableHashCtxt>(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
139        use RegionConstraint::*;
140
141        std::mem::discriminant(self).stable_hash(hcx, hasher);
142        match self {
143            Ambiguity => (),
144            RegionOutlives(a, b) => {
145                a.stable_hash(hcx, hasher);
146                b.stable_hash(hcx, hasher);
147            }
148            AliasTyOutlivesViaEnv(outlives) => {
149                outlives.stable_hash(hcx, hasher);
150            }
151            PlaceholderTyOutlives(a, b) => {
152                a.stable_hash(hcx, hasher);
153                b.stable_hash(hcx, hasher);
154            }
155            And(and) => {
156                for a in and.iter() {
157                    a.stable_hash(hcx, hasher);
158                }
159            }
160            Or(or) => {
161                for a in or.iter() {
162                    a.stable_hash(hcx, hasher);
163                }
164            }
165        }
166    }
167}
168
169impl<I: Interner> TypeFoldable<I> for RegionConstraint<I> {
170    fn try_fold_with<F: FallibleTypeFolder<I>>(self, f: &mut F) -> Result<Self, F::Error> {
171        use RegionConstraint::*;
172        Ok(match self {
173            Ambiguity => self,
174            RegionOutlives(a, b) => RegionOutlives(a.try_fold_with(f)?, b.try_fold_with(f)?),
175            AliasTyOutlivesViaEnv(outlives) => AliasTyOutlivesViaEnv(outlives.try_fold_with(f)?),
176            PlaceholderTyOutlives(a, b) => {
177                PlaceholderTyOutlives(a.try_fold_with(f)?, b.try_fold_with(f)?)
178            }
179            And(and) => {
180                let mut new_and = Vec::new();
181                for a in and {
182                    new_and.push(a.try_fold_with(f)?);
183                }
184                And(new_and.into_boxed_slice())
185            }
186            Or(or) => {
187                let mut new_or = Vec::new();
188                for a in or {
189                    new_or.push(a.try_fold_with(f)?);
190                }
191                Or(new_or.into_boxed_slice())
192            }
193        })
194    }
195
196    fn fold_with<F: TypeFolder<I>>(self, f: &mut F) -> Self {
197        use RegionConstraint::*;
198        match self {
199            Ambiguity => self,
200            RegionOutlives(a, b) => RegionOutlives(a.fold_with(f), b.fold_with(f)),
201            AliasTyOutlivesViaEnv(outlives) => AliasTyOutlivesViaEnv(outlives.fold_with(f)),
202            PlaceholderTyOutlives(a, b) => PlaceholderTyOutlives(a.fold_with(f), b.fold_with(f)),
203            And(and) => {
204                let mut new_and = Vec::new();
205                for a in and {
206                    new_and.push(a.fold_with(f));
207                }
208                And(new_and.into_boxed_slice())
209            }
210            Or(or) => {
211                let mut new_or = Vec::new();
212                for a in or {
213                    new_or.push(a.fold_with(f));
214                }
215                Or(new_or.into_boxed_slice())
216            }
217        }
218    }
219}
220
221impl<I: Interner> TypeVisitable<I> for RegionConstraint<I> {
222    fn visit_with<F: TypeVisitor<I>>(&self, f: &mut F) -> F::Result {
223        use core::ops::ControlFlow::*;
224
225        use RegionConstraint::*;
226
227        match self {
228            Ambiguity => (),
229            RegionOutlives(a, b) => {
230                if let b @ Break(_) = a.visit_with(f).branch() {
231                    return F::Result::from_branch(b);
232                };
233                if let b @ Break(_) = b.visit_with(f).branch() {
234                    return F::Result::from_branch(b);
235                };
236            }
237            AliasTyOutlivesViaEnv(outlives) => {
238                return outlives.visit_with(f);
239            }
240            PlaceholderTyOutlives(a, b) => {
241                if let b @ Break(_) = a.visit_with(f).branch() {
242                    return F::Result::from_branch(b);
243                };
244                if let b @ Break(_) = b.visit_with(f).branch() {
245                    return F::Result::from_branch(b);
246                };
247            }
248            And(and) => {
249                for a in and {
250                    if let b @ Break(_) = a.visit_with(f).branch() {
251                        return F::Result::from_branch(b);
252                    };
253                }
254            }
255            Or(or) => {
256                for a in or {
257                    if let b @ Break(_) = a.visit_with(f).branch() {
258                        return F::Result::from_branch(b);
259                    };
260                }
261            }
262        };
263
264        F::Result::output()
265    }
266}
267
268impl<I: Interner> Default for RegionConstraint<I> {
269    fn default() -> Self {
270        Self::new_true()
271    }
272}
273
274impl<I: Interner> RegionConstraint<I> {
275    pub fn new_true() -> Self {
276        RegionConstraint::And(Box::new([]))
277    }
278
279    pub fn is_true(&self) -> bool {
280        match self {
281            Self::And(and) => and.is_empty(),
282            _ => false,
283        }
284    }
285
286    pub fn new_false() -> Self {
287        RegionConstraint::Or(Box::new([]))
288    }
289
290    pub fn is_false(&self) -> bool {
291        match self {
292            Self::Or(or) => or.is_empty(),
293            _ => false,
294        }
295    }
296
297    pub fn is_or(&self) -> bool {
298        #[allow(non_exhaustive_omitted_patterns)] match self {
    Self::Or(_) => true,
    _ => false,
}matches!(self, Self::Or(_))
299    }
300
301    pub fn unwrap_or(self) -> Box<[RegionConstraint<I>]> {
302        match self {
303            Self::Or(ors) => ors,
304            _ => {
    ::core::panicking::panic_fmt(format_args!("`unwrap_or` on non-Or: {0:?}",
            self));
}panic!("`unwrap_or` on non-Or: {self:?}"),
305        }
306    }
307
308    pub fn unwrap_and(self) -> Box<[RegionConstraint<I>]> {
309        match self {
310            Self::And(ands) => ands,
311            _ => {
    ::core::panicking::panic_fmt(format_args!("`unwrap_and` on non-And: {0:?}",
            self));
}panic!("`unwrap_and` on non-And: {self:?}"),
312        }
313    }
314
315    pub fn is_and(&self) -> bool {
316        #[allow(non_exhaustive_omitted_patterns)] match self {
    Self::And(_) => true,
    _ => false,
}matches!(self, Self::And(_))
317    }
318
319    pub fn is_ambig(&self) -> bool {
320        #[allow(non_exhaustive_omitted_patterns)] match self {
    Self::Ambiguity => true,
    _ => false,
}matches!(self, Self::Ambiguity)
321    }
322
323    pub fn and(self, other: RegionConstraint<I>) -> RegionConstraint<I> {
324        use RegionConstraint::*;
325
326        match (self, other) {
327            (And(a_ands), And(b_ands)) => And(a_ands
328                .into_iter()
329                .chain(b_ands.into_iter())
330                .collect::<Vec<_>>()
331                .into_boxed_slice()),
332            (And(ands), other) | (other, And(ands)) => {
333                And(ands.into_iter().chain([other]).collect::<Vec<_>>().into_boxed_slice())
334            }
335            (this, other) => And(Box::new([this, other])),
336        }
337    }
338
339    /// Converts the region constraint into an ORs of ANDs of "leaf" constraints. Where
340    /// a leaf constraint is a non-or/and constraint.
341    x;#[instrument(level = "debug", ret)]
342    pub fn canonical_form(self) -> Self {
343        use RegionConstraint::*;
344
345        fn permutations<I: Interner>(
346            ors: &[Vec<RegionConstraint<I>>],
347        ) -> Vec<Vec<RegionConstraint<I>>> {
348            match ors {
349                [] => vec![vec![]],
350                [or1] => {
351                    let mut choices = vec![];
352                    for choice in or1 {
353                        choices.push(vec![choice.clone()]);
354                    }
355                    choices
356                }
357                [or1, rest_ors @ ..] => {
358                    let mut choices = vec![];
359                    for choice in or1 {
360                        choices.extend(permutations(rest_ors).into_iter().map(|mut and| {
361                            and.push(choice.clone());
362                            and
363                        }));
364                    }
365                    choices
366                }
367            }
368        }
369
370        let canonical = match self {
371            And(ands) => {
372                // AND of OR of AND of LEAFs
373                //
374                // We can turn `AND of OR of X` into `OR of AND of X` by enumerating every set of choices
375                // for the list of ORs. For example if we have `AND ( OR(A, B), OR(C, D) )` we can convert this into
376                // `OR ( AND (A, C), AND (A, D), AND (B, C), AND (B, D ))`
377                //
378                // if A/B/C/D are all in canonical forms then we wind up with an `OR of AND of AND of LEAFs` which
379                // is trivially canonicalizeable by flattening the multiple layers of AND into one.
380                let ors = ands
381                    .into_iter()
382                    .map(|c| c.canonical_form().unwrap_or().to_vec())
383                    .collect::<Vec<_>>();
384                debug!(?ors);
385                let or_permutations = permutations(&ors);
386                debug!(?or_permutations);
387
388                Or(or_permutations
389                    .into_iter()
390                    .map(|c| {
391                        And(c
392                            .into_iter()
393                            .flat_map(|c2| c2.unwrap_and().into_iter())
394                            .collect::<Vec<_>>()
395                            .into_boxed_slice())
396                    })
397                    .collect::<Vec<_>>()
398                    .into_boxed_slice())
399            }
400            Or(ors) => {
401                // OR of OR of AND of LEAFs
402                //
403                // trivially canonicalizeable by concatenating all of the ORs into one big OR
404                Or(ors
405                    .into_iter()
406                    .flat_map(|c| c.canonical_form().unwrap_or().into_iter())
407                    .collect::<Vec<_>>()
408                    .into_boxed_slice())
409            }
410            _ => Or(Box::new([And(Box::new([self]))])),
411        };
412
413        assert!(
414            canonical.is_canonical_form(),
415            "non canonical form region constraint: {:?}",
416            canonical
417        );
418        canonical
419    }
420
421    fn is_leaf_constraint(&self) -> bool {
422        use RegionConstraint::*;
423        match self {
424            Ambiguity
425            | RegionOutlives(..)
426            | AliasTyOutlivesViaEnv(..)
427            | PlaceholderTyOutlives(..) => true,
428            And(..) | Or(..) => false,
429        }
430    }
431
432    fn is_canonical_and(&self) -> bool {
433        if let Self::And(ands) = self { ands.iter().all(|c| c.is_leaf_constraint()) } else { false }
434    }
435
436    pub fn is_canonical_form(&self) -> bool {
437        if let Self::Or(ors) = self { ors.iter().all(|c| c.is_canonical_and()) } else { false }
438    }
439}
440
441/// Takes any constraints involving placeholders from the current universe and eagerly checks them.
442/// This can be done a few ways:
443/// - There's an assumption on the binder introducing the placeholder which means the constraint is satisfied (true)
444/// - There's assumptions on the binder introducing the placeholder which allow us to rewrite the constraint in
445///    terms of lower universe variables. For example given `for<'a> where('b: 'a) { prove(T: '!a_u1) }` we can
446///    convert this constraint to `T: 'b` which no longer references anything from `u1`.
447/// - There are no relevant assumptions so we can neither rewrite the constraint nor consider it satisfied (false)
448/// - We failed to compute the full set of assumptions when entering the binder corresponding to `u`. (ambiguity)
449///
450/// After handling all of the region constraints in `u` we then evaluate the entire constraint as much as possible,
451/// propagating true/false/ambiguity as close to the root of the constraint as we can. The returned constraint should
452/// be checked for whether it is true/false/ambiguous as that should affect the result of whatever operation required
453/// entering the binder corresponding to `u`.
454x;#[instrument(level = "debug", skip(infcx), ret)]
455pub fn eagerly_handle_placeholders_in_universe<Infcx: InferCtxtLike<Interner = I>, I: Interner>(
456    infcx: &Infcx,
457    constraint: RegionConstraint<I>,
458    u: UniverseIndex,
459) -> RegionConstraint<I> {
460    use RegionConstraint::*;
461
462    let assumptions = infcx.get_placeholder_assumptions(u);
463
464    // 1. rewrite type outlives constraints involving things from `u` into either region constraints
465    //     involving things from `u` or type outlives constraints not involving things from `u`
466    //
467    //    IOW, we only want to encounter things from `u` as part of region out lives constraints.
468    let constraint = rewrite_type_outlives_constraints_in_universe_for_eager_placeholder_handling(
469        infcx,
470        constraint,
471        u,
472        &assumptions,
473    );
474
475    // 2. rewrite the constraint into a canonical ORs of ANDs form
476    let constraint = constraint.canonical_form();
477
478    // 3. compute transitive region outlives and get a new set of region outlives constraints by
479    //     looking for every region which either a placeholder_u flows into it, or it flows into
480    //     the placeholder.
481    //
482    //    do this for each element in the top level OR
483    let constraint = Or(constraint
484        .unwrap_or()
485        .into_iter()
486        .map(|c| {
487            let and =
488                And(compute_new_region_constraints(infcx, &c.unwrap_and(), u).into_boxed_slice());
489
490            // 4. rewrite region outlives constraints (potentially to false/true)
491            pull_region_outlives_constraints_out_of_universe(infcx, and, u, &assumptions)
492        })
493        .collect::<Vec<_>>()
494        .into_boxed_slice());
495
496    // 5. actually evaluate the constraint to eagerly error on false
497    evaluate_solver_constraint(&constraint)
498}
499
500/// Filter our region constraints to not include constraints between region variables from `u` and
501/// other regions as those are always satisfied. This requires some care to handle correctly for example:
502/// `'!a_u1: '?x_u1: '!b_u1` should result in us requiring `'!a_u1: '!b_u1` rather than dropping the two
503/// constraints entirely.
504///
505/// The only constraints involving things from `u` should be region outlives constraints at this point. Type
506/// outlives constraints should have been handled already either by destructuring into region outlives or by
507/// being rewritten in terms of smaller universe variables.
508x;#[instrument(level = "debug", skip(infcx), ret)]
509fn compute_new_region_constraints<Infcx: InferCtxtLike<Interner = I>, I: Interner>(
510    infcx: &Infcx,
511    constraints: &[RegionConstraint<I>],
512    u: UniverseIndex,
513) -> Vec<RegionConstraint<I>> {
514    use RegionConstraint::*;
515
516    let mut new_constraints = vec![];
517
518    let mut region_flows_builder = TransitiveRelationBuilder::default();
519    let mut regions = IndexSet::new();
520    for c in constraints {
521        match c {
522            And(..) | Or(..) => unreachable!(),
523            Ambiguity | PlaceholderTyOutlives(..) | AliasTyOutlivesViaEnv(..) => {
524                new_constraints.push(c.clone())
525            }
526            RegionOutlives(r1, r2) => {
527                regions.insert(r1);
528                regions.insert(r2);
529                region_flows_builder.add(r2, r1);
530            }
531        }
532    }
533
534    let region_flow = region_flows_builder.freeze();
535    for r in regions.into_iter() {
536        for ub in region_flow.reachable_from(r) {
537            // we want to retain any region constraints between two "placeholder-likes" where for our
538            // purposes a placeholder-like is either a placeholder or variable in a lower universe
539            let is_placeholder_like = |r: I::Region| match r.kind() {
540                RegionKind::ReLateParam(..)
541                | RegionKind::ReEarlyParam(..)
542                | RegionKind::RePlaceholder(..)
543                | RegionKind::ReStatic => true,
544                RegionKind::ReVar(..) => max_universe(infcx, r) < u,
545                RegionKind::ReError(..) => false,
546                RegionKind::ReErased | RegionKind::ReBound(..) => unreachable!(),
547            };
548
549            if is_placeholder_like(*r) && is_placeholder_like(*ub) {
550                new_constraints.push(RegionOutlives(*ub, *r));
551            }
552        }
553    }
554
555    new_constraints
556}
557
558/// Evaluate ANDs and ORs to true/false/ambiguous based on whether their arguments are true/false/ambiguous
559x;#[instrument(level = "debug", ret)]
560pub fn evaluate_solver_constraint<I: Interner>(
561    constraint: &RegionConstraint<I>,
562) -> RegionConstraint<I> {
563    use RegionConstraint::*;
564    match constraint {
565        Ambiguity | RegionOutlives(..) | AliasTyOutlivesViaEnv(..) | PlaceholderTyOutlives(..) => {
566            constraint.clone()
567        }
568        And(and) => {
569            let mut and_constraints = Vec::new();
570            let mut is_ambiguous_constraint = false;
571            for c in and.iter() {
572                let evaluated_constraint = evaluate_solver_constraint(c);
573                if evaluated_constraint.is_true() {
574                    // - do nothing
575                } else if evaluated_constraint.is_false() {
576                    return RegionConstraint::new_false();
577                } else if evaluated_constraint.is_ambig() {
578                    is_ambiguous_constraint = true;
579                } else {
580                    and_constraints.push(evaluated_constraint);
581                }
582            }
583
584            if is_ambiguous_constraint {
585                RegionConstraint::Ambiguity
586            } else {
587                RegionConstraint::And(and_constraints.into_boxed_slice())
588            }
589        }
590        Or(or) => {
591            let mut or_constraints = Vec::new();
592            let mut is_ambiguous_constraint = false;
593            for c in or.iter() {
594                let evaluated_constraint = evaluate_solver_constraint(c);
595                if evaluated_constraint.is_false() {
596                    // do nothing
597                } else if evaluated_constraint.is_true() {
598                    return RegionConstraint::new_true();
599                } else if evaluated_constraint.is_ambig() {
600                    is_ambiguous_constraint = true;
601                } else {
602                    or_constraints.push(evaluated_constraint);
603                }
604            }
605
606            if is_ambiguous_constraint {
607                RegionConstraint::Ambiguity
608            } else {
609                RegionConstraint::Or(or_constraints.into_boxed_slice())
610            }
611        }
612    }
613}
614
615/// Handles converting region outlives constraints involving placeholders from `u` into OR constraints
616/// involving regions from smaller universes with known relationships to the placeholder. For example:
617/// ```ignore (not rust)
618/// for<'a, 'b> where(
619///     'c: 'b, 'd: 'b,
620///     'a: 'e, 'a: 'f,
621/// ) {
622///     'a_u1: 'b_u1
623/// }
624/// ```
625/// will get converted to:
626/// ```ignore (not rust)
627/// OR(
628///     'e: 'c,
629///     'e: 'd,
630///     'f: 'c,
631///     'f: 'd,
632/// )
633/// ```
634/// if we are handling constraints in `u1`.
635x;#[instrument(level = "debug", skip(infcx), ret)]
636fn pull_region_outlives_constraints_out_of_universe<
637    Infcx: InferCtxtLike<Interner = I>,
638    I: Interner,
639>(
640    infcx: &Infcx,
641    constraint: RegionConstraint<I>,
642    u: UniverseIndex,
643    assumptions: &Option<Assumptions<I>>,
644) -> RegionConstraint<I> {
645    assert!(max_universe(infcx, constraint.clone()) <= u);
646
647    // FIXME(-Zassumptions-on-binders): we don't lower universes of region variables when exiting `u`
648    // this seems dubious/potentially wrong? we can't just blindly do this though as if we had something
649    // like `!T_u -> ?x_u -> !U_u` then lowering `?x` to `u-1` when exiting `u` would be wrong.
650    //
651    // I'm not even sure this would be necessary given we filter out region constraints involving regions#
652    // from the current universe and only retain those between placeholders.
653
654    use RegionConstraint::*;
655    match constraint {
656        Ambiguity | PlaceholderTyOutlives(..) | AliasTyOutlivesViaEnv(..) => {
657            assert!(max_universe(infcx, constraint.clone()) < u);
658            constraint
659        }
660        RegionOutlives(region_1, region_2) => {
661            let region_1_u = max_universe(infcx, region_1);
662            let region_2_u = max_universe(infcx, region_2);
663
664            if region_1_u != u && region_2_u != u {
665                return constraint;
666            }
667
668            let assumptions = match assumptions {
669                Some(assumptions) => assumptions,
670                None => return RegionConstraint::Ambiguity,
671            };
672
673            let mut candidates = vec![];
674            for ub in
675                regions_outlived_by(region_1, assumptions).filter(|r| max_universe(infcx, *r) < u)
676            {
677                // FIXME(-Zassumptions-on-binders): if `region_2` is in a smaller universe there'll be both
678                // `'region_2` and `'static` as lower bounds which seems... unfortunate and may cause us to
679                // add a bunch of duplicate `'ub: 'static` candidates the more binders we leave.
680                for lb in regions_outliving(region_2, assumptions, infcx.cx())
681                    .filter(|r| max_universe(infcx, *r) < u)
682                {
683                    // As long as any region outlived by `region_1` outlives any region region which
684                    // `region_2` outlives, we know that `region_1: region_2` holds. In other words,
685                    // there exists some set of 4 regions for which `'r1: 'i1` `'i1: 'i2` `'i2: 'r2`
686                    candidates.push(RegionOutlives(ub, lb));
687                }
688            }
689
690            RegionConstraint::Or(candidates.into_boxed_slice())
691        }
692        And(constraints) => And(constraints
693            .into_iter()
694            .map(|constraint| {
695                pull_region_outlives_constraints_out_of_universe(infcx, constraint, u, assumptions)
696            })
697            .collect()),
698        Or(_) => unreachable!(),
699    }
700}
701
702/// Converts type outlives constraints into region outlives constraints. This assumes the *complete* set of
703/// assumptions are known. This should not be called until the end of type checking.
704///
705/// The returned region constraint will not have *any* PlaceholderTyOutlives or AliasTyOutlivesViaEnv constraints.
706pub fn destructure_type_outlives_constraints_in_root<
707    Infcx: InferCtxtLike<Interner = I>,
708    I: Interner,
709>(
710    infcx: &Infcx,
711    constraint: RegionConstraint<I>,
712    assumptions: &Assumptions<I>,
713) -> RegionConstraint<I> {
714    use RegionConstraint::*;
715
716    match constraint {
717        Ambiguity | RegionOutlives(..) => constraint,
718        PlaceholderTyOutlives(ty, r) => {
719            Or(regions_outlived_by_placeholder(ty, assumptions, infcx.cx())
720                .map(move |assumption_r| RegionOutlives(assumption_r, r))
721                .collect::<Vec<_>>()
722                .into_boxed_slice())
723        }
724        AliasTyOutlivesViaEnv(bound_outlives) => {
725            alias_outlives_candidates_from_assumptions(infcx, bound_outlives, assumptions)
726        }
727        And(constraints) => And(constraints
728            .into_iter()
729            .map(|constraint| {
730                destructure_type_outlives_constraints_in_root(infcx, constraint, assumptions)
731            })
732            .collect()),
733        Or(constraints) => Or(constraints
734            .into_iter()
735            .map(|constraint| {
736                destructure_type_outlives_constraints_in_root(infcx, constraint, assumptions)
737            })
738            .collect()),
739    }
740}
741
742/// Converts type outlives constraints into either region outlives constraints, or type outlives
743/// constraints which do not contain anything from `u`.
744///
745/// This only works off assumptions associated with the binder corresponding to `u` both for
746/// perf reasons and because the full set of region assumptions is not known during type checking
747/// due to closure signature inference.
748///
749/// This only really causes problems for higher-ranked outlives assumptions, for example if we have
750/// `where for<'a> <T as Trait<'a>>::Assoc: 'b` then we can't use that to prove `<T as Trait<'!c>>::Assoc: 'b`
751/// until we are in the root context. See comments inside this function for more detail.
752x;#[instrument(level = "debug", skip(infcx), ret)]
753fn rewrite_type_outlives_constraints_in_universe_for_eager_placeholder_handling<
754    Infcx: InferCtxtLike<Interner = I>,
755    I: Interner,
756>(
757    infcx: &Infcx,
758    constraint: RegionConstraint<I>,
759    u: UniverseIndex,
760    assumptions: &Option<Assumptions<I>>,
761) -> RegionConstraint<I> {
762    assert!(
763        max_universe(infcx, constraint.clone()) <= u,
764        "constraint {:?} contains terms from a larger universe than {:?}",
765        constraint.clone(),
766        u
767    );
768
769    use RegionConstraint::*;
770    match constraint {
771        Ambiguity | RegionOutlives(..) => constraint,
772        PlaceholderTyOutlives(ty, region) => {
773            let ty_u = max_universe(infcx, ty);
774            let region_u = max_universe(infcx, region);
775
776            if region_u != u && ty_u != u {
777                return constraint;
778            }
779
780            let assumptions = match assumptions {
781                Some(assumptions) => assumptions,
782                None => return Ambiguity,
783            };
784
785            let mut candidates = vec![];
786
787            // There could be `!T: 'region` assumptions in the env even if `!T` is in a
788            // smaller universe
789            candidates.extend(
790                regions_outlived_by_placeholder(ty, assumptions, infcx.cx())
791                    .map(move |assumption_r| RegionOutlives(assumption_r, region)),
792            );
793
794            // We can express `!T: 'region` as `!T: 'r` where `'r: 'region`. This is only necessary
795            // if the placeholder type is in a smaller universe as otherwise we know all regions which
796            // the placeholder outlives and can just destructure into an OR of RegionOutlives.
797            if region_u == u && ty_u < u {
798                candidates.extend(
799                    regions_outliving::<I>(region, assumptions, infcx.cx())
800                        .filter(|r| max_universe(infcx, *r) < u)
801                        .map(|r| PlaceholderTyOutlives(ty, r)),
802                );
803            }
804
805            Or(candidates.into_boxed_slice())
806        }
807        AliasTyOutlivesViaEnv(bound_outlives) => {
808            let mut candidates = Vec::new();
809
810            // given there can be higher ranked assumptions, e.g. `for<'a> <T as Trait<'a>>::Assoc: 'c`, that
811            // means that it's actually *always* possible for an alias outlive to be satisfied in the root universe
812            // which means there should *always* be atleast two candidates when destructuring alias outlives. The
813            // two candidates being component outlives and then a higher ranked alias outlives.
814            //
815            // we dont care about this for region outlives as `for<'a> 'a: 'b` can't exist as we don't elaborate
816            // higher ranked type outlives assumptions into higher ranked region outlives assumptions. similarly,
817            // we don't care about `for<'a> Foo<'a>: 'b` as we always destructure adts into their components and if
818            // we dont equivalently elaborate the assumption into assumptions on the adt's components we just drop the
819            // assumptions
820            //
821            // so actually only `for<'a, 'b> Alias<'a>: 'b` and `for<'a> T: 'a` are assumptions we actually need to
822            // handle.
823            //
824            // we don't care about this when rewriting in the root universe as we know the complete set of assumptions
825            if max_universe(infcx, bound_outlives) == u {
826                let mut replacer = PlaceholderReplacer {
827                    cx: infcx.cx(),
828                    existing_var_count: bound_outlives.bound_vars().len(),
829                    bound_vars: IndexMap::default(),
830                    universe: u,
831                    current_index: DebruijnIndex::ZERO,
832                };
833                let escaping_outlives = bound_outlives.skip_binder().fold_with(&mut replacer);
834                let bound_vars = bound_outlives.bound_vars().iter().chain(
835                    core::mem::take(&mut replacer.bound_vars)
836                        .into_iter()
837                        .map(|(_, bound_region)| BoundVariableKind::Region(bound_region.kind)),
838                );
839                let bound_outlives = Binder::bind_with_vars(
840                    escaping_outlives,
841                    I::BoundVarKinds::from_vars(infcx.cx(), bound_vars),
842                );
843                candidates.push(RegionConstraint::AliasTyOutlivesViaEnv(bound_outlives));
844            }
845
846            let assumptions = match assumptions {
847                Some(assumptions) => assumptions,
848                None => {
849                    candidates.push(Ambiguity);
850                    return Or(candidates.into_boxed_slice());
851                }
852            };
853
854            // Actually look at the assumptions and matching our higher ranked alias outlives goal
855            // against potentially higher ranked type outlives assumptions.
856            candidates.push(alias_outlives_candidates_from_assumptions(
857                infcx,
858                bound_outlives,
859                assumptions,
860            ));
861
862            // we can rewrite `Alias_u1: 'u2` into `Or(Alias_u1: 'u1)`
863            // given a list of regions which outlive `'u2`
864            //
865            // we don't care about this when rewriting in the root universe as we know the complete set of assumptions
866            let (escaping_alias, escaping_r) = bound_outlives.skip_binder();
867            if max_universe(infcx, escaping_r) == u {
868                let mut replacer = PlaceholderReplacer {
869                    cx: infcx.cx(),
870                    existing_var_count: bound_outlives.bound_vars().len(),
871                    bound_vars: IndexMap::default(),
872                    universe: u,
873                    current_index: DebruijnIndex::ZERO,
874                };
875                let escaping_alias = escaping_alias.fold_with(&mut replacer);
876                let bound_vars = bound_outlives.bound_vars().iter().chain(
877                    core::mem::take(&mut replacer.bound_vars)
878                        .into_iter()
879                        .map(|(_, bound_region)| BoundVariableKind::Region(bound_region.kind)),
880                );
881                let bound_alias = Binder::bind_with_vars(
882                    escaping_alias,
883                    I::BoundVarKinds::from_vars(infcx.cx(), bound_vars),
884                );
885
886                // while we did skip the binder, bound vars aren't in any universe so
887                // this can't be an escaping bound var
888                candidates.extend(
889                    regions_outliving(escaping_r, assumptions, infcx.cx())
890                        .filter(|r2| max_universe(infcx, *r2) < u)
891                        .map(|r2| AliasTyOutlivesViaEnv(bound_alias.map_bound(|alias| (alias, r2))))
892                        .collect::<Vec<_>>(),
893                );
894            }
895
896            // I'm not convinced our handling here is *complete* so for now
897            // let's be conservative and not let alias outlives' cause NoSolution
898            // in coherence
899            match infcx.typing_mode_raw() {
900                TypingMode::Coherence => candidates.push(RegionConstraint::Ambiguity),
901                TypingMode::Analysis { .. }
902                | TypingMode::ErasedNotCoherence { .. }
903                | TypingMode::Borrowck { .. }
904                | TypingMode::PostBorrowckAnalysis { .. }
905                | TypingMode::PostAnalysis => (),
906            };
907
908            RegionConstraint::Or(candidates.into_boxed_slice())
909        }
910        And(constraints) => And(constraints
911            .into_iter()
912            .map(|constraint| {
913                rewrite_type_outlives_constraints_in_universe_for_eager_placeholder_handling(
914                    infcx,
915                    constraint,
916                    u,
917                    assumptions,
918                )
919            })
920            .collect()),
921        Or(constraints) => Or(constraints
922            .into_iter()
923            .map(|constraint| {
924                rewrite_type_outlives_constraints_in_universe_for_eager_placeholder_handling(
925                    infcx,
926                    constraint,
927                    u,
928                    assumptions,
929                )
930            })
931            .collect()),
932    }
933}
934
935/// Returns all regions `r2` for which `r: r2` is known to hold in
936/// the universe associated with `assumptions`
937pub fn regions_outlived_by<I: Interner>(
938    r: I::Region,
939    assumptions: &Assumptions<I>,
940) -> impl Iterator<Item = I::Region> {
941    // FIXME(-Zassumptions-on-binders): do we need to be adding the reflexive edge here?
942    assumptions.region_outlives.reachable_from(r).into_iter().chain([r])
943}
944
945/// Returns all regions `r2` for which `r2: r` is known to hold in
946/// the universe associated with `assumptions`
947pub fn regions_outliving<I: Interner>(
948    r: I::Region,
949    assumptions: &Assumptions<I>,
950    cx: I,
951) -> impl Iterator<Item = I::Region> {
952    assumptions
953        .inverse_region_outlives
954        .reachable_from(r)
955        .into_iter()
956        // FIXME(-Zassumptions-on-binders): 'static may have been an input region canonicalized to something else is that important?
957        // FIXME(-Zassumptions-on-binders): do we need to adding the reflexive edge here?
958        .chain([r, I::Region::new_static(cx)])
959}
960
961/// Returns all regions `r` for which `!t: r` is known to hold in
962/// the universe associated with `assumptions`
963pub fn regions_outlived_by_placeholder<I: Interner>(
964    t: I::Ty,
965    assumptions: &Assumptions<I>,
966    cx: I,
967) -> impl Iterator<Item = I::Region> {
968    match t.kind() {
969        TyKind::Placeholder(..) | TyKind::Param(..) => (),
970        _ => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("non-placeholder in `regions_outlived_by_placeholder`: {0:?}",
                t)));
}unreachable!("non-placeholder in `regions_outlived_by_placeholder`: {t:?}"),
971    }
972
973    assumptions.type_outlives.iter().flat_map(move |binder| match binder.no_bound_vars() {
974        Some(OutlivesPredicate(ty, r)) => (ty == t).then_some(r),
975        None => Some(I::Region::new_static(cx)),
976    })
977}
978
979/// The largest universe a variable or placeholder was from in `t`
980pub fn max_universe<Infcx: InferCtxtLike<Interner = I>, I: Interner, T: TypeVisitable<I>>(
981    infcx: &Infcx,
982    t: T,
983) -> UniverseIndex {
984    let mut visitor = MaxUniverse::new(infcx);
985    t.visit_with(&mut visitor);
986    visitor.max_universe()
987}
988
989// FIXME(-Zassumptions-on-binders): Share this with the visitor used by generalization. We currently don't
990// as generalization does not look at universes of inference variables but we do
991struct MaxUniverse<'a, Infcx: InferCtxtLike> {
992    max_universe: UniverseIndex,
993    infcx: &'a Infcx,
994}
995
996impl<'a, Infcx: InferCtxtLike> MaxUniverse<'a, Infcx> {
997    fn new(infcx: &'a Infcx) -> Self {
998        MaxUniverse { infcx, max_universe: UniverseIndex::ROOT }
999    }
1000
1001    fn max_universe(self) -> UniverseIndex {
1002        self.max_universe
1003    }
1004}
1005
1006impl<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeVisitor<I>
1007    for MaxUniverse<'a, Infcx>
1008{
1009    type Result = ();
1010
1011    fn visit_ty(&mut self, t: I::Ty) {
1012        match t.kind() {
1013            TyKind::Placeholder(p) => self.max_universe = self.max_universe.max(p.universe),
1014            TyKind::Infer(InferTy::TyVar(inf)) => {
1015                let u = self.infcx.universe_of_ty(inf).unwrap();
1016                {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_type_ir/src/region_constraint.rs:1016",
                        "rustc_type_ir::region_constraint", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_type_ir/src/region_constraint.rs"),
                        ::tracing_core::__macro_support::Option::Some(1016u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_type_ir::region_constraint"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("var {0:?} in universe {1:?}",
                                                    inf, u) as &dyn Value))])
            });
    } else { ; }
};debug!("var {inf:?} in universe {u:?}");
1017                self.max_universe = self.max_universe.max(u);
1018            }
1019            _ => t.super_visit_with(self),
1020        }
1021    }
1022
1023    fn visit_const(&mut self, c: I::Const) {
1024        match c.kind() {
1025            ConstKind::Placeholder(p) => self.max_universe = self.max_universe.max(p.universe),
1026            ConstKind::Infer(rustc_type_ir::InferConst::Var(inf)) => {
1027                let u = self.infcx.universe_of_ct(inf).unwrap();
1028                {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_type_ir/src/region_constraint.rs:1028",
                        "rustc_type_ir::region_constraint", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_type_ir/src/region_constraint.rs"),
                        ::tracing_core::__macro_support::Option::Some(1028u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_type_ir::region_constraint"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("var {0:?} in universe {1:?}",
                                                    inf, u) as &dyn Value))])
            });
    } else { ; }
};debug!("var {inf:?} in universe {u:?}");
1029                self.max_universe = self.max_universe.max(u);
1030            }
1031            _ => c.super_visit_with(self),
1032        }
1033    }
1034
1035    fn visit_region(&mut self, r: I::Region) {
1036        match r.kind() {
1037            RegionKind::RePlaceholder(p) => self.max_universe = self.max_universe.max(p.universe),
1038            RegionKind::ReVar(var) => {
1039                let u = self.infcx.universe_of_lt(var).unwrap();
1040                {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_type_ir/src/region_constraint.rs:1040",
                        "rustc_type_ir::region_constraint", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_type_ir/src/region_constraint.rs"),
                        ::tracing_core::__macro_support::Option::Some(1040u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_type_ir::region_constraint"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("var {0:?} in universe {1:?}",
                                                    var, u) as &dyn Value))])
            });
    } else { ; }
};debug!("var {var:?} in universe {u:?}");
1041                self.max_universe = self.max_universe.max(u);
1042            }
1043            _ => (),
1044        }
1045    }
1046}
1047
1048pub struct PlaceholderReplacer<I: Interner> {
1049    cx: I,
1050    existing_var_count: usize,
1051    bound_vars: IndexMap<BoundVar, BoundRegion<I>>,
1052    universe: UniverseIndex,
1053    current_index: DebruijnIndex,
1054}
1055
1056impl<I: Interner> TypeFolder<I> for PlaceholderReplacer<I> {
1057    fn cx(&self) -> I {
1058        self.cx
1059    }
1060
1061    fn fold_region(&mut self, r: I::Region) -> I::Region {
1062        match r.kind() {
1063            RegionKind::RePlaceholder(p) if p.universe == self.universe => {
1064                let bound_vars_len = self.bound_vars.len();
1065                let mapped_var = self.bound_vars.entry(p.bound.var).or_insert(BoundRegion {
1066                    var: BoundVar::from_usize(self.existing_var_count + bound_vars_len),
1067                    kind: p.bound.kind,
1068                });
1069                I::Region::new_bound(self.cx, self.current_index, *mapped_var)
1070            }
1071            // FIXME(-Zassumptions-on-binders): We should be handling region variables here somehow
1072            _ => r,
1073        }
1074    }
1075
1076    fn fold_binder<T: TypeFoldable<I>>(&mut self, b: Binder<I, T>) -> Binder<I, T> {
1077        self.current_index.shift_in(1);
1078        let b = b.super_fold_with(self);
1079        self.current_index.shift_out(1);
1080        b
1081    }
1082}
1083
1084/// Converts an `AliasTyOutlivesViaEnv` constraint into an OR of region outlives constraints by
1085/// matching the alias against any `Alias: 'a` assumptions. This is somewhat tricky as we have a
1086/// potentially higher ranked alias being equated with a potentially higher ranked assumption and
1087/// we don't handle it correctly right now (though it is a somewhat reasonable halfway step).
1088x;#[instrument(level = "debug", skip(infcx), ret)]
1089fn alias_outlives_candidates_from_assumptions<Infcx: InferCtxtLike<Interner = I>, I: Interner>(
1090    infcx: &Infcx,
1091    bound_outlives: Binder<I, (AliasTy<I>, I::Region)>,
1092    assumptions: &Assumptions<I>,
1093) -> RegionConstraint<I> {
1094    let mut candidates = Vec::new();
1095
1096    let prev_universe = infcx.universe();
1097
1098    // FIXME(-Zassumptions-on-binders): Handle the assumptions on this binder
1099    infcx.enter_forall(bound_outlives, |(alias, r)| {
1100        let u = infcx.universe();
1101        infcx.insert_placeholder_assumptions(u, Some(Assumptions::empty()));
1102
1103        for bound_type_outlives in assumptions.type_outlives.iter() {
1104            let OutlivesPredicate(alias2, r2) =
1105                infcx.instantiate_binder_with_infer(*bound_type_outlives);
1106
1107            let mut relation = HigherRankedAliasMatcher {
1108                infcx,
1109                region_constraints: vec![RegionConstraint::RegionOutlives(r2, r)],
1110            };
1111
1112            if let Ok(_) = relation.relate(alias.to_ty(infcx.cx()), alias2) {
1113                candidates
1114                    .push(RegionConstraint::And(relation.region_constraints.into_boxed_slice()));
1115            }
1116        }
1117    });
1118
1119    let constraint = RegionConstraint::Or(candidates.into_boxed_slice());
1120
1121    let largest_universe = infcx.universe();
1122    debug!(?prev_universe, ?largest_universe);
1123
1124    ((prev_universe.index() + 1)..=largest_universe.index())
1125        .map(|u| UniverseIndex::from_usize(u))
1126        .rev()
1127        .fold(constraint, |constraint, u| {
1128            eagerly_handle_placeholders_in_universe(infcx, constraint, u)
1129        })
1130}
1131
1132struct HigherRankedAliasMatcher<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> {
1133    infcx: &'a Infcx,
1134    region_constraints: Vec<RegionConstraint<I>>,
1135}
1136
1137impl<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeRelation<I>
1138    for HigherRankedAliasMatcher<'a, Infcx, I>
1139{
1140    fn cx(&self) -> I {
1141        self.infcx.cx()
1142    }
1143
1144    fn relate_ty_args(
1145        &mut self,
1146        a_ty: I::Ty,
1147        _b_ty: I::Ty,
1148        _ty_def_id: I::DefId,
1149        a_args: I::GenericArgs,
1150        b_args: I::GenericArgs,
1151        _mk: impl FnOnce(I::GenericArgs) -> I::Ty,
1152    ) -> RelateResult<I, I::Ty> {
1153        rustc_type_ir::relate::relate_args_invariantly(self, a_args, b_args)?;
1154        Ok(a_ty)
1155    }
1156
1157    fn relate_with_variance<T: Relate<I>>(
1158        &mut self,
1159        _variance: Variance,
1160        _info: VarianceDiagInfo<I>,
1161        a: T,
1162        b: T,
1163    ) -> RelateResult<I, T> {
1164        // FIXME(-Zassumptions-on-binders): bivariance is important for opaque type args so
1165        // we should actually handle variance in some way here.
1166        self.relate(a, b)
1167    }
1168
1169    fn tys(&mut self, a: I::Ty, b: I::Ty) -> RelateResult<I, I::Ty> {
1170        rustc_type_ir::relate::structurally_relate_tys(self, a, b)
1171    }
1172
1173    fn regions(&mut self, a: I::Region, b: I::Region) -> RelateResult<I, I::Region> {
1174        if a != b {
1175            self.region_constraints.push(RegionConstraint::RegionOutlives(a, b));
1176            self.region_constraints.push(RegionConstraint::RegionOutlives(b, a));
1177        }
1178        Ok(a)
1179    }
1180
1181    fn consts(&mut self, a: I::Const, b: I::Const) -> RelateResult<I, I::Const> {
1182        rustc_type_ir::relate::structurally_relate_consts(self, a, b)
1183    }
1184
1185    fn binders<T>(&mut self, a: Binder<I, T>, b: Binder<I, T>) -> RelateResult<I, Binder<I, T>>
1186    where
1187        T: Relate<I>,
1188    {
1189        self.infcx.enter_forall(a, |a| {
1190            let u = self.infcx.universe();
1191            self.infcx.insert_placeholder_assumptions(u, Some(Assumptions::empty()));
1192            let b = self.infcx.instantiate_binder_with_infer(b);
1193            self.relate(a, b)
1194        })?;
1195
1196        self.infcx.enter_forall(b, |b| {
1197            let u = self.infcx.universe();
1198            self.infcx.insert_placeholder_assumptions(u, Some(Assumptions::empty()));
1199            let a = self.infcx.instantiate_binder_with_infer(a);
1200            self.relate(a, b)
1201        })?;
1202
1203        Ok(a)
1204    }
1205}