forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rollup merge of rust-lang#122804 - compiler-errors:item-bounds-can-re…
…ference-self, r=BoxyUwU Item bounds can reference self projections and still be object safe ### Background Currently, we have some interesting rules about where `Self` is allowed to be mentioned in objects. Specifically, we allow mentioning `Self` behind associated types (e.g. `fn foo(&self) -> Self::Assoc`) only if that `Self` type comes from the trait we're defining or its supertraits: ``` trait Foo { fn good() -> Self::Assoc; // GOOD :) fn bad() -> <Self as OtherTrait>::Assoc; // BAD! } ``` And more specifically, these `Self::Assoc` projections are *only* allowed to show up in: * (A1) Method signatures * (A2) Where clauses on traits, GATs and methods But `Self::Assoc` projections are **not** allowed to show up in: * (B1) Supertrait bounds (specifically: all *super-predicates*, which includes the projections that come from elaboration, and not just the traits themselves). * (B2) Item bounds of associated types The reason for (B1) is interesting: specifically, it arises from the fact that we currently eagerly elaborate all projection predicates into the object, so if we had the following code: ``` trait Sub<Assoc = Self::SuperAssoc> {} trait Super { type SuperAssoc; } ``` Then given `dyn Sub<SuperAssoc = i32>` we would need to have a type that is substituted into itself an infinite number of times[^1], like `dyn Sub<SuperAssoc = i32, Assoc = <dyn Sub<SuperAssoc = i32, Assoc = <dyn Sub<SuperAssoc = i32, Assoc = <... as Super>::SuperAssoc> as Super>::SuperAssoc> as Super>::SuperAssoc>`, i.e. the fixed-point of: `type T = dyn Sub<SuperAssoc = i32, Assoc = <T as Super>::SuperAssoc>`. Similarly for (B2), we restrict mentioning `Self::Assoc` in associated type item bounds, which is the cause for rust-lang#122798. However, there is **no reason** for us to do so, since item bounds never show up structurally in the `dyn Trait` object type. #### What? This PR relaxes the check for item bounds so that `Self` may be mentioned behind associated types in the same cases that they currently work for method signatures (A1) and where clauses (A2). #### Why? Fixes rust-lang#122798. Removes a subtle and confusing inconsistency for the code mentioned in that issue. This is sound because we only assemble alias bounds for rigid projections, and all projections coming from an object self type are not rigid, since all associated types should be specified by the type. This is also desirable because we can do this via supertraits already. In rust-lang#122789, it is noted that an item bound of `Eq` already works, just not `PartialEq` because of the default item bound. This is weird and should be fixed. #### Future work We could make the check for `Self` in super-predicates more sophisticated as well, only erroring if `Self` shows up in a projection super-predicate. [^1]: This could be fixed by some sort of structural replacement or eager normalization, but I don't think it's necessary currently.
- Loading branch information
Showing
2 changed files
with
91 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
//@ check-pass | ||
|
||
pub trait Foo { | ||
type X: PartialEq; | ||
type Y: PartialEq<Self::Y>; | ||
type Z: PartialEq<Self::Y>; | ||
} | ||
|
||
fn uwu(x: &dyn Foo<X = i32, Y = i32, Z = i32>) {} | ||
|
||
fn main() {} |