Skip to content

Commit 3dfee39

Browse files
committed
alias eq mvp
1 parent 499d492 commit 3dfee39

File tree

5 files changed

+187
-16
lines changed

5 files changed

+187
-16
lines changed

chalk-solve/src/clauses.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ mod dyn_ty;
1616
mod env_elaborator;
1717
mod generalize;
1818
pub mod program_clauses;
19+
pub mod syntactic_eq;
1920

2021
/// For auto-traits, we generate a default rule for every struct,
2122
/// unless there is a manual impl for that struct given explicitly.

chalk-solve/src/clauses/builder.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::iter;
22
use std::marker::PhantomData;
33

44
use crate::cast::{Cast, CastTo};
5+
use crate::clauses::syntactic_eq::syn_eq_lower;
56
use crate::RustIrDatabase;
67
use chalk_ir::fold::Fold;
78
use chalk_ir::interner::{HasInterner, Interner};
@@ -77,18 +78,17 @@ impl<'me, I: Interner> ClauseBuilder<'me, I> {
7778
priority,
7879
};
7980

80-
if self.binders.len() == 0 {
81-
self.clauses
82-
.push(ProgramClauseData::Implies(clause).intern(interner));
81+
let clause = if self.binders.len() == 0 {
82+
ProgramClauseData::Implies(clause).intern(interner)
8383
} else {
84-
self.clauses.push(
85-
ProgramClauseData::ForAll(Binders::new(
86-
VariableKinds::from(interner, self.binders.clone()),
87-
clause,
88-
))
89-
.intern(interner),
90-
);
91-
}
84+
ProgramClauseData::ForAll(Binders::new(
85+
VariableKinds::from(interner, self.binders.clone()),
86+
clause,
87+
))
88+
.intern(interner)
89+
};
90+
91+
self.clauses.push(syn_eq_lower(interner, &clause));
9292

9393
debug!("pushed clause {:?}", self.clauses.last());
9494
}

chalk-solve/src/clauses/program_clauses.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,7 @@ impl<I: Interner> ToProgramClauses<I> for AssociatedTyDatum<I> {
856856

857857
// add new type parameter U
858858
builder.push_bound_ty(|builder, ty| {
859+
let alias = AliasTy::Projection(projection.clone());
859860
// `Normalize(<T as Foo>::Assoc -> U)`
860861
let normalize = Normalize {
861862
alias: AliasTy::Projection(projection.clone()),
@@ -864,8 +865,8 @@ impl<I: Interner> ToProgramClauses<I> for AssociatedTyDatum<I> {
864865

865866
// `AliasEq(<T as Foo>::Assoc = U)`
866867
let projection_eq = AliasEq {
867-
alias: AliasTy::Projection(projection),
868-
ty,
868+
alias: alias.clone(),
869+
ty: ty.clone(),
869870
};
870871

871872
// Projection equality rule from above.
@@ -874,7 +875,7 @@ impl<I: Interner> ToProgramClauses<I> for AssociatedTyDatum<I> {
874875
// AliasEq(<T as Foo>::Assoc = U) :-
875876
// Normalize(<T as Foo>::Assoc -> U).
876877
// }
877-
builder.push_clause(projection_eq, Some(normalize));
878+
builder.push_clause(projection_eq.clone(), Some(normalize));
878879
});
879880
});
880881
}
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
use std::{iter, mem::replace};
2+
3+
use chalk_engine::fallible::Fallible;
4+
use chalk_ir::{
5+
cast::Cast,
6+
fold::{shift::Shift, Fold, Folder, SuperFold},
7+
interner::Interner,
8+
AliasEq, AliasTy, Binders, BoundVar, DebruijnIndex, Goal, GoalData, Goals, ProgramClause,
9+
ProgramClauseData, ProgramClauseImplication, QuantifierKind, Ty, TyData, VariableKind,
10+
VariableKinds,
11+
};
12+
13+
pub fn syn_eq_lower<I: Interner, T: Fold<I>>(interner: &I, clause: &T) -> <T as Fold<I>>::Result {
14+
let mut folder = SynEqFolder {
15+
interner,
16+
new_params: vec![],
17+
new_goals: vec![],
18+
binders_len: 0,
19+
};
20+
21+
clause
22+
.fold_with(&mut folder, DebruijnIndex::INNERMOST)
23+
.unwrap()
24+
}
25+
26+
struct SynEqFolder<'i, I: Interner> {
27+
interner: &'i I,
28+
new_params: Vec<VariableKind<I>>,
29+
new_goals: Vec<Goal<I>>,
30+
binders_len: usize,
31+
}
32+
33+
impl<'i, I: Interner> Folder<'i, I> for SynEqFolder<'i, I> {
34+
fn as_dyn(&mut self) -> &mut dyn Folder<'i, I> {
35+
self
36+
}
37+
38+
fn fold_ty(&mut self, ty: &Ty<I>, outer_binder: DebruijnIndex) -> Fallible<Ty<I>> {
39+
let interner = self.interner;
40+
let bound_var = BoundVar::new(DebruijnIndex::INNERMOST, self.binders_len);
41+
42+
let new_ty = TyData::BoundVar(bound_var).intern(interner);
43+
match ty.data(interner) {
44+
TyData::Alias(alias @ AliasTy::Projection(_)) => {
45+
self.new_params.push(VariableKind::Ty);
46+
self.new_goals.push(
47+
AliasEq {
48+
alias: alias.clone(),
49+
ty: new_ty.clone(),
50+
}
51+
.cast(interner),
52+
);
53+
self.binders_len += 1;
54+
ty.super_fold_with(self, outer_binder)?;
55+
Ok(new_ty)
56+
}
57+
TyData::Function(_) => Ok(ty.clone()),
58+
_ => Ok(ty.super_fold_with(self, outer_binder)?),
59+
}
60+
}
61+
62+
fn fold_program_clause(
63+
&mut self,
64+
clause: &ProgramClause<I>,
65+
outer_binder: DebruijnIndex,
66+
) -> Fallible<ProgramClause<I>> {
67+
let interner = self.interner;
68+
69+
let ((binders, implication), in_binders) = match clause.data(interner) {
70+
ProgramClauseData::ForAll(for_all) => (for_all.clone().into(), true),
71+
// introduce a dummy binder and shift implication through it
72+
ProgramClauseData::Implies(implication) => (
73+
(
74+
VariableKinds::new(interner),
75+
implication.shifted_in(interner),
76+
),
77+
false,
78+
),
79+
};
80+
let mut binders: Vec<_> = binders.as_slice(interner).clone().into();
81+
82+
let outer_binder = outer_binder.shifted_in();
83+
84+
self.binders_len = binders.len();
85+
let consequence = implication.consequence.fold_with(self, outer_binder)?;
86+
// Immediately move `new_params` out of of the folder struct so it's safe
87+
// to call `.fold_with` again
88+
let new_params = replace(&mut self.new_params, vec![]);
89+
let new_goals = replace(&mut self.new_goals, vec![]);
90+
91+
let mut conditions = implication.conditions.fold_with(self, outer_binder)?;
92+
if new_params.is_empty() && !in_binders {
93+
// shift the clause out since we didn't use the dummy binder
94+
return Ok(ProgramClauseData::Implies(
95+
ProgramClauseImplication {
96+
consequence,
97+
conditions,
98+
priority: implication.priority,
99+
}
100+
.shifted_out(interner)?,
101+
)
102+
.intern(interner));
103+
}
104+
105+
binders.extend(new_params.into_iter());
106+
107+
conditions = Goals::from(
108+
interner,
109+
conditions.iter(interner).cloned().chain(new_goals),
110+
);
111+
112+
Ok(ProgramClauseData::ForAll(Binders::new(
113+
VariableKinds::from(interner, binders),
114+
ProgramClauseImplication {
115+
consequence,
116+
conditions,
117+
priority: implication.priority,
118+
},
119+
))
120+
.intern(interner))
121+
}
122+
123+
fn fold_goal(&mut self, goal: &Goal<I>, outer_binder: DebruijnIndex) -> Fallible<Goal<I>> {
124+
assert!(self.new_params.is_empty(), true);
125+
126+
let interner = self.interner;
127+
match goal.data(interner) {
128+
GoalData::DomainGoal(_) | GoalData::EqGoal(_) => (),
129+
_ => return goal.super_fold_with(self, outer_binder),
130+
};
131+
132+
self.binders_len = 0;
133+
// shifted in because we introduce a new binder
134+
let outer_binder = outer_binder.shifted_in();
135+
let syn_goal = goal
136+
.shifted_in(interner)
137+
.super_fold_with(self, outer_binder)?;
138+
let new_params = replace(&mut self.new_params, vec![]);
139+
let new_goals = replace(&mut self.new_goals, vec![]);
140+
141+
if new_params.is_empty() {
142+
return Ok(goal.clone());
143+
}
144+
145+
let goal = GoalData::All(Goals::from(
146+
interner,
147+
iter::once(syn_goal).into_iter().chain(new_goals),
148+
))
149+
.intern(interner);
150+
151+
Ok(GoalData::Quantified(
152+
QuantifierKind::Exists,
153+
Binders::new(VariableKinds::from(interner, new_params), goal),
154+
)
155+
.intern(interner))
156+
}
157+
158+
fn interner(&self) -> &'i I {
159+
self.interner
160+
}
161+
162+
fn target_interner(&self) -> &'i I {
163+
self.interner
164+
}
165+
}

chalk-solve/src/ext.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::clauses::syntactic_eq::syn_eq_lower;
12
use crate::infer::InferenceTable;
23
use chalk_ir::fold::Fold;
34
use chalk_ir::interner::{HasInterner, Interner};
@@ -89,7 +90,9 @@ impl<I: Interner> GoalExt<I> for Goal<I> {
8990
}
9091
}
9192
};
92-
let canonical = infer.canonicalize(interner, &peeled_goal).quantified;
93+
let canonical = infer
94+
.canonicalize(interner, &syn_eq_lower(interner, &peeled_goal))
95+
.quantified;
9396
infer.u_canonicalize(interner, &canonical).quantified
9497
}
9598

@@ -104,7 +107,8 @@ impl<I: Interner> GoalExt<I> for Goal<I> {
104107
/// Will panic if this goal does in fact contain free variables.
105108
fn into_closed_goal(self, interner: &I) -> UCanonical<InEnvironment<Goal<I>>> {
106109
let mut infer = InferenceTable::new();
107-
let env_goal = InEnvironment::new(&Environment::new(interner), self);
110+
let lowered_goal = syn_eq_lower(interner, &self);
111+
let env_goal = InEnvironment::new(&Environment::new(interner), &lowered_goal);
108112
let canonical_goal = infer.canonicalize(interner, &env_goal).quantified;
109113
infer.u_canonicalize(interner, &canonical_goal).quantified
110114
}

0 commit comments

Comments
 (0)