- 
                Notifications
    You must be signed in to change notification settings 
- Fork 13.9k
avoid generalization inside of aliases #119106
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
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
AliasRelategoal. ThisAliasRelatethen 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
NormalizesTofails. While we already do so inside ofAliasRelateanyways, also doing so when instantiating a query response would be both ugly/difficult and likely inefficient. To avoid that I changeinstantiate_and_apply_query_responseto relate types completely structurally. This change generally removes a lot of annoying complexity, which is nice. It's implemented by adding a flag toEquateto 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.