Skip to content

Commit 031768f

Browse files
basil-cownathanwhit
authored andcommitted
alias eq mvp
1 parent 70e77f1 commit 031768f

File tree

5 files changed

+178
-12
lines changed

5 files changed

+178
-12
lines changed

chalk-solve/src/clauses.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ mod dyn_ty;
1818
mod env_elaborator;
1919
mod generalize;
2020
pub mod program_clauses;
21+
pub mod syntactic_eq;
2122

2223
// yields the types "contained" in `app_ty`
2324
fn constituent_types<I: Interner>(db: &dyn RustIrDatabase<I>, ty: &TyKind<I>) -> Vec<Ty<I>> {

chalk-solve/src/clauses/builder.rs

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

33
use crate::cast::{Cast, CastTo};
4+
use crate::clauses::syntactic_eq::syn_eq_lower;
45
use crate::RustIrDatabase;
56
use chalk_ir::fold::{Fold, Shift};
67
use chalk_ir::interner::{HasInterner, Interner};
@@ -95,14 +96,13 @@ impl<'me, I: Interner> ClauseBuilder<'me, I> {
9596
} else {
9697
clause
9798
};
99+
let clause = ProgramClauseData(Binders::new(
100+
VariableKinds::from_iter(interner, self.binders.clone()),
101+
clause,
102+
))
103+
.intern(interner);
98104

99-
self.clauses.push(
100-
ProgramClauseData(Binders::new(
101-
VariableKinds::from_iter(interner, self.binders.clone()),
102-
clause,
103-
))
104-
.intern(interner),
105-
);
105+
self.clauses.push(syn_eq_lower(interner, &clause));
106106

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

chalk-solve/src/clauses/program_clauses.rs

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

870870
// add new type parameter U
871871
builder.push_bound_ty(|builder, ty| {
872+
let alias = AliasTy::Projection(projection.clone());
872873
// `Normalize(<T as Foo>::Assoc -> U)`
873874
let normalize = Normalize {
874875
alias: AliasTy::Projection(projection.clone()),
@@ -877,8 +878,8 @@ impl<I: Interner> ToProgramClauses<I> for AssociatedTyDatum<I> {
877878

878879
// `AliasEq(<T as Foo>::Assoc = U)`
879880
let projection_eq = AliasEq {
880-
alias: AliasTy::Projection(projection),
881-
ty,
881+
alias: alias.clone(),
882+
ty: ty.clone(),
882883
};
883884

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

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)