Skip to content

Write well-formedness checking chapter #222

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Nov 3, 2018
Merged

Conversation

scalexm
Copy link
Member

@scalexm scalexm commented Oct 29, 2018

This covers types, traits and trait impls.

cc @nikomatsakis @tmandry

Copy link
Member

@mark-i-m mark-i-m left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks :)

I left a few nits and comments, but overall it looks good!

@mark-i-m
Copy link
Member

Also, travis is failing.

Co-Authored-By: scalexm <[email protected]>
Copy link
Member

@tmandry tmandry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! I think this does a very good job of explaining the concepts. It would have been really helpful to have when I was first working on traits.

Added a few readability nits, otherwise looks good to me.

src/traits/wf.md Outdated
}
```

So where clauses on associated types work *exactly* like where clauses on
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was confused at first because I thought you were talking about WF rules for trait methods (which aren't mentioned here). It might be helpful to say "In Rust, where clauses on associated types work..." to make it clear you're talking about the semantics of Rust itself.

Also consider marking this paragraph as an "aside" with >, to emphasize that you don't need to be familiar with those semantics to understand the rest of the chapter.

forall<P2...> {
if (FromEnv(WC_assoc)) {
WellFormed(SomeValue<A3...>: Bounds_assoc) &&
WellFormed(InputTypes(SomeValue<A3...>))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From a quick scan of the below text, I'm confused why this doesn't have WellFormed(InputTypes(WC_assoc)) as in the other goals.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is indeed something missing but not exactly what you’re pointing :)

I stated that you could assume that the receiver type and its input types are well-formed.

This is correct but not complete: actually you can assume FromEnv(InputTypes(SomeType<A2...>: Trait<A1...>)). We can do that because everywhere else we check that all types appearing in where clauses are WF. This is what we currently do in chalk, I just forgot about it.

Then, we already checked WC_assoc in the trait decl. In the impl, they are basically repeated, except that we substituted type parameters from the trait with the values provided by the impl, that is A1.... But since we already assume that the A1... are WF, no need to check again.

Copy link
Member

@tmandry tmandry Oct 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then, we already checked WC_assoc in the trait decl. In the impl, they are basically repeated, except that we substituted type parameters from the trait with the values provided by the impl, that is A1.... But since we already assume that the A1... are WF, no need to check again.

Yeah, on second thought this seems clear, though it may be worth saying. Also, the text might want to mention (in the paragraph above) where the WC_assoc is verified to be equivalent to the trait decl. i.e. is it during lowering in chalk?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In chalk we have an easy solution for that: we just don’t write where clauses on associated type values, they are like auto-repeated from the trait :)

I don’t know yet where we’ll do that in rustc, especially because if we want to really mimic where clauses on trait methods, then it’s a bit more complex than just « omit it or write it »: on trait methods, you can actually write "new" where clauses provided that they are weaker than (= implied by) the original ones, for example you can do that:

trait Foo {
    fn foo<T> where T: Copy;
}

impl Foo for i32 {
    fn foo<T> where T: Clone { ... }
}

Of course this is useless from a semantic POV, it just serves as a documentation that you are not using the full power of the original where clause. But to check that the where clauses you wrote are indeed weaker, you’d need to use the trait solver of course. So I decided to juste sidestep this in the text as this is anecdotic I think.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the idea would be that -- to prove the impl is well-formed -- we have to prove that the where-clauses from the trait imply the where-clauses from the impl. i.e., assuming the where-clauses from the trait hold, we show we can prove the where-clauses from the impl -- but I agree it can wait to be added.

`WellFormed(SomeType<A2...>: Trait<A1...>)` hold. That is, we want to prove
that `SomeType<A2...>` verify all the where clauses that might transitively
come from the `Trait` definition (see
[this subsection](./implied-bounds.md#co-inductiveness-of-wellformed)).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to skip over the WellFormed(InputTypes(WC_impl)) part.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I was trying to factor out all the WellFormed(InputTypes(...)) in the previous paragraph (« assuming that the various where clauses hold, we prove that every type appearing in the impl is WF»)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I missed that, sorry. Maybe update the goal clauses to match the order that they are mentioned in the text?

Also, it does say something to the effect of "assuming that the various where clauses hold" twice, this might be slightly confusing.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think when writing that paragraph I wasn’t entierely convinced by my formulation either :)

I’ll separate the if goals in two parts yes, it should be clearer.

src/traits/wf.md Outdated
Lastly, assuming that the where clauses on the associated type `WC_assoc` hold,
we prove that `WellFormed(SomeValue<A3...>: Bounds_assoc)` hold. Again, we are
not only proving `Implemented(SomeValue<A3...>: Bounds_assoc)`, but also
all the facts that might transitively come from `Bounds_assoc`. This is because
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
all the facts that might transitively come from `Bounds_assoc`. This is because
all the facts that might transitively come from `Bounds_assoc` using only the
where clauses in scope. We must do this because

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmh so we’re not only using the where clauses in fact, we can also rely on the various program clauses that don’t come from the environment but rather from the other impls,

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point.

@scalexm
Copy link
Member Author

scalexm commented Oct 30, 2018

@tmandry Thanks, I’ll fix what we discussed in the comments soon (on my phone now).

Co-Authored-By: scalexm <[email protected]>
@scalexm
Copy link
Member Author

scalexm commented Oct 30, 2018

Ok @tmandry should be good now. Just waiting for @nikomatsakis to proofread it and we should be ok.

Copy link
Contributor

@nikomatsakis nikomatsakis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This all seems like a great start. I left some nits. I think we will wind up iterating but I'd prefer to land the text and refine over time.


The new-style WF checking has not been implemented in rustc yet.

[wf]: https://github.com/rust-lang-nursery/chalk/blob/master/src/rules/wf.rs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should link to the chalk rustdocs at http://rust-lang-nursery.github.io/chalk/doc/chalk/rules/wf/index.html instead? Not sure.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that the code is still a good documentation for that chapter as there are multiple subtle things happening.

src/traits/wf.md Outdated
lowering rules, we'll introduce another notation: when checking WF of a
declaration, we'll often have to prove that all types that appear are
well-formed, except type parameters that we always assume to be WF. Hence,
we'll use the following notation: for a type `SomeType<...>`, we denote
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Instead of "we denote" maybe "we define InputTypes(SomeType<..>) to be the set of all non-parameter types..."

src/traits/wf.md Outdated
* `InputTypes(Box<T>) = [Box<T>]`
* `InputTypes(Box<Box<T>>) = [Box<T>, Box<Box<T>>]`

We may naturally extend the `InputTypes` notation to where clauses, for example
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: "We also extend the InputTypes notation to where clauses in the natural way. So, for example, InputTypes(A0: ...)..."

src/traits/wf.md Outdated
}
```

we generate the following goal:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: we generate the following goal, which represents its well-formedness condition:

src/traits/wf.md Outdated

Examples:
* `InputTypes((u32, f32)) = [u32, f32, (u32, f32)]`
* `InputTypes(Box<T>) = [Box<T>]`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add something like ", assuming that T is a type parameter"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remind me btw why we pushed the "expansion" into the lowering step, versus defining a proper WellFormed(T) goal? (And then having struct Box<T> get to assume that WellFormed(T) in its "environment"?)

src/traits/wf.md Outdated
}
```

which in English gives: assuming that the where clauses defined on the type
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/gives/states/

src/traits/wf.md Outdated
the input types of `SomeType<A2...>` are well-formed, we prove that
`WellFormed(SomeType<A2...>: Trait<A1...>)` hold. That is, we want to prove
that `SomeType<A2...>` verify all the where clauses that might transitively
come from the `Trait` definition (see
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: s/come/be required by/

@nikomatsakis nikomatsakis merged commit 505c99f into rust-lang:master Nov 3, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants