Skip to content
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

Goal builder #361

Merged
merged 15 commits into from
Apr 1, 2020
Merged

Goal builder #361

merged 15 commits into from
Apr 1, 2020

Conversation

nikomatsakis
Copy link
Contributor

Initial work on introducing a "goal builder", with the aim of making the wf and coherence code easier to read and less error-prone. This is only part-way through. Builds on #360.

@jackh726
Copy link
Member

Haven't really looked it over yet, but I'm definitely happy about this. It should make lowering Goals for rustc easier.

@nikomatsakis nikomatsakis force-pushed the goal-builder branch 2 times, most recently from e3cbf1e to 10013b1 Compare March 28, 2020 10:42
For a GAT like

```
impl<T> Foo<T> { type Bar<'a> = ..}
```

Instead of constructing nested quantifiers like

```
forall<T> {
  if (..) {
    stuff &&
    forall<'a> { more_stuff }
  }
}
```

we will now build separate goals

```
forall<T> { if (...) { stuff } } &&
forall<T, 'a> { if (...) { more_stuff } }
```

This both removes the need for the 'partial' forall methods in
GoalBuilder butalso means we would be able to give better error
messages in rustc at somepoint, since we can test "is this impl header
WF" separately from "is this associated type value WF" etc.
@nikomatsakis nikomatsakis marked this pull request as ready for review March 31, 2020 10:31
@nikomatsakis
Copy link
Contributor Author

nikomatsakis commented Mar 31, 2020

OK, the PR history took a bit of a round-about path, but I'd say this is ready for comment. Probably best to just view the "whole diff".

The new APIs are in goal_builder.rs, so you might start there.

The wf.rs and coherence changes are porting code to use the goal builder. I think the result is much more readable, and it also includes no manual adjusting of debruijn indices. It's much harder to get things wrong, and the "general visual structure" of the code matches the logical goal we are building. Still, the code is more verbose than I had hoped.

The new APIs do lead to a little more cloning than we used to have, but I'm not concerned. I wouldn't expect these pathways to be perf sensitive in the real compiler, and we could optimize if that were ever a problem.

One possible change worth making: converting GoalBuilder to use &self instead of &mut self. It wound up having no internal state, and &mut self makes some things a bit more annoying (e.g., I have to do let interner = gb.interner() more often than I might otherwise have to).

Another slight annoyance that crops up a few times is that we have to thread the id of various datums into gb.forall and gb.exists calls and then "re-fetch" the associated datum from the database. This is true even though we have a Arc<FooDatum> struct on hand. This is relatively harmless, those fetches are meant to be cached and cheap, but kind of annoying. It happens because those types don't implement Fold and so they can't be threaded through. What we would maybe ideally want is something that lets us "fold" them by cloning, but without deep-cloning the Arc. Probably the right thing would be to move the Arc into the FooDatum struct, so that it can be cheaply cloned. I didn't do this.

chalk-solve/src/goal_builder.rs Outdated Show resolved Hide resolved
chalk-solve/src/goal_builder.rs Outdated Show resolved Hide resolved
chalk-solve/src/goal_builder.rs Outdated Show resolved Hide resolved
{
let interner = self.interner();
let bound_goal = binders.map_ref(|bound_value| {
let substitution: Substitution<I> = Substitution::from(
Copy link
Member

Choose a reason for hiding this comment

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

Can you move this out of this out of the map_ref closure? Then just either pass a &Substitution or clone? It makes it a little bit more obvious what's going on.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can move it out of the closure, but I'm not sure what you mean by "passing a &Substitution or clone" -- you'd rather I not give ownership of the Substitution? Or would you rather I clone the contents of the binder?

In some variant, I had the signature of the body be:

  • Substitution<I>
  • B::Result (i.e., contents of binder, instantiated with Substitution)
  • P::Result (i.e., contents of passthru, shifted)

I changed to &B because, in fact, the substitution is always an identity substitution (in the earlier version, this wasn't always the case), so doing a substitution wasn't really necessary. But I think the above signature is kind of the most "obvious" signature, and I'd be reasonably happy to adopt it (since I think readability trumps most concerns here).

chalk-solve/src/wf.rs Outdated Show resolved Hide resolved
chalk-solve/src/wf.rs Outdated Show resolved Hide resolved
chalk-solve/src/goal_builder.rs Outdated Show resolved Hide resolved
@jackh726 jackh726 merged commit 039fc90 into rust-lang:master Apr 1, 2020
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.

2 participants