-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Use the recorded types in MIR to determine generator auto-trait implementations #65782
Closed
Commits on Dec 7, 2019
-
Use the recorded types in MIR to determine generator auto-trait imple…
…mentations When we construct a generator type, we build a `ty::GeneratorWitness` from a list of types that may live across a suspend point. These types are used to determine the 'constitutent types' for a generator when selecting an auto-trait predicate. Any types appearing in the GeneratorWitness are required to implement the auto trait (e.g. `Send` or `Sync`). This analysis is based on the HIR - as a result, it is unable to take liveness of variables into account. This often results in unnecessary bounds being computing (e.g requiring that a `Rc` be `Sync` even if it is dropped before a suspend point), making generators and `async fn`s much less ergonomic to write. This commit uses the generator MIR to determine the actual 'constituent types' of a generator. Specifically, a type in the generator witness is considered to be a 'constituent type' of the witness if it appears in the `field_tys` of the computed `GeneratorLayout`. Any type which is stored across an suspend point must be a constituent type (since it could be used again after a suspend), while any type that is not stored across a suspend point cannot possible be a constituent type (since it is impossible for it to be used again). By re-using the existing generator layout computation logic, we get some nice properties for free: * Types which are dead before the suspend point are not considered constituent types * Types without Drop impls not considered constituent types if their scope extends across an await point (assuming that they are never used after an await point). Note that this only affects `ty::GeneratorWitness`, *not* `ty::Generator` itself. Upvars (captured types from the parent scope) are considered to be constituent types of the base `ty::Generator`, not the inner `ty::GeneratorWitness`. This means that upvars are always considered constituent types - this is because by defintion, they always live across the first implicit suspend point. ------- Implementation: The most significant part of this PR is the introduction of a new 'delayed generator witness mode' to `TraitEngine`. As @nikomatsakis pointed out, attmepting to compute generator MIR during type-checking results in the following cycle: 1. We attempt to type-check a generator's parent function 2. During type checking of the parent function, we record a predicate of the form `<generator>: AutoTrait` 3. We add this predicate to a `TraitEngine`, and attempt to fulfill it. 4. When we atempt to select the predicate, we attempt to compute the MIR for `<generator>` 5. The MIR query attempts to compute `type_of(generator_def_id)`, which results in us attempting to type-check the generator's parent function. To break this cycle, we defer processing of all auto-trait predicates involving `ty::GeneratorWitness`. These predicates are recorded in the `TypeckTables` for the parent function. During MIR type-checking of the parent function, we actually attempt to fulfill these predicates, reporting any errors that occur. The rest of the PR is mostly fallout from this change: * `ty::GeneratorWitness` now stores the `DefId` of its generator. This allows us to retrieve the MIR for the generator when `SelectionContext` processes a predicate involving a `ty::GeneratorWitness` * Since we now store `PredicateObligations` in `TypeckTables`, several different types have now become `RustcEncodable`/`RustcDecodable`. These are purely mechanical changes (adding new `#[derives]`), with one exception - a new `SpecializedDecoder` impl for `List<Predicate>`. This was essentially identical to other `SpecializedDecoder` imps, but it would be good to have someone check it over. * When we delay processing of a `Predicate`, we move it from one `InferCtxt` to another. This requires us to prevent any inference variables from leaking out from the first `InferCtxt` - if used in another `InferCtxt`, they will either be non-existent or refer to the the wrong variable. Fortunately, the predicate itself has no region variables - the `ty::GeneratorWitness` has only late-bound regions, while auto-traits have no generic parameters whatsoever. However, we still need to deal with the `ObligationCause` stored by the `PredicateObligation`. An `ObligationCause` (or a nested cause) may have any number of region variables stored inside it (e.g. from stored types). Luckily, `ObligationCause` is only used for error reporting, so we can safely erase all regions variables from it, without affecting the actual processing of the obligation. To accomplish this, I took the somewhat unusual approach of implementing `TypeFoldable` for `ObligationCause`, but did *not* change the `TypeFoldable` implementation of `Obligation` to fold its contained `ObligationCause. Other than this one odd case, all other callers of `TypeFoldable` have no interest in folding an `ObligationCause`. As a result, we explicitly fold the `ObligationCause` when computing our deferred generator witness predicates. Since `ObligationCause` is only used for displaying error messages, the worst that can happen is that a slightly odd error message is displayed to a user. With this change, several tests now have fewer errors than they did previously, due to the improved generator analysis. Unfortunately, this does not resolve issue rust-lang#64960. The MIR generator transformation stores format temporaries in the generator, due to the fact that the `format!` macro takes a reference to them. As a result, they are still considered constituent types of the `GeneratorWitness`, and are still required to implement `Send` and `Sync. * I've changed the pretty-printing of `ty::GeneratorWitness` to print out its generator DefId, as well as the word `witness`. This makes debugging issues related to the computation of constituent types much simpler. As a final note, this PR contains one unrelated change - all generators now implement `Freeze` unconditionally. I've opened a separate PR containing this change - however, it's necessary to allow this branch to compile without cycle errors. I've left it in this PR to make it easy to test out this branch on actual code. Assuming that it is accepted, this PR will be rebased against `master` when it is merged. Otherwise, I'll need to figure out a different approach to generator const-qualification.
Configuration menu - View commit details
-
Copy full SHA for 9303810 - Browse repository at this point
Copy the full SHA 9303810View commit details -
Configuration menu - View commit details
-
Copy full SHA for 78159e1 - Browse repository at this point
Copy the full SHA 78159e1View commit details -
Configuration menu - View commit details
-
Copy full SHA for 46e2d2c - Browse repository at this point
Copy the full SHA 46e2d2cView commit details -
Configuration menu - View commit details
-
Copy full SHA for 5ce4306 - Browse repository at this point
Copy the full SHA 5ce4306View commit details -
Configuration menu - View commit details
-
Copy full SHA for 6840bc4 - Browse repository at this point
Copy the full SHA 6840bc4View commit details -
Configuration menu - View commit details
-
Copy full SHA for bea0a42 - Browse repository at this point
Copy the full SHA bea0a42View commit details -
Configuration menu - View commit details
-
Copy full SHA for 2b2986d - Browse repository at this point
Copy the full SHA 2b2986dView commit details -
Configuration menu - View commit details
-
Copy full SHA for e4684c7 - Browse repository at this point
Copy the full SHA e4684c7View commit details -
Configuration menu - View commit details
-
Copy full SHA for 97116eb - Browse repository at this point
Copy the full SHA 97116ebView commit details -
Configuration menu - View commit details
-
Copy full SHA for b3e6f8d - Browse repository at this point
Copy the full SHA b3e6f8dView commit details -
Configuration menu - View commit details
-
Copy full SHA for 0c92b83 - Browse repository at this point
Copy the full SHA 0c92b83View commit details -
Configuration menu - View commit details
-
Copy full SHA for b891e49 - Browse repository at this point
Copy the full SHA b891e49View commit details -
Configuration menu - View commit details
-
Copy full SHA for 87fc30d - Browse repository at this point
Copy the full SHA 87fc30dView commit details -
Co-Authored-By: Ralf Jung <post@ralfj.de>
Configuration menu - View commit details
-
Copy full SHA for 8f58a71 - Browse repository at this point
Copy the full SHA 8f58a71View commit details -
Configuration menu - View commit details
-
Copy full SHA for 71c9dd5 - Browse repository at this point
Copy the full SHA 71c9dd5View commit details
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.