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

Implement generators #593

Merged
merged 4 commits into from
Sep 29, 2020
Merged

Implement generators #593

merged 4 commits into from
Sep 29, 2020

Conversation

Aaron1011
Copy link
Member

@Aaron1011 Aaron1011 commented Aug 10, 2020

GeneratorDatum and GeneratorWitnessDatum are introduced, which
mirror TyKind::Generator and TyKind::GeneratorWitness in rustc.

We handle auto traits for GeneratorDatum using the existing
constituent_types method. For GeneratorWitnessDatum, we generate a
forall<'a, 'b, ... 'z> goal to reflect the fact that our lifetimes are
existentially bound.

Unresolved questions:

  • The implementation of GeneratorWitnessDatum needs careful review -
    I'm not certain that I fully understand how Binders works.
  • The syntax implemented in parser.lalrpop can be bikesheeded. We
    might want to use something other than for<> for the witness types,
    to reflect that fact that we have existential rather than universal
    quantification.
  • The generator grammar only allows quantifying over liftimes for the
    witness types - however, this gets lowered to a Binders, which
    supports types and constants as well. Should we do anything else
    to ensure we never end up with types/consts where they're not
    expected?
  • I added a test to ensure that we treat the witness lifetimes as
    existentially quantified - for example, if we have
    for<'a, 'b> Foo<'a, 'b>, we should only be able to use an auto
    trait impl that is fully generic over lifetimes - e.g.
    impl<'a> Send for Foo<'a, 'b> will not be used. I believe
    that the test is showing this behavior - it ends up returning
    region constraints that require 'a and 'b to outlive each other.
    Since these are 'existential' lifetimes (which cannot be substituted),
    this is an unsatisfiable constraint. However, I'm not sure where we
    should be detecting that this is unsatisfiable.
  • In rustc, all of the existential witness lifetimes are distinct. This is not enforced by this PR e.g. you can repeat a lifetime in the witness type. I'm not sure if/where we should enforce this.

@Aaron1011
Copy link
Member Author

This is mostly working - however, I still need to figure out how to treat generator witness lifetime as existentially quantified when handling auto traits.

@Aaron1011 Aaron1011 marked this pull request as ready for review September 21, 2020 01:41
@Aaron1011 Aaron1011 changed the title [WIP] Generators Implement generators Sep 21, 2020
@Aaron1011
Copy link
Member Author

@jackh726 @nikomatsakis This is ready for review

`GeneratorDatum` and `GeneratorWitnessDatum` are introduced, which
mirror `TyKind::Generator` and `TyKind::GeneratorWitness` in rustc.

We handle auto traits for `GeneratorDatum` using the existing
`constituent_types` method. For `GeneratorWitnessDatum`, we generate a
`forall<'a, 'b, ... 'z>` goal to reflect the fact that our lifetimes are
existentially bound.

Unresolved questions:
* The implementation of `GeneratorWitnessDatum` needs careful review -
  I'm not certain that I fully understand how `Binders` works.
* The syntax implemented in `parser.lalrpop` can be bikesheeded. We
  might want to use something other than `for<>` for the witness types,
  to reflect that fact that we have existential rather than universal
  quantification.
* The generator grammar only allows quantifying over liftimes for the
  witness types - however, this gets lowered to a `Binders`, which
  supports types and constants as well. Should we do anything else
  to ensure we never end up with types/consts where they're not
  expected?
* I added a test to ensure that we treat the witness lifetimes as
  existentially quantified - for example, if we have
  `for<'a, 'b> Foo<'a, 'b>`, we should only be able to use an auto
  trait impl that is fully generic over lifetimes - e.g.
  `impl<'a> Send for Foo<'a, 'b>` will not be used. I *believe*
  that the test is showing this behavior - it ends up returning
  region constraints that require `'a` and `'b` to outlive each other.
  Since these are 'existential' lifetimes (which cannot be substituted),
  this is an unsatisfiable constraint. However, I'm not sure where we
  should be detecting that this is unsatisfiable.
@jackh726
Copy link
Member

I definitely don't know enough about generators to make a meaningful review of this, so will definitely have to defer to @nikomatsakis. However, the book builtin types table will need to be updated here.

Additionally, I really want to push for us to document generators and generator witnesses in the chalk book. I don't think it needs to be in this PR, but I am somewhat worried that if it isn't at least loosely documented here, it'll get pushed aside. Particularly, I feel like documenting this is super important since there's almost no documentation in the rustc dev guide or in the rustc codebase (that I can find).

@Aaron1011
Copy link
Member Author

I'll work on writing up some docs.

@jackh726
Copy link
Member

I'll work on writing up some docs.

Awesome!

I do want to stress that I understand docs can sometimes be hard to write. But I would definitely error on the side of "some docs are better than no docs" and "don't let perfect be the enemy of good enough"; we can always expand upon/clarify the docs in subsequent PRs.

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 is great. I left a nit about the syntax but I'm inclined to land it.

* Resume/yield/return types - the types produced/consumed by various generator methods.
These are not stored in the generator across yield points - they are only
used when the generator is running.
* Generator witness - see the `Generator Witness` section below.
Copy link
Contributor

Choose a reason for hiding this comment

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

thank you for writing docs! wonderful.

### Generator witness types

The `GeneratorWitness` variant represents the generator witness of
the generator with id `GeneratorId`.
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 it'd be good to explain the purpose of a witness:

The witness type captures the types of all variables that may be live across a yield point.

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 just moved this entire block from a different section of the book :) - I'm happy to expand on it.

// If we have `Foo<'a, 'b>` stored as a witness type, we will
// not currently use this information to determine a more precise
// relationship between 'a and 'b. In the future, we will likely
// do this to avoid incorrectly rejecting correct code.
Copy link
Contributor

Choose a reason for hiding this comment

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

Another great comment.


generator send_any_lifetime<T>[resume = (), yield = ()] {
upvars []
witnesses for<'a, 'b> [SendAnyLifetime<'a, 'b, T>; u8]
Copy link
Contributor

Choose a reason for hiding this comment

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

the for syntax here seems a bit misleading, I guess?

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, it's not great. Do you think exists<> would be better?

@Aaron1011
Copy link
Member Author

@nikomatsakis: I've addressed your comments

@jackh726
Copy link
Member

@bors r=nikomatsakis

@bors
Copy link
Contributor

bors commented Sep 29, 2020

📌 Commit e7a0892 has been approved by nikomatsakis

@bors
Copy link
Contributor

bors commented Sep 29, 2020

⌛ Testing commit e7a0892 with merge 8f28056...

@bors
Copy link
Contributor

bors commented Sep 29, 2020

☀️ Test successful - checks-actions
Approved by: nikomatsakis
Pushing 8f28056 to master...

@bors bors merged commit 8f28056 into rust-lang:master Sep 29, 2020
@jackh726 jackh726 mentioned this pull request Oct 3, 2020
2 tasks
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