Skip to content

Commit 2c0c785

Browse files
committed
always introduce binders, even if they are empty
If we are counting binding levels, then this is important to keep the debruijn indices from getting out of whack. In other words, `for ^1.0` is very different from `^1.0`.
1 parent 57b15d4 commit 2c0c785

File tree

4 files changed

+40
-33
lines changed

4 files changed

+40
-33
lines changed

chalk-integration/src/lowering.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,11 +1196,7 @@ impl LowerClause for Clause {
11961196
.into_iter()
11971197
.map(
11981198
|implication: chalk_ir::Binders<chalk_ir::ProgramClauseImplication<ChalkIr>>| {
1199-
if implication.binders.is_empty() {
1200-
chalk_ir::ProgramClause::Implies(implication.value)
1201-
} else {
1202-
chalk_ir::ProgramClause::ForAll(implication)
1203-
}
1199+
chalk_ir::ProgramClause::ForAll(implication)
12041200
},
12051201
)
12061202
.collect();

chalk-ir/src/cast.rs

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -138,15 +138,11 @@ impl<I: Interner> CastTo<Goal<I>> for EqGoal<I> {
138138

139139
impl<T: CastTo<Goal<I>>, I: Interner> CastTo<Goal<I>> for Binders<T> {
140140
fn cast_to(self, interner: &I) -> Goal<I> {
141-
if self.binders.is_empty() {
142-
self.value.cast(interner)
143-
} else {
144-
GoalData::Quantified(
145-
QuantifierKind::ForAll,
146-
self.map(|bound| bound.cast(interner)),
147-
)
148-
.intern(interner)
149-
}
141+
GoalData::Quantified(
142+
QuantifierKind::ForAll,
143+
self.map(|bound| bound.cast(interner)),
144+
)
145+
.intern(interner)
150146
}
151147
}
152148

@@ -199,14 +195,10 @@ where
199195
I: Interner,
200196
{
201197
fn cast_to(self, interner: &I) -> ProgramClause<I> {
202-
if self.binders.is_empty() {
203-
self.value.cast::<ProgramClause<I>>(interner)
204-
} else {
205-
ProgramClause::ForAll(self.map(|bound| ProgramClauseImplication {
206-
consequence: bound.cast(interner),
207-
conditions: Goals::new(interner),
208-
}))
209-
}
198+
ProgramClause::ForAll(self.map(|bound| ProgramClauseImplication {
199+
consequence: bound.cast(interner),
200+
conditions: Goals::new(interner),
201+
}))
210202
}
211203
}
212204

chalk-ir/src/debug.rs

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -308,19 +308,24 @@ impl<T: Debug> Debug for Binders<T> {
308308
ref binders,
309309
ref value,
310310
} = *self;
311-
if !binders.is_empty() {
312-
write!(fmt, "for<")?;
313-
for (index, binder) in binders.iter().enumerate() {
314-
if index > 0 {
315-
write!(fmt, ", ")?;
316-
}
317-
match *binder {
318-
ParameterKind::Ty(()) => write!(fmt, "type")?,
319-
ParameterKind::Lifetime(()) => write!(fmt, "lifetime")?,
320-
}
311+
312+
// NB: We always print the `for<>`, even if it is empty,
313+
// because it may affect the debruijn indices of things
314+
// contained within. For example, `for<> { ^1.0 }` is very
315+
// different from `^1.0` in terms of what variable is being
316+
// referenced.
317+
318+
write!(fmt, "for<")?;
319+
for (index, binder) in binders.iter().enumerate() {
320+
if index > 0 {
321+
write!(fmt, ", ")?;
322+
}
323+
match *binder {
324+
ParameterKind::Ty(()) => write!(fmt, "type")?,
325+
ParameterKind::Lifetime(()) => write!(fmt, "lifetime")?,
321326
}
322-
write!(fmt, "> ")?;
323327
}
328+
write!(fmt, "> ")?;
324329
Debug::fmt(value, fmt)
325330
}
326331
}
@@ -345,6 +350,12 @@ impl<T: Display> Display for Canonical<T> {
345350
let Canonical { binders, value } = self;
346351

347352
if binders.is_empty() {
353+
// Ordinarily, we try to print all binder levels, if they
354+
// are empty, but we can skip in this *particular* case
355+
// because we know that `Canonical` terms are never
356+
// supposed to contain free variables. In other words,
357+
// all "bound variables" that appear inside the canonical
358+
// value must reference values that appear in `binders`.
348359
write!(f, "{}", value)?;
349360
} else {
350361
write!(f, "for<")?;

chalk-solve/src/clauses/env_elaborator.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,14 @@ impl<'me, I: Interner> EnvElaborator<'me, I> {
4444
}
4545

4646
fn visit_alias_ty(&mut self, alias_ty: &AliasTy<I>) {
47+
debug!("EnvElaborator::visit_alias_ty(alias_ty={:?})", alias_ty);
4748
self.db
4849
.associated_ty_data(alias_ty.associated_ty_id)
4950
.to_program_clauses(&mut self.builder);
5051
}
5152

5253
fn visit_ty(&mut self, ty: &Ty<I>) {
54+
debug!("EnvElaborator::visit_ty(ty={:?})", ty);
5355
let interner = self.db.interner();
5456
match ty.data(interner) {
5557
TyData::Apply(application_ty) => {
@@ -70,6 +72,7 @@ impl<'me, I: Interner> EnvElaborator<'me, I> {
7072
}
7173

7274
fn visit_from_env(&mut self, from_env: &FromEnv<I>) {
75+
debug!("EnvElaborator::visit_from_env(from_env={:?})", from_env);
7376
match from_env {
7477
FromEnv::Trait(trait_ref) => {
7578
let trait_datum = self.db.trait_datum(trait_ref.trait_id);
@@ -90,13 +93,18 @@ impl<'me, I: Interner> EnvElaborator<'me, I> {
9093
}
9194

9295
fn visit_domain_goal(&mut self, domain_goal: &DomainGoal<I>) {
96+
debug!(
97+
"EnvElaborator::visit_domain_goal(domain_goal={:?})",
98+
domain_goal
99+
);
93100
match domain_goal {
94101
DomainGoal::FromEnv(from_env) => self.visit_from_env(from_env),
95102
_ => {}
96103
}
97104
}
98105

99106
fn visit_program_clause(&mut self, clause: &ProgramClause<I>) {
107+
debug!("visit_program_clause(clause={:?})", clause);
100108
match clause {
101109
ProgramClause::Implies(clause) => self.visit_domain_goal(&clause.consequence),
102110
ProgramClause::ForAll(clause) => self.visit_domain_goal(&clause.value.consequence),

0 commit comments

Comments
 (0)