diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 4c7ae87556f76..2d93f87986f1a 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -4075,11 +4075,20 @@ pub struct TestBinderConstraints { pub struct TestBinderBody { pub foralls: ThinVec, pub exists: ThinVec, + pub region_equalities: Vec, pub constraints: Vec, /// These are not where clauses, but rather predicates within the body to be proven pub predicates: Vec, } +#[derive(Clone, Encodable, Decodable, Debug, Walkable)] +pub struct TestBinderRegionEquality { + #[visitable(extra = LifetimeCtxt::Bound)] + pub lhs: Lifetime, + #[visitable(extra = LifetimeCtxt::Bound)] + pub rhs: Lifetime, +} + #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct TestBinderForall { pub span: Span, diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index e4813b9588409..1f7aad264c0ec 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -559,6 +559,7 @@ macro_rules! common_visitor_and_walkers { StructExpr, StructRest, Term, + TestBinderRegionEquality, Trait, TraitBoundModifiers, TraitObjectSyntax, diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 9cea3519cf94e..af339a3369e28 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1998,6 +1998,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let exists = self.arena.alloc_from_iter( body.exists.iter().map(|exists| self.lower_test_binder_exists(exists)), ); + let region_equalities = self.arena.alloc_from_iter(body.region_equalities.iter().map( + |TestBinderRegionEquality { lhs, rhs }| { + let lhs = self.lower_lifetime(lhs, LifetimeSource::Other, lhs.ident.into()); + let rhs = self.lower_lifetime(rhs, LifetimeSource::Other, rhs.ident.into()); + (lhs, rhs) + }, + )); let constraints = self.lower_test_binder_constraints_as_and(&body.constraints); let mut dedup_map = Default::default(); let predicates = self.arena.alloc_from_iter( @@ -2005,7 +2012,7 @@ impl<'hir> LoweringContext<'_, 'hir> { .iter() .map(|predicate| self.lower_where_predicate(predicate, &[], &mut dedup_map)), ); - hir::TestBinderBody { foralls, exists, constraints, predicates } + hir::TestBinderBody { foralls, exists, region_equalities, constraints, predicates } } fn lower_test_binder_forall( diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index ceb7f38c2a416..49db7d3734bf2 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4529,6 +4529,7 @@ impl FnHeader { pub struct TestBinderBody<'hir> { pub foralls: &'hir [TestBinderForall<'hir>], pub exists: &'hir [TestBinderExists<'hir>], + pub region_equalities: &'hir [(&'hir Lifetime, &'hir Lifetime)], /// Constraints to be inserted directly into constraint storage to be proven pub constraints: TestBinderConstraint<'hir>, /// Constraints declared using `where` syntax, used via `register_obligation` diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index b404d1708b85b..f4c5379015e60 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1600,9 +1600,13 @@ pub fn walk_test_binder_body<'v, V: Visitor<'v>>( visitor: &mut V, body: &'v TestBinderBody<'v>, ) -> V::Result { - let TestBinderBody { foralls, exists, constraints, predicates } = body; + let TestBinderBody { foralls, exists, region_equalities, constraints, predicates } = body; walk_list!(visitor, visit_test_binder_forall, *foralls); walk_list!(visitor, visit_test_binder_exists, *exists); + for (lhs, rhs) in *region_equalities { + try_visit!(visitor.visit_lifetime(lhs)); + try_visit!(visitor.visit_lifetime(rhs)); + } try_visit!(visitor.visit_test_binder_constraint(&constraints)); walk_list!(visitor, visit_where_predicate, *predicates); V::Result::output() diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 86f386381b9e2..fd525b5c4b68c 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -2356,7 +2356,15 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { #[instrument(level = "debug", skip(self))] pub(super) fn check_test_binder_body(&self, body: TestBinderBody<'tcx>) { - let TestBinderBody { foralls, exists, constraints, predicates } = body; + let TestBinderBody { foralls, exists, region_equalities, constraints, predicates } = body; + for (equality, span) in region_equalities { + let cause = traits::ObligationCause::misc(span, self.body_def_id); + self.infcx.register_region_eq_constraint( + equality, + ty::VisibleForLeakCheck::Yes, + &cause, + ); + } if !predicates.is_empty() { for (predicate, span) in predicates { let cause = traits::ObligationCause::misc(span, self.body_def_id); @@ -2776,6 +2784,7 @@ struct RedundantLifetimeArgsLint<'tcx> { pub(crate) struct TestBinderBody<'tcx> { pub foralls: Vec>, pub exists: Vec>, + pub region_equalities: Vec<(ty::RegionEqPredicate<'tcx>, Span)>, /// Constraints to be inserted directly into constraint storage to be proven pub constraints: SolverRegionConstraint<'tcx>, /// Constraints declared using `where` syntax, used via `register_obligation` diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index df9a3877b1f15..8b1964bd90780 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -328,16 +328,26 @@ impl<'tcx> ItemCtxt<'tcx> { &self, item: &hir::TestBinderBody<'tcx>, ) -> TestBinderBody<'tcx> { - let hir::TestBinderBody { foralls, exists, constraints, predicates } = item; + let hir::TestBinderBody { foralls, exists, region_equalities, constraints, predicates } = + item; let foralls = foralls.iter().map(|forall| self.lower_test_binder_forall(forall)).collect(); let exists = exists.iter().map(|exists| self.lower_test_binder_exists(exists)).collect(); + let region_equalities = region_equalities + .iter() + .map(|(lhs, rhs)| { + let span = lhs.ident.span.to(rhs.ident.span); + let lhs = self.lowerer().lower_lifetime(lhs, RegionInferReason::RegionPredicate); + let rhs = self.lowerer().lower_lifetime(rhs, RegionInferReason::RegionPredicate); + (ty::RegionEqPredicate(lhs, rhs), span) + }) + .collect(); let constraints = self.lower_test_binder_constraint(&constraints); let mut clauses = Default::default(); for predicate in *predicates { clauses_of::where_predicate_clauses(self, predicate, &mut clauses); } let predicates = clauses.into_iter().map(|(c, span)| (c.kind(), span)).collect(); - TestBinderBody { foralls, exists, constraints, predicates } + TestBinderBody { foralls, exists, region_equalities, constraints, predicates } } #[instrument(level = "debug", skip(self), ret)] diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 6d3d79bbe2b5c..59ded860410f4 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2715,6 +2715,7 @@ impl<'a> Parser<'a> { pub fn parse_test_binder_body(&mut self) -> PResult<'a, TestBinderBody> { let mut foralls = ThinVec::new(); let mut exists = ThinVec::new(); + let mut region_equalities = Vec::new(); let mut constraints = Vec::new(); let mut predicates = Vec::new(); self.parse_delim_comma_seq(exp!(OpenBrace), exp!(CloseBrace), |this| { @@ -2731,11 +2732,20 @@ impl<'a> Parser<'a> { exists.push(this.parse_test_binder_exists()?) } + _ if this.token.is_lifetime() && this.look_ahead(1, |t| t.kind == token::Eq) => { + let lhs = this.expect_lifetime(); + this.expect(exp!(Eq))?; + if !this.check_lifetime() { + this.unexpected()?; + } + let rhs = this.expect_lifetime(); + region_equalities.push(TestBinderRegionEquality { lhs, rhs }); + } _ => constraints.push(this.parse_test_binder_constraint()?), } Ok(()) })?; - Ok(TestBinderBody { foralls, exists, constraints, predicates }) + Ok(TestBinderBody { foralls, exists, region_equalities, constraints, predicates }) } pub fn parse_test_binder_forall(&mut self) -> PResult<'a, TestBinderForall> { diff --git a/compiler/rustc_type_ir/src/region_constraint.rs b/compiler/rustc_type_ir/src/region_constraint.rs index 4a6e704cb0020..6f224273df17b 100644 --- a/compiler/rustc_type_ir/src/region_constraint.rs +++ b/compiler/rustc_type_ir/src/region_constraint.rs @@ -565,6 +565,7 @@ pub fn eagerly_handle_placeholders_in_universe RegionConstraint { assert!(u > UniverseIndex::ROOT, "eagerly handle placeholders called for root universe"); + let constraint = infcx.deeply_resolve_via_unification_table(constraint); let assumptions = infcx.get_placeholder_assumptions(u); // 1. rewrite type outlives constraints involving things from `u` into either region constraints diff --git a/tests/ui/assumptions_on_binders/resolve-region-vars.rs b/tests/ui/assumptions_on_binders/resolve-region-vars.rs new file mode 100644 index 0000000000000..3543a2f810e63 --- /dev/null +++ b/tests/ui/assumptions_on_binders/resolve-region-vars.rs @@ -0,0 +1,82 @@ +//@ check-pass +//@ compile-flags: -Zassumptions-on-binders -Znext-solver=globally + +#![feature(test_binder_constraints)] + +trait Trait<'a, 'b> { + type Assoc; +} + +core::test_binder_constraints! { + impl<'c, T> + where + for<'a, 'b> T: Trait<'a, 'b>, + { + forall<'a> + where + for<'b> >::Assoc: 'c, + { + forall<'b> { + predicates >::Assoc: 'c + } expect { + for<'b> >::Assoc: 'c + } + } expect { } + } +} + +core::test_binder_constraints! { + impl<'c, T> + where + for<'a, 'b> T: Trait<'a, 'b>, + { + forall<'a> + where + for<'b> >::Assoc: 'c, + { + forall<'b> { + exists<'a2, 'b2, 'c2> { + 'a2 = 'a, + 'b2 = 'b, + 'c2 = 'c, + or { + for<> >::Assoc: 'c2, + and { T: 'c2, 'a2: 'c2, 'b2: 'c2 } + } + } + } expect { + for<'b> >::Assoc: 'c + } + } expect { } + } +} + +core::test_binder_constraints! { + impl<'c, T> + where + for<'a, 'b> T: Trait<'a, 'b>, + { + forall<'a> + where + for<'b> >::Assoc: 'c, + { + forall<'b> { + exists<'a2, 'b2, 'c2> { + exists<'a3, 'b3, 'c3> { + 'a2 = 'a3, + 'b2 = 'b3, + 'c2 = 'c3, + 'a3 = 'a, + 'b3 = 'b, + 'c3 = 'c, + for<> >::Assoc: 'c3 + } + } + } expect { + for<'b> >::Assoc: 'c + } + } expect { } + } +} + +fn main() {}