Skip to content

Commit 444f6e1

Browse files
scalexmnikomatsakis
authored andcommitted
Elaborate where clauses in Implies goals
1 parent bafd6f3 commit 444f6e1

File tree

6 files changed

+87
-18
lines changed

6 files changed

+87
-18
lines changed

chalk-parse/src/ast.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,10 @@ pub struct Field {
162162
pub enum Goal {
163163
ForAll(Vec<ParameterKind>, Box<Goal>),
164164
Exists(Vec<ParameterKind>, Box<Goal>),
165-
Implies(Vec<WhereClause>, Box<Goal>),
165+
166+
// The `bool` flag indicates whether we should elaborate where clauses or not
167+
Implies(Vec<WhereClause>, Box<Goal>, bool),
168+
166169
And(Box<Goal>, Box<Goal>),
167170
Not(Box<Goal>),
168171

chalk-parse/src/parser.lalrpop

+2-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ pub Goal: Box<Goal> = {
2828
Goal1: Box<Goal> = {
2929
"forall" "<" <p:Comma<ParameterKind>> ">" "{" <g:Goal> "}" => Box::new(Goal::ForAll(p, g)),
3030
"exists" "<" <p:Comma<ParameterKind>> ">" "{" <g:Goal> "}" => Box::new(Goal::Exists(p, g)),
31-
"if" "(" <w:Comma<WhereClause>> ")" "{" <g:Goal> "}" => Box::new(Goal::Implies(w, g)),
31+
"if" "(" <w:Comma<WhereClause>> ")" "{" <g:Goal> "}" => Box::new(Goal::Implies(w, g, true)),
32+
"if_raw" "(" <w:Comma<WhereClause>> ")" "{" <g:Goal> "}" => Box::new(Goal::Implies(w, g, false)),
3233
"not" "{" <g:Goal> "}" => Box::new(Goal::Not(g)),
3334
<w:WhereClause> => Box::new(Goal::Leaf(w)),
3435
};

src/cast.rs

+32-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use ir::*;
2+
use std::marker::PhantomData;
23

34
pub trait Cast<T>: Sized {
45
fn cast(self) -> T;
@@ -130,7 +131,7 @@ impl<T, U> Cast<Vec<U>> for Vec<T>
130131
where T: Cast<U>
131132
{
132133
fn cast(self) -> Vec<U> {
133-
self.into_iter().map(|v| v.cast()).collect()
134+
self.into_iter().casted().collect()
134135
}
135136
}
136137

@@ -145,3 +146,33 @@ impl Cast<Parameter> for Lifetime {
145146
ParameterKind::Lifetime(self)
146147
}
147148
}
149+
150+
pub struct Casted<I, U> {
151+
iterator: I,
152+
_cast: PhantomData<U>,
153+
}
154+
155+
impl<I: Iterator, U> Iterator for Casted<I, U> where I::Item: Cast<U> {
156+
type Item = U;
157+
158+
fn next(&mut self) -> Option<Self::Item> {
159+
self.iterator.next().map(|item| item.cast())
160+
}
161+
162+
fn size_hint(&self) -> (usize, Option<usize>) {
163+
self.iterator.size_hint()
164+
}
165+
}
166+
167+
pub trait Caster<U>: Sized {
168+
fn casted(self) -> Casted<Self, U>;
169+
}
170+
171+
impl<I: Iterator, U> Caster<U> for I {
172+
fn casted(self) -> Casted<Self, U> {
173+
Casted {
174+
iterator: self,
175+
_cast: PhantomData,
176+
}
177+
}
178+
}

src/ir/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,9 @@ pub struct AssociatedTyDatum {
225225
/// Parameters on this associated type, beginning with those from the trait,
226226
/// but possibly including more.
227227
pub parameter_kinds: Vec<ParameterKind<Identifier>>,
228+
229+
/// Where clauses that must hold for the projection be well-formed.
230+
pub where_clauses: Vec<DomainGoal>,
228231
}
229232

230233
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
@@ -367,7 +370,7 @@ impl DomainGoal {
367370
}
368371

369372
/// A clause of the form (T: Foo) expands to (T: Foo), WF(T: Foo).
370-
/// A clause of the form (T: Foo<Item = U>) expands to (T: Foo<Item = U>), (T: Foo), WF(T: Foo).
373+
/// A clause of the form (T: Foo<Item = U>) expands to (T: Foo<Item = U>), WF(T: Foo).
371374
pub fn expanded(self, program: &Program) -> impl Iterator<Item = DomainGoal> {
372375
let mut expanded = vec![];
373376
match self {
@@ -380,7 +383,6 @@ impl DomainGoal {
380383
trait_id: associated_ty_data.trait_id,
381384
parameters: trait_params.to_owned()
382385
};
383-
expanded.push(trait_ref.clone().cast());
384386
expanded.push(WellFormed::TraitRef(trait_ref).cast());
385387
}
386388
_ => ()

src/lower/mod.rs

+22-8
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::collections::HashMap;
33
use chalk_parse::ast::*;
44
use lalrpop_intern::intern;
55

6-
use cast::Cast;
6+
use cast::{Cast, Caster};
77
use errors::*;
88
use ir;
99

@@ -167,6 +167,7 @@ impl LowerProgram for Program {
167167
id: info.id,
168168
name: defn.name.str,
169169
parameter_kinds: parameter_kinds,
170+
where_clauses: vec![],
170171
});
171172
}
172173
}
@@ -725,8 +726,19 @@ impl<'k> LowerGoal<Env<'k>> for Goal {
725726
g.lower_quantified(env, ir::QuantifierKind::ForAll, ids),
726727
Goal::Exists(ref ids, ref g) =>
727728
g.lower_quantified(env, ir::QuantifierKind::Exists, ids),
728-
Goal::Implies(ref wc, ref g) =>
729-
Ok(Box::new(ir::Goal::Implies(wc.lower(env)?, g.lower(env)?))),
729+
Goal::Implies(ref wc, ref g, elaborate) => {
730+
let mut where_clauses = wc.lower(env)?;
731+
if elaborate {
732+
where_clauses = ir::with_current_program(|program| {
733+
let program = program.expect("cannot elaborate without a program");
734+
where_clauses.into_iter()
735+
.flat_map(|wc| wc.expanded(program))
736+
.casted()
737+
.collect()
738+
});
739+
}
740+
Ok(Box::new(ir::Goal::Implies(where_clauses, g.lower(env)?)))
741+
}
730742
Goal::And(ref g1, ref g2) =>
731743
Ok(Box::new(ir::Goal::And(g1.lower(env)?, g2.lower(env)?))),
732744
Goal::Not(ref g) =>
@@ -803,7 +815,7 @@ impl ir::ImplDatum {
803815
.iter()
804816
.cloned()
805817
.flat_map(|wc| wc.expanded(program))
806-
.map(|wc| wc.cast())
818+
.casted()
807819
.collect(),
808820
}
809821
}),
@@ -935,12 +947,13 @@ impl ir::StructDatum {
935947
.iter()
936948
.filter_map(|pk| pk.as_ref().ty())
937949
.cloned()
938-
.map(|ty| ir::WellFormed::Ty(ty).cast());
950+
.map(|ty| ir::WellFormed::Ty(ty))
951+
.casted();
939952

940953
let where_clauses = bound_datum.where_clauses.iter()
941954
.cloned()
942955
.flat_map(|wc| wc.expanded(program))
943-
.map(|wc| wc.cast());
956+
.casted();
944957

945958
tys.chain(where_clauses).collect()
946959
}
@@ -987,9 +1000,10 @@ impl ir::TraitDatum {
9871000
.iter()
9881001
.filter_map(|pk| pk.as_ref().ty())
9891002
.cloned()
990-
.map(|ty| ir::WellFormed::Ty(ty).cast());
1003+
.map(|ty| ir::WellFormed::Ty(ty))
1004+
.casted();
9911005

992-
tys.chain(where_clauses.iter().cloned().map(|wc| wc.cast())).collect()
1006+
tys.chain(where_clauses.iter().cloned().casted()).collect()
9931007
}
9941008
}
9951009
}),

src/solve/test.rs

+23-5
Original file line numberDiff line numberDiff line change
@@ -175,13 +175,23 @@ fn prove_forall() {
175175
// Here, we do know that `T: Clone`, so we can.
176176
goal {
177177
forall<T> {
178-
if (WellFormed(T: Clone), T: Clone) {
178+
if (T: Clone) {
179179
Vec<T>: Clone
180180
}
181181
}
182182
} yields {
183183
"Unique; substitution [], lifetime constraints []"
184184
}
185+
186+
goal {
187+
forall<T> {
188+
if_raw (T: Clone) {
189+
Vec<T>: Clone
190+
}
191+
}
192+
} yields {
193+
"CannotProve"
194+
}
185195
}
186196
}
187197

@@ -546,7 +556,7 @@ fn elaborate_eq() {
546556

547557
goal {
548558
forall<T> {
549-
if (WellFormed(T: Eq)) {
559+
if (T: Eq) {
550560
T: PartialEq
551561
}
552562
}
@@ -567,7 +577,7 @@ fn elaborate_transitive() {
567577

568578
goal {
569579
forall<T> {
570-
if (WellFormed(T: StrictEq)) {
580+
if (T: StrictEq) {
571581
T: PartialEq
572582
}
573583
}
@@ -596,7 +606,7 @@ fn elaborate_normalize() {
596606

597607
goal {
598608
forall<T, U> {
599-
if (WellFormed(T: Item), T: Item<Out = U>) {
609+
if (T: Item<Out = U>) {
600610
U: Eq
601611
}
602612
}
@@ -753,6 +763,8 @@ fn trait_wf() {
753763

754764
impl Ord<Int> for Int { }
755765
impl<T> Ord<Vec<T>> for Vec<T> where T: Ord<T> { }
766+
767+
impl<T> Ord<Slice<T>> for Slice<T> { }
756768
}
757769

758770
goal {
@@ -779,13 +791,19 @@ fn trait_wf() {
779791
"Unique; substitution [], lifetime constraints []"
780792
}
781793

794+
goal {
795+
Slice<Int>: Ord<Slice<Int>>
796+
} yields {
797+
"Unique"
798+
}
799+
782800
goal {
783801
Slice<Int>: Eq<Slice<Int>>
784802
} yields {
785803
"No possible solution"
786804
}
787805

788-
// not WF because previous equation doesn't hold
806+
// not WF because previous equation doesn't hold, despite Slice<Int> having an impl for Ord<Int>
789807
goal {
790808
WellFormed(Slice<Int>: Ord<Slice<Int>>)
791809
} yields {

0 commit comments

Comments
 (0)