Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4075,11 +4075,20 @@ pub struct TestBinderConstraints {
pub struct TestBinderBody {
pub foralls: ThinVec<TestBinderForall>,
pub exists: ThinVec<TestBinderExists>,
pub region_equalities: Vec<TestBinderRegionEquality>,
pub constraints: Vec<TestBinderConstraint>,
/// These are not where clauses, but rather predicates within the body to be proven
pub predicates: Vec<WherePredicate>,
}

#[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,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,7 @@ macro_rules! common_visitor_and_walkers {
StructExpr,
StructRest,
Term,
TestBinderRegionEquality,
Trait,
TraitBoundModifiers,
TraitObjectSyntax,
Expand Down
9 changes: 8 additions & 1 deletion compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1998,14 +1998,21 @@ 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(
body.predicates
.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(
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
11 changes: 10 additions & 1 deletion compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -2776,6 +2784,7 @@ struct RedundantLifetimeArgsLint<'tcx> {
pub(crate) struct TestBinderBody<'tcx> {
pub foralls: Vec<TestBinderForall<'tcx>>,
pub exists: Vec<TestBinderExists<'tcx>>,
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`
Expand Down
14 changes: 12 additions & 2 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
12 changes: 11 additions & 1 deletion compiler/rustc_parse/src/parser/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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| {
Expand All @@ -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> {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_type_ir/src/region_constraint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,7 @@ pub fn eagerly_handle_placeholders_in_universe<Infcx: InferCtxtLike<Interner = I
) -> RegionConstraint<I> {
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
Expand Down
82 changes: 82 additions & 0 deletions tests/ui/assumptions_on_binders/resolve-region-vars.rs
Original file line number Diff line number Diff line change
@@ -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> <T as Trait<'a, 'b>>::Assoc: 'c,
{
forall<'b> {
predicates <T as Trait<'a, 'b>>::Assoc: 'c
} expect {
for<'b> <T as Trait<'a, 'b>>::Assoc: 'c
}
} expect { }
}
}

core::test_binder_constraints! {
impl<'c, T>
where
for<'a, 'b> T: Trait<'a, 'b>,
{
forall<'a>
where
for<'b> <T as Trait<'a, 'b>>::Assoc: 'c,
{
forall<'b> {
exists<'a2, 'b2, 'c2> {
'a2 = 'a,
'b2 = 'b,
'c2 = 'c,
or {
for<> <T as Trait<'a2, 'b2>>::Assoc: 'c2,
and { T: 'c2, 'a2: 'c2, 'b2: 'c2 }
}
}
} expect {
for<'b> <T as Trait<'a, 'b>>::Assoc: 'c
}
} expect { }
}
}

core::test_binder_constraints! {
impl<'c, T>
where
for<'a, 'b> T: Trait<'a, 'b>,
{
forall<'a>
where
for<'b> <T as Trait<'a, '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<> <T as Trait<'a3, 'b3>>::Assoc: 'c3
}
}
} expect {
for<'b> <T as Trait<'a, 'b>>::Assoc: 'c
}
} expect { }
}
}

fn main() {}
Loading