Skip to content

Commit 4f007d9

Browse files
authored
Merge pull request #82 from scalexm/implied-bounds-ok
Implied bounds, second take
2 parents 4defa33 + 249bd61 commit 4f007d9

File tree

16 files changed

+888
-401
lines changed

16 files changed

+888
-401
lines changed

chalk-parse/src/ast.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ pub enum WhereClause {
181181
ProjectionEq { projection: ProjectionTy, ty: Ty },
182182
TyWellFormed { ty: Ty },
183183
TraitRefWellFormed { trait_ref: TraitRef },
184+
TyFromEnv { ty: Ty },
185+
TraitRefFromEnv { trait_ref: TraitRef },
184186
UnifyTys { a: Ty, b: Ty },
185187
UnifyLifetimes { a: Lifetime, b: Lifetime },
186188
TraitInScope { trait_name: Identifier },
@@ -202,10 +204,7 @@ pub struct Clause {
202204
pub enum Goal {
203205
ForAll(Vec<ParameterKind>, Box<Goal>),
204206
Exists(Vec<ParameterKind>, Box<Goal>),
205-
206-
// The `bool` flag indicates whether we should elaborate where clauses or not
207-
Implies(Vec<WhereClause>, Box<Goal>, bool),
208-
207+
Implies(Vec<WhereClause>, Box<Goal>),
209208
And(Box<Goal>, Box<Goal>),
210209
Not(Box<Goal>),
211210

chalk-parse/src/parser.lalrpop

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,12 @@ pub Goal: Box<Goal> = {
2929
Goal1: Box<Goal> = {
3030
"forall" "<" <p:Comma<ParameterKind>> ">" "{" <g:Goal> "}" => Box::new(Goal::ForAll(p, g)),
3131
"exists" "<" <p:Comma<ParameterKind>> ">" "{" <g:Goal> "}" => Box::new(Goal::Exists(p, g)),
32-
<i:IfKeyword> "(" <w:Comma<WhereClause>> ")" "{" <g:Goal> "}" => Box::new(Goal::Implies(w, g, i)),
32+
"if" "(" <w:Comma<WhereClause>> ")" "{" <g:Goal> "}" => Box::new(Goal::Implies(w, g)),
3333
"not" "{" <g:Goal> "}" => Box::new(Goal::Not(g)),
3434
<w:WhereClause> => Box::new(Goal::Leaf(w)),
3535
"(" <Goal> ")",
3636
};
3737

38-
IfKeyword: bool = {
39-
"if" => true,
40-
"if_raw" => false,
41-
};
42-
4338
StructDefn: StructDefn = {
4439
"struct" <n:Id><p:Angle<ParameterKind>> <w:WhereClauses> "{" <f:Fields> "}" => StructDefn {
4540
name: n,
@@ -187,9 +182,11 @@ WhereClause: WhereClause = {
187182

188183
"WellFormed" "(" <t:Ty> ")" => WhereClause::TyWellFormed { ty: t },
189184

190-
"WellFormed" "(" <t:TraitRef<":">> ")" => WhereClause::TraitRefWellFormed {
191-
trait_ref: t
192-
},
185+
"WellFormed" "(" <t:TraitRef<":">> ")" => WhereClause::TraitRefWellFormed { trait_ref: t },
186+
187+
"FromEnv" "(" <t:Ty> ")" => WhereClause::TyFromEnv { ty: t },
188+
189+
"FromEnv" "(" <t:TraitRef<":">> ")" => WhereClause::TraitRefFromEnv { trait_ref: t },
193190

194191
<a:Ty> "=" <b:Ty> => WhereClause::UnifyTys { a, b },
195192

src/cast.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,32 @@ impl Cast<LeafGoal> for WellFormed {
111111
}
112112
}
113113

114+
impl Cast<DomainGoal> for FromEnv {
115+
fn cast(self) -> DomainGoal {
116+
DomainGoal::FromEnv(self)
117+
}
118+
}
119+
120+
impl Cast<LeafGoal> for FromEnv {
121+
fn cast(self) -> LeafGoal {
122+
LeafGoal::DomainGoal(self.cast())
123+
}
124+
}
125+
114126
impl Cast<Goal> for WellFormed {
115127
fn cast(self) -> Goal {
116128
let wcg: LeafGoal = self.cast();
117129
wcg.cast()
118130
}
119131
}
120132

133+
impl Cast<Goal> for FromEnv {
134+
fn cast(self) -> Goal {
135+
let wcg: LeafGoal = self.cast();
136+
wcg.cast()
137+
}
138+
}
139+
121140
impl Cast<Goal> for Normalize {
122141
fn cast(self) -> Goal {
123142
let wcg: LeafGoal = self.cast();

src/errors.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,16 @@ error_chain! {
3434
display("overlapping impls of trait {:?}", trait_id)
3535
}
3636

37+
IllFormedTypeDecl(ty_id: ir::Identifier) {
38+
description("ill-formed type declaration")
39+
display("type declaration {:?} does not meet well-formedness requirements", ty_id)
40+
}
41+
42+
IllFormedTraitImpl(trait_id: ir::Identifier) {
43+
description("ill-formed trait impl")
44+
display("trait impl for {:?} does not meet well-formedness requirements", trait_id)
45+
}
46+
3747
CouldNotMatch {
3848
description("could not match")
3949
display("could not match")

src/fold/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -404,8 +404,9 @@ macro_rules! enum_fold {
404404

405405
enum_fold!(PolarizedTraitRef[] { Positive(a), Negative(a) });
406406
enum_fold!(ParameterKind[T,L] { Ty(a), Lifetime(a) } where T: Fold, L: Fold);
407-
enum_fold!(DomainGoal[] { Implemented(a), ProjectionEq(a), Normalize(a), UnselectedNormalize(a), WellFormed(a), InScope(a) });
408-
enum_fold!(WellFormed[] { Ty(a), TraitRef(a) });
407+
enum_fold!(DomainGoal[] { Implemented(a), ProjectionEq(a), Normalize(a), UnselectedNormalize(a), WellFormed(a), FromEnv(a), InScope(a) });
408+
enum_fold!(WellFormed[] { Ty(a), TraitRef(a), ProjectionEq(a) });
409+
enum_fold!(FromEnv[] { Ty(a), TraitRef(a), ProjectionEq(a) });
409410
enum_fold!(LeafGoal[] { EqGoal(a), DomainGoal(a) });
410411
enum_fold!(Constraint[] { LifetimeEq(a, b) });
411412
enum_fold!(Goal[] { Quantified(qkind, subgoal), Implies(wc, subgoal), And(g1, g2), Not(g), Leaf(wc),

src/ir/could_match.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,7 @@ impl<T: Zip> CouldMatch<T> for T {
1717
fn zip_tys(&mut self, a: &Ty, b: &Ty) -> Fallible<()> {
1818
let could_match = match (a, b) {
1919
(&Ty::Apply(ref a), &Ty::Apply(ref b)) => {
20-
let names_could_match = match (a.name, b.name) {
21-
(TypeName::ItemId(item_a), TypeName::ItemId(item_b)) => {
22-
item_a == item_b
23-
}
24-
_ => true,
25-
};
20+
let names_could_match = a.name == b.name;
2621

2722
names_could_match
2823
&& a.parameters

src/ir/debug.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ impl Debug for DomainGoal {
182182
Angle(&n.parameters[1..])
183183
),
184184
DomainGoal::WellFormed(ref n) => write!(fmt, "{:?}", n),
185+
DomainGoal::FromEnv(ref n) => write!(fmt, "{:?}", n),
185186
DomainGoal::InScope(ref n) => write!(fmt, "InScope({:?})", n),
186187
}
187188
}
@@ -201,11 +202,23 @@ impl Debug for WellFormed {
201202
let value: &Debug = match *self {
202203
WellFormed::Ty(ref t) => t,
203204
WellFormed::TraitRef(ref t) => t,
205+
WellFormed::ProjectionEq(ref t) => t,
204206
};
205207
write!(fmt, "WellFormed({:?})", value)
206208
}
207209
}
208210

211+
impl Debug for FromEnv {
212+
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
213+
let value: &Debug = match *self {
214+
FromEnv::Ty(ref t) => t,
215+
FromEnv::TraitRef(ref t) => t,
216+
FromEnv::ProjectionEq(ref t) => t,
217+
};
218+
write!(fmt, "FromEnv({:?})", value)
219+
}
220+
}
221+
209222
impl Debug for EqGoal {
210223
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
211224
write!(fmt, "({:?} = {:?})", self.a, self.b)

src/ir/mod.rs

Lines changed: 71 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use cast::Cast;
21
use chalk_parse::ast;
32
use fallible::*;
43
use fold::{DefaultTypeFolder, ExistentialFolder, Fold, IdentityUniversalFolder};
@@ -297,6 +296,13 @@ impl Ty {
297296
_ => panic!("{:?} is not a projection", self),
298297
}
299298
}
299+
300+
pub fn is_projection(&self) -> bool {
301+
match *self {
302+
Ty::Projection(..) | Ty::UnselectedProjection(..) => true,
303+
_ => false,
304+
}
305+
}
300306
}
301307

302308
/// for<'a...'z> X -- all binders are instantiated at once,
@@ -444,6 +450,7 @@ pub enum DomainGoal {
444450
Normalize(Normalize),
445451
UnselectedNormalize(UnselectedNormalize),
446452
WellFormed(WellFormed),
453+
FromEnv(FromEnv),
447454
InScope(ItemId),
448455
}
449456

@@ -462,27 +469,25 @@ impl DomainGoal {
462469
}
463470
}
464471

465-
/// A clause of the form (T: Foo) expands to (T: Foo), WF(T: Foo).
466-
/// A clause of the form (T: Foo<Item = U>) expands to (T: Foo<Item = U>), T: Foo, WF(T: Foo).
467-
crate fn expanded(self, program: &Program) -> impl Iterator<Item = DomainGoal> {
468-
let mut expanded = vec![];
472+
/// Turn a where clause into the WF version of it i.e.:
473+
/// * `T: Trait` maps to `WellFormed(T: Trait)`
474+
/// * `T: Trait<Item = Foo>` maps to `WellFormed(T: Trait<Item = Foo>)`
475+
/// * any other clause maps to itself
476+
crate fn into_well_formed_clause(self) -> DomainGoal {
469477
match self {
470-
DomainGoal::Implemented(ref trait_ref) => {
471-
expanded.push(WellFormed::TraitRef(trait_ref.clone()).cast())
472-
}
473-
DomainGoal::ProjectionEq(ProjectionEq { ref projection, .. }) => {
474-
let (associated_ty_data, trait_params, _) = program.split_projection(&projection);
475-
let trait_ref = TraitRef {
476-
trait_id: associated_ty_data.trait_id,
477-
parameters: trait_params.to_owned(),
478-
};
479-
expanded.push(WellFormed::TraitRef(trait_ref.clone()).cast());
480-
expanded.push(trait_ref.cast());
481-
}
482-
_ => (),
483-
};
484-
expanded.push(self.cast());
485-
expanded.into_iter()
478+
DomainGoal::Implemented(tr) => DomainGoal::WellFormed(WellFormed::TraitRef(tr)),
479+
DomainGoal::ProjectionEq(n) => DomainGoal::WellFormed(WellFormed::ProjectionEq(n)),
480+
goal => goal,
481+
}
482+
}
483+
484+
/// Same as `into_well_formed_clause` but with the `FromEnv` predicate instead of `WellFormed`.
485+
crate fn into_from_env_clause(self) -> DomainGoal {
486+
match self {
487+
DomainGoal::Implemented(tr) => DomainGoal::FromEnv(FromEnv::TraitRef(tr)),
488+
DomainGoal::ProjectionEq(n) => DomainGoal::FromEnv(FromEnv::ProjectionEq(n)),
489+
goal => goal,
490+
}
486491
}
487492
}
488493

@@ -502,9 +507,47 @@ pub struct EqGoal {
502507
}
503508

504509
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
510+
/// A predicate which is true is some object is well-formed, e.g. a type or a trait ref.
511+
/// For example, given the following type definition:
512+
///
513+
/// ```notrust
514+
/// struct Set<K> where K: Hash {
515+
/// ...
516+
/// }
517+
/// ```
518+
///
519+
/// then we have the following rule: `WellFormed(Set<K>) :- (K: Hash)`.
520+
/// See the complete rules in `lower.rs`.
505521
pub enum WellFormed {
506522
Ty(Ty),
507523
TraitRef(TraitRef),
524+
ProjectionEq(ProjectionEq),
525+
}
526+
527+
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
528+
/// A predicate which enables deriving everything which should be true if we *know* that some object
529+
/// is well-formed. For example, given the following trait definitions:
530+
///
531+
/// ```notrust
532+
/// trait Clone { ... }
533+
/// trait Copy where Self: Clone { ... }
534+
/// ```
535+
///
536+
/// then we can use `FromEnv(T: Copy)` to derive that `T: Clone`, like in:
537+
///
538+
/// ```notrust
539+
/// forall<T> {
540+
/// if (FromEnv(T: Copy)) {
541+
/// T: Clone
542+
/// }
543+
/// }
544+
/// ```
545+
///
546+
/// See the complete rules in `lower.rs`.
547+
pub enum FromEnv {
548+
Ty(Ty),
549+
TraitRef(TraitRef),
550+
ProjectionEq(ProjectionEq),
508551
}
509552

510553
/// Proves that the given projection **normalizes** to the given
@@ -710,13 +753,19 @@ impl<T> UCanonical<T> {
710753
}
711754

712755
impl UCanonical<InEnvironment<Goal>> {
713-
/// A goal has coinductive semantics if it is of the form `T: AutoTrait`.
756+
/// A goal has coinductive semantics if it is of the form `T: AutoTrait`, or if it is of the
757+
/// form `WellFormed(T: Trait)` where `Trait` is any trait. The latter is needed for dealing
758+
/// with WF requirements and cyclic traits, which generates cycles in the proof tree which must
759+
/// not be rejected but instead must be treated as a success.
714760
crate fn is_coinductive(&self, program: &ProgramEnvironment) -> bool {
715761
match &self.canonical.value.goal {
716762
Goal::Leaf(LeafGoal::DomainGoal(DomainGoal::Implemented(tr))) => {
717763
let trait_datum = &program.trait_data[&tr.trait_id];
718764
trait_datum.binders.value.flags.auto
719765
}
766+
Goal::Leaf(LeafGoal::DomainGoal(DomainGoal::WellFormed(WellFormed::TraitRef(_)))) => {
767+
true
768+
}
720769
_ => false,
721770
}
722771
}

src/lower/default.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use solve::infer::InferenceTable;
33
use cast::Cast;
44

55
impl Program {
6-
pub(super) fn add_default_impls(&mut self) {
6+
pub fn add_default_impls(&mut self) {
77
// For each auto trait `MyAutoTrait` and for each struct/type `MyStruct`
88
for auto_trait in self.trait_data
99
.values()

0 commit comments

Comments
 (0)