Repository navigation
Implied bounds, second take - #82
Conversation
nikomatsakis
left a comment
There was a problem hiding this comment.
First round of comments. Will read in more depth tomorrow, especially the accumulator stuff. This is nice! 💯
| "forall" "<" <p:Comma<ParameterKind>> ">" "{" <g:Goal> "}" => Box::new(Goal::ForAll(p, g)), | ||
| "exists" "<" <p:Comma<ParameterKind>> ">" "{" <g:Goal> "}" => Box::new(Goal::Exists(p, g)), | ||
| <i:IfKeyword> "(" <w:Comma<WhereClause>> ")" "{" <g:Goal> "}" => Box::new(Goal::Implies(w, g, i)), | ||
| "if" "(" <w:Comma<WhereClause>> ")" "{" <g:Goal> "}" => Box::new(Goal::Implies(w, g)), |
There was a problem hiding this comment.
I am happy to see if_raw gone, I have to say. That always felt "yucky".
| fn parse_and_lower_program(text: &str, solver_choice: SolverChoice, skip_coherence: bool) | ||
| -> Result<ir::Program> | ||
| { | ||
| if skip_coherence { |
There was a problem hiding this comment.
It seems like this parameter is just always false? Can we just plain remove this?
| CYCLEY_GOAL, | ||
| b, | ||
| "Unique", | ||
| true |
There was a problem hiding this comment.
well I guess it's true here, but not (I take it) for the reasons stated? (why is it true here?)
There was a problem hiding this comment.
The recursive solver fails to answer uniquely goals of the form <Bar as Foo>::Assoc: SomeTrait (or WellFormed(<Bar as Foo>::Assoc: SomeTrait)). So this is a temporary hack (de-activing checking WF requirements) so that the benchmark tests pass, but I should add a FIXME or something because this is really not ought to stay.
| impl UCanonical<InEnvironment<Goal>> { | ||
| /// A goal has coinductive semantics if it is of the form `T: AutoTrait`. | ||
| /// A goal has coinductive semantics if it is of the form `T: AutoTrait`, or if it is of the | ||
| /// form `WellFormed(T: Trait)` where `Trait` is any trait. The latter is needed for dealing |
There was a problem hiding this comment.
I am mildly surprised that we don't want to just make all WellFormed goals coinductive. But I guess it's only needed for traits...
There was a problem hiding this comment.
Well types only have where clauses of the form T: Trait, there are no WF(Type) where clauses so you never have the kinds of cycles encountered with traits.
| WhereClause::TraitRefWellFormed { ref trait_ref } => { | ||
| ir::WellFormed::TraitRef(trait_ref.lower(env)?).cast() | ||
| } | ||
| WhereClause::TyFromEnv { ref ty } => ir::FromEnv::Ty(ty.lower(env)?).cast(), |
There was a problem hiding this comment.
I am torn on the question of what this should mean:
if (T: Trait) { .. }
I am thinking maybe we should make that equivalent to if (FromEnv(T: Trait)) { .. } and then have an explicit form if (Implemented(T: Trait)) { .. }. Basically T: Trait would parse to an AST form whose expansion depends on whether it appears in a "clause" (in which case it is FromEnv) or a Goal (in which case it is "Implemented").
There was a problem hiding this comment.
(That said, I'm not really sure when we would want to say if (Implemented(T: Trait)) { ... }.. but maybe it's useful when crafting unit tests or something.)
There was a problem hiding this comment.
Yeah not really sure either, but I think converting to FromEnv(T: Trait) in clauses is a good thing, and the explicit goal Implemented would replace the former if_raw statement in a much nicer way.
| // | ||
| // forall<T> { | ||
| // Normalize(<T as Foo>::Assoc -> U) :- FromEnv(T: Foo<Assoc = U>) | ||
| // } |
There was a problem hiding this comment.
As an aside, and not for this PR, I wonder if we can use macros to make this code less tedious to write.
| impl<T> A for T where T: B {} | ||
| } error_msg { | ||
| "trait impl for \"B\" does not meet well-formedness requirements" | ||
| } |
There was a problem hiding this comment.
(maybe we should add a test where this succeeds?)
| type Value; | ||
| } | ||
|
|
||
| impl Bar for i32 { |
There was a problem hiding this comment.
Maybe add a comment here: this fails because i32: Foo does not hold
| type Value; | ||
| } | ||
|
|
||
| impl<K> Foo for Set<K> { |
There was a problem hiding this comment.
Here, Wf(Set<K>) implies K: Hash and hence OnlyEq<K> is WF
|
|
||
| // Type parameters and higher-kinded types do not carry any input types (so we can sort | ||
| // of assume they are always WF). | ||
| Ty::Var(..) | Ty::ForAll(..) => (), |
There was a problem hiding this comment.
Hmm, Ty::ForAll corresponds to for<'a> fn(&'a u32) or some such. I don't know that we can assume they are always WF. I think this accumulator probably doesn't want to accumulate into a vector, but rather to invoke a callback, because in the case of for<'a> we may want to create subuniverses? I have to read this code a bit more carefully I guess.
There was a problem hiding this comment.
Actually we discussed that and for some reason we decided that higher-kinded types are always WF. This is similar to the fact that if we have this kind of function:
fn foo<T>(arg: HashSet<NotHash<T>>) { ... }we would not issue any error until the function is called. For lifetime parametric function types, again an error would be issued only if a function of this type is ever called. We discussed that in our dropbox paper (see 2017.07.25).
There was a problem hiding this comment.
Oh, right, I forgot about that. Basically we were assuming that for all types introduce their own implied bounds, right? Makes sense.
There was a problem hiding this comment.
Can we put a more explicit comment then? =)
|
@scalexm ok so the changes to make then are:
Do you think you'll have time for that? Do you want me to do it? We should probably make more tests but I'm not inclined to block on that. |
05f2322 to
acd499f
Compare
|
I read over the changes more thoroughly. Everything looks great. I looked briefly at the on-demand test was failing; for some reason it is now creating However, I did notice one thing. It seems like you are treating The intention is that "projection eq" is the "normal" rule, with Anyway, I pushed a final commit with a test that fails as a result -- but I think is expected to pass. |
This is a full implementation of implied bounds as well as enforcing WF requirements on impls and type declarations.
The rules for WF requirements on traits are detailed in #12 (and in the code). The rules for types are much more simple (no need for co-recursion but we still have two predicates,
WellFormedandFromEnv).I was not greatly inspired for the tests, so one can feel free to add some more.
Fixes #11 and incidentally some form of bug related to #70. And eventually #12 will be resolved too.