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

avoid generalization inside of aliases #119106

Merged
merged 6 commits into from
Feb 26, 2024
Merged

Conversation

lcnr
Copy link
Contributor

@lcnr lcnr commented Dec 19, 2023

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. This AliasRelate 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 of AliasRelate anyways, also doing so when instantiating a query response would be both ugly/difficult and likely inefficient. To avoid that I change instantiate_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 to Equate 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.

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Dec 19, 2023
@rust-log-analyzer

This comment has been minimized.

@compiler-errors
Copy link
Member

gna mark this as author until it's out of draft?

@rustbot author

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Dec 21, 2023
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Jan 17, 2024
…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`
compiler-errors added a commit to compiler-errors/rust that referenced this pull request Jan 17, 2024
…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``
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Jan 17, 2024
…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```
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Jan 18, 2024
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```
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Jan 18, 2024
…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
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Jan 19, 2024
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
@rustbot rustbot added the WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver) label Jan 29, 2024
@lcnr lcnr changed the title [DRAFT] add a generalizer hack in new solver for reasons do not create fresh infer vars when generalizing aliases Jan 29, 2024
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@lcnr lcnr force-pushed the decrement-universes branch 3 times, most recently from eabd1a6 to feff26b Compare February 2, 2024 12:56
@lcnr lcnr marked this pull request as ready for review February 2, 2024 12:58
@rustbot
Copy link
Collaborator

rustbot commented Feb 2, 2024

Some changes occurred to the core trait solver

cc @rust-lang/initiative-trait-system-refactor

Type relation code was changed

cc @compiler-errors, @lcnr

@lcnr lcnr changed the title do not create fresh infer vars when generalizing aliases avoid generalization inside of aliases Feb 2, 2024
@BoxyUwU
Copy link
Member

BoxyUwU commented Feb 26, 2024

@bors r+ rollup=never (seems liable to conflict with stuff)

@bors
Copy link
Contributor

bors commented Feb 26, 2024

📌 Commit 3b3514a has been approved by BoxyUwU

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Feb 26, 2024
@bors
Copy link
Contributor

bors commented Feb 26, 2024

⌛ Testing commit 3b3514a with merge b8de591...

@bors
Copy link
Contributor

bors commented Feb 26, 2024

☀️ Test successful - checks-actions
Approved by: BoxyUwU
Pushing b8de591 to master...

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (b8de591): comparison URL.

Overall result: no relevant changes - no action needed

@rustbot label: -perf-regression

Instruction count

This benchmark run did not return any relevant results for this metric.

Max RSS (memory usage)

Results

This 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.

mean range count
Regressions ❌
(primary)
4.1% [4.1%, 4.1%] 1
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-3.7% [-4.2%, -3.2%] 2
All ❌✅ (primary) 4.1% [4.1%, 4.1%] 1

Cycles

Results

This 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.

mean range count
Regressions ❌
(primary)
2.0% [2.0%, 2.0%] 1
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 2.0% [2.0%, 2.0%] 1

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 653.235s -> 649.794s (-0.53%)
Artifact size: 311.20 MiB -> 311.12 MiB (-0.03%)

GuillaumeGomez added a commit to GuillaumeGomez/rust that referenced this pull request Feb 28, 2024
…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.
GuillaumeGomez added a commit to GuillaumeGomez/rust that referenced this pull request Feb 28, 2024
…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.
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Feb 28, 2024
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver)
Projects
None yet
7 participants