-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
avoid generalization inside of aliases #119106
Conversation
This comment has been minimized.
This comment has been minimized.
fe6db6e
to
01ec1ab
Compare
gna mark this as author until it's out of draft? @rustbot author |
…ty-eagerly, r=oli-obk Construct closure type eagerly Construct the returned closure type *before* checking the body, in the same match as we were previously deducing the coroutine types based off of the closure kind. This simplifies some changes I'm doing in the async closure PR, and imo just seems easier to read (since we only need one match on closure kind, instead of two). There's no reason I can tell that we needed to create the closure type *after* the body was checked. ~~This also has the side-effect of making it so that the universe of the closure synthetic infer vars are lower than any infer vars that come from checking the body. We can also get rid of `next_root_ty_var` hack from closure checking (though in general we still need this, rust-lang#119106). cc `@lcnr` since you may care about this hack 😆~~ r? `@oli-obk`
…ty-eagerly, r=oli-obk Construct closure type eagerly Construct the returned closure type *before* checking the body, in the same match as we were previously deducing the coroutine types based off of the closure kind. This simplifies some changes I'm doing in the async closure PR, and imo just seems easier to read (since we only need one match on closure kind, instead of two). There's no reason I can tell that we needed to create the closure type *after* the body was checked. ~~This also has the side-effect of making it so that the universe of the closure synthetic infer vars are lower than any infer vars that come from checking the body. We can also get rid of `next_root_ty_var` hack from closure checking (though in general we still need this, rust-lang#119106). cc ``@lcnr`` since you may care about this hack 😆~~ r? ``@oli-obk``
…ty-eagerly, r=oli-obk Construct closure type eagerly Construct the returned closure type *before* checking the body, in the same match as we were previously deducing the coroutine types based off of the closure kind. This simplifies some changes I'm doing in the async closure PR, and imo just seems easier to read (since we only need one match on closure kind, instead of two). There's no reason I can tell that we needed to create the closure type *after* the body was checked. ~~This also has the side-effect of making it so that the universe of the closure synthetic infer vars are lower than any infer vars that come from checking the body. We can also get rid of `next_root_ty_var` hack from closure checking (though in general we still need this, rust-lang#119106). cc ```@lcnr``` since you may care about this hack 😆~~ r? ```@oli-obk```
Rollup merge of rust-lang#120031 - compiler-errors:construct-closure-ty-eagerly, r=oli-obk Construct closure type eagerly Construct the returned closure type *before* checking the body, in the same match as we were previously deducing the coroutine types based off of the closure kind. This simplifies some changes I'm doing in the async closure PR, and imo just seems easier to read (since we only need one match on closure kind, instead of two). There's no reason I can tell that we needed to create the closure type *after* the body was checked. ~~This also has the side-effect of making it so that the universe of the closure synthetic infer vars are lower than any infer vars that come from checking the body. We can also get rid of `next_root_ty_var` hack from closure checking (though in general we still need this, rust-lang#119106). cc ```@lcnr``` since you may care about this hack 😆~~ r? ```@oli-obk```
…ar-helper, r=lcnr Remove `next_root_ty_var` Uhh we seem to not have any test that relies on this anymore. Maybe due to the way we changed alias-relate or whatever. Removing this hack helper fn because rust-lang#119106 is the general solution. r? lcnr
Rollup merge of rust-lang#120037 - compiler-errors:remove-next-root-var-helper, r=lcnr Remove `next_root_ty_var` Uhh we seem to not have any test that relies on this anymore. Maybe due to the way we changed alias-relate or whatever. Removing this hack helper fn because rust-lang#119106 is the general solution. r? lcnr
01ec1ab
to
213a42f
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
eabd1a6
to
feff26b
Compare
Some changes occurred to the core trait solver cc @rust-lang/initiative-trait-system-refactor Type relation code was changed |
feff26b
to
c683cac
Compare
9733e7a
to
1c264ca
Compare
@bors r+ rollup=never (seems liable to conflict with stuff) |
☀️ Test successful - checks-actions |
Finished benchmarking commit (b8de591): comparison URL. Overall result: no relevant changes - no action needed@rustbot label: -perf-regression Instruction countThis benchmark run did not return any relevant results for this metric. Max RSS (memory usage)ResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
Binary sizeThis benchmark run did not return any relevant results for this metric. Bootstrap: 653.235s -> 649.794s (-0.53%) |
…e, r=lcnr Process alias-relate obligations in CoerceUnsized loop After rust-lang#119106, we now emit `AliasRelate` goals when relating `?0` and `Alias<T, ..>` in the new solver. In the ad-hoc `CoerceUnsized` selection loop, we now may have `AliasRelate` goals which must be processed to constrain type variables which are mentioned in other goals. --- For example, in the included test, we try to coerce `&<ManuallyDrop<T> as Deref>::Target` to `&dyn Foo`. This requires proving: * 1 `&<ManuallyDrop<T> as Deref>::Target: CoerceUnsized<&dyn Foo>` * 2 `<ManuallyDrop<T> as Deref>::Target alias-relate ?0` * 3 `?0: Unsize<dyn Foo>` * 4 `?0: Foo` * 5 `?0: Sized` If we don't process goal (2.) before processing goal (3.), then we hit ambiguity since `?0` is never constrained, and therefore we bail out, refusing to coerce the types. After processing (2.), we know `?0 := T`, and the rest of the goals can be processed normally.
…e, r=lcnr Process alias-relate obligations in CoerceUnsized loop After rust-lang#119106, we now emit `AliasRelate` goals when relating `?0` and `Alias<T, ..>` in the new solver. In the ad-hoc `CoerceUnsized` selection loop, we now may have `AliasRelate` goals which must be processed to constrain type variables which are mentioned in other goals. --- For example, in the included test, we try to coerce `&<ManuallyDrop<T> as Deref>::Target` to `&dyn Foo`. This requires proving: * 1 `&<ManuallyDrop<T> as Deref>::Target: CoerceUnsized<&dyn Foo>` * 2 `<ManuallyDrop<T> as Deref>::Target alias-relate ?0` * 3 `?0: Unsize<dyn Foo>` * 4 `?0: Foo` * 5 `?0: Sized` If we don't process goal (2.) before processing goal (3.), then we hit ambiguity since `?0` is never constrained, and therefore we bail out, refusing to coerce the types. After processing (2.), we know `?0 := T`, and the rest of the goals can be processed normally.
Rollup merge of rust-lang#121702 - compiler-errors:coerce-alias-relate, r=lcnr Process alias-relate obligations in CoerceUnsized loop After rust-lang#119106, we now emit `AliasRelate` goals when relating `?0` and `Alias<T, ..>` in the new solver. In the ad-hoc `CoerceUnsized` selection loop, we now may have `AliasRelate` goals which must be processed to constrain type variables which are mentioned in other goals. --- For example, in the included test, we try to coerce `&<ManuallyDrop<T> as Deref>::Target` to `&dyn Foo`. This requires proving: * 1 `&<ManuallyDrop<T> as Deref>::Target: CoerceUnsized<&dyn Foo>` * 2 `<ManuallyDrop<T> as Deref>::Target alias-relate ?0` * 3 `?0: Unsize<dyn Foo>` * 4 `?0: Foo` * 5 `?0: Sized` If we don't process goal (2.) before processing goal (3.), then we hit ambiguity since `?0` is never constrained, and therefore we bail out, refusing to coerce the types. After processing (2.), we know `?0 := T`, and the rest of the goals can be processed normally.
The basic idea of this PR is that we don't generalize aliases when the instantiation could fail later on, either due to the occurs check or because of a universe error. We instead replace the whole alias with an inference variable and emit a nested
AliasRelate
goal. ThisAliasRelate
then fully normalizes the alias before equating it with the inference variable, at which point the alias can be treated like any other rigid type.We now treat aliases differently depending on whether they are rigid or not. To detect whether an alias is rigid we check whether
NormalizesTo
fails. While we already do so inside ofAliasRelate
anyways, also doing so when instantiating a query response would be both ugly/difficult and likely inefficient. To avoid that I changeinstantiate_and_apply_query_response
to relate types completely structurally. This change generally removes a lot of annoying complexity, which is nice. It's implemented by adding a flag toEquate
to change it to structurally handle aliases.We currently always apply constraints from canonical queries right away. By providing all the necessary information to the canonical query, we can guarantee that instantiating the query response never fails, which further simplifies the implementation. This does add the invariant that any information which could cause instantiating type variables to fail must also be available inside of the query.
While it's acceptable for canonicalization to result in more ambiguity, we must not cause the solver to incompletely structurally relate aliases by erasing information. This means we have to be careful when merging universes during canonicalization. As we only generalize for type and const variables we have to make sure that anything nameable by such a type or const variable inside of the canonical query is also nameable outside of it. Because of this we both stop merging universes of existential variables when canonicalizing inputs, we put all uniquified regions into a higher universe which is not nameable by any type or const variable.
I will look into always replacing aliases with inference variables when generalizing in a later PR unless the alias references bound variables. This should both pretty much fix rust-lang/trait-system-refactor-initiative#4. This may allow us to merge the universes of existential variables again by changing generalize to not consider their universe when deciding whether to generalize aliases. This requires some additional non-trivial changes to alias-relate, so I am leaving that as future work.
Fixes rust-lang/trait-system-refactor-initiative#79. While it would be nice to decrement universe indices when existing a
forall
, that was surprisingly difficult and not necessary to fix this issue. I am really happy with the approach in this PR think it is the correct way forward to also fix the remaining cases of rust-lang/trait-system-refactor-initiative#8.