Fix ICE in next-solver TransmuteFrom candidate
Treat TransmuteFrom goals with non-region inference variables as ambiguous before running transmutability, matching the old solver.
Closesrust-lang/rust#153370 .
Treat TransmuteFrom goals with non-region inference variables as ambiguous before running transmutability, instead of computing layouts for unresolved types. The old solver already treated these goals as ambiguous, so only the next solver could hit this ICE.
`FindParamInClause` handle edge-cases
If normalization is ambiguous, we want to treat the where-bound as non-global. The affected code should pretty much always have other errors in that case. It does make reasoning about trait solver cycles and rerunning more confusing and just feels wrong ™️ I encountered this while looking into `ml-kem` (https://github.com/rust-lang/trait-system-refactor-initiative/issues/246). I don't know whether this matters in practice and don't care to look into it too deeply.
We also want to properly handle concrete aliases which mention to something mentioning a generic parameter due to another where-bound.
r? @BoxyUwU
BikeshedGuaranteedNoDrop trait: add comments indicating that it can be observed on stable
Not sure if that's worth it, maybe this goes without saying for all these builtin traits?
This is meant to be the interim successor to generic const expressions.
Essentially, const item RHS's will be allowed to do arbitrary const
operations using generics. The limitation is that these const items will
be treated opaquely, like ADTs in nominal typing, such that uses of them
will only be equal if the same const item is referenced. In other words,
two const items with the exact same RHS will not be considered equal.
I also added some logic to check feature gates that depend on others
being enabled (like oGCA depending on mGCA).
= Coherence =
During coherence, OGCA consts should be normalized ambiguously because
they are opaque but eventually resolved to a real value. We don't want
two OGCAs that have the same value to be treated as distinct for
coherence purposes. (Just like opaque types.)
This actually doesn't work yet because there are pre-existing
fundamental issues with equate relations involving consts that need to
be normalized. The problem is that we normalize only one layer of the
const item and don't actually process the resulting anon const. Normally
the created inference variable should be handled, which in this case
would cause us to hit the anon const, but that's not happening.
Specifically, `visit_const` on `Generalizer` should be updated to be
similar to `visit_ty`.
Replace `#[rustc_do_not_implement_via_object]` with `#[rustc_dyn_incompatible_trait]`
Background: `#[rustc_do_not_implement_via_object]` on a trait currently still allows `dyn Trait` to exist (if the trait is otherwise dyn-compatible), it just means that `dyn Trait` does not automatically implement `Trait` via the normal object candidate. For some traits, this means that `dyn Trait` does not implement `Trait` at all (e.g. `Unsize` and `Tuple`). For some traits, this means that `dyn Trait` implements `Trait`, but with different associated types (e.g. `Pointee`, `DiscriminantKind`). Both of these cases can can cause issues with codegen , as seen in https://github.com/rust-lang/rust/issues/148089 (and https://github.com/rust-lang/rust/issues/148089#issuecomment-3447803823 ), because codegen assumes that if `dyn Trait` does not implement `Trait` (including if `dyn Trait<Assoc = T>` does not implement `Trait` with `Assoc == T`), then `dyn Trait` cannot be constructed, so vtable accesses on `dyn Trait` are unreachable, but this is not the case if `dyn Trait` has multiple supertraits: one which is `#[rustc_do_not_implement_via_object]`, and one which we are doing the vtable access to call a method from.
This PR replaces `#[rustc_do_not_implement_via_object]` with `#[rustc_dyn_incompatible_trait]`, which makes the marked trait dyn-incompatible, making `dyn Trait` not well-formed, instead of it being well-formed but not implementing `Trait`. This resolvesrust-lang/rust#148089 by making it not compile.
May fixrust-lang/rust#148615
The traits that are currently marked `#[rustc_do_not_implement_via_object]` are: `Sized`, `MetaSized`, `PointeeSized`, `TransmuteFrom`, `Unsize`, `BikeshedGuaranteedNoDrop`, `DiscriminantKind`, `Destruct`, `Tuple`, `FnPtr`, `Pointee`. Of these:
* `Sized` and `FnPtr` are already not dyn-compatible (`FnPtr: Copy`, which implies `Sized`)
* `MetaSized`
* Removed `#[rustc_do_not_implement_via_object]`. Still dyn-compatible after this change. (Has a special-case in the trait solvers to ignore the object candidate for `dyn MetaSized`, since it `dyn MetaSized: MetSized` comes from the sized candidate that all `dyn Trait` get.)
* `PointeeSized`
* Removed `#[rustc_do_not_implement_via_object]`. It doesn't seem to have been doing anything anyway ([playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=a395626c8bef791b87a2d371777b7841)), since `PointeeSized` is removed before trait solving(?).
* `Pointee`, `DiscriminantKind`, `Unsize`, and `Tuple` being dyn-compatible without having `dyn Trait: Trait` (with same assoc tys) can be observed to cause codegen issues (https://github.com/rust-lang/rust/issues/148089) so should be made dyn-incompatible
* `Destruct`, `TransmuteFrom`, and `BikeshedGuaranteedNoDrop` I'm not sure if would be useful as object types, but they can be relaxed to being dyn-compatible later if it is determined they should be.
-----
<details> <summary> resolved </summary>
Questions before merge:
1. `dyn MetaSized: MetaSized` having both `SizedCandidate` and `ObjectCandidate`
1. I'm not sure if the checks in compiler/rustc_trait_selection/src/traits/project.rs and compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs were "load-bearing" for `MetaSized` (which is the only trait that was previously `#[rustc_do_not_implement_via_object]` that is still dyn-compatible after this change). Is it fine to just remove them? Removing them (as I did in the second commit) doesn't change any UI test results.
3. IIUC, `dyn MetaSized` could get its `MetaSized` implementation in two ways: the object candidate (the normal `dyn Trait: Trait`) that was supressed by `#[rustc_do_not_implement_via_object]`, and the `SizedCandidate` (that all `dyn Trait` get for `dyn Trait: MetaSized`). Given that `MetaSized` has no associated types or methods, is it fine that these both exist now? Or is it better to only have the `SizedCandidate` and leave these checks in (i.e. drop the second commit, and remove the FIXMEs)?
4. Resolved: the trait solvers special-case `dyn MetaSized` to ignore the object candidate in preference to the sizedness candidate (technically the check is for any `is_sizedness_trait`, but only `MetaSized` gets this far (`Sized` is inherently dyn-incompatible, and `dyn PointeeSized` is ill-formed for other reasons)
4. Diagnostics improvements?
1. The diagnostics are kinda bad. If you have a `trait Foo: Pointee {}`, you now get a note that reads like *Foo* "opted out of dyn-compatbility", when really `Pointee` did that.
2. Resolved: can be improved later
<details> <summary>diagnostic example</summary>
```rs
#![feature(ptr_metadata)]
trait C: std::ptr::Pointee {}
fn main() {
let y: &dyn C;
}
```
```rs
error[E0038]: the trait `C` is not dyn compatible
--> c.rs:6:17
|
6 | let y: &dyn C;
| ^ `C` is not dyn compatible
|
note: for a trait to be dyn compatible it needs to allow building a vtable
for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
--> /home/zachary/opt_mount/zachary/Programming/rust-compiler-2/library/core/src/ptr/metadata.rs:57:1
|
57 | #[rustc_dyn_incompatible_trait]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because it opted out of dyn-compatbility
|
::: c.rs:3:7
|
3 | trait C: std::ptr::Pointee {}
| - this trait is not dyn compatible...
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0038`.
```
</details> </details>
Still investigating "3. `compiler/rustc_hir/src/attrs/encode_cross_crate.rs`: Should `DynIncompatibleTrait` attribute be encoded cross crate?"
Removes the attribute from `MetaSized` and `PointeeSized`, with a special case in the trait solvers for `MetaSized`.
`dyn MetaSized` is a perfectly cromulent type, and seems to only have had #[rustc_do_not_implement_via_object] so the builtin object
candidate does not overlap with the builtin MetaSized impl that all `dyn` types get.
Resolves this with a special case by checking `is_sizedness_trait` where the trait solvers previously checked `implement_via_object`.
`dyn PointeeSized` alone is rejected for other reasons (since `dyn PointeeSized` is considered to have no principal trait because `PointeeSized`
is removed at an earlier stage of the compiler), but `(dyn PointeeSized + Send)` is valid and equivalent to `dyn Send`.
Add suggestions from code review
Update compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs and tests
Co-authored-by: lcnr <rust@lcnr.de>
Optimize canonicalizer flag checks.
The most important change here relates to type folding: we now check the flags up front, instead of doing it in `inner_fold_ty` after checking the cache and doing a match. This is a small perf win, and matches other similar folders (e.g. `CanonicalInstantiator`).
Likewise for const folding, we now check the flags first. (There is no cache for const folding.)
Elsewhere we don't check flags before folding a predicate (unnecessary, because `fold_predicate` already checks the flags itself before doing anything else), and invert the flag checks in a couple of methods to match the standard order.
r? @lcnr
- Remove the vacuous `Types`, which provides extremely little value.
- Make sure `src` comes before `dst` in all transmute-related functions.
(Currently it's a mix: sometimes `src` is first, sometimes it is
second`.)
The most important change here relates to type folding: we now check the
flags up front, instead of doing it in `inner_fold_ty` after checking
the cache and doing a match. This is a small perf win, and matches other
similar folders (e.g. `CanonicalInstantiator`).
Likewise for const folding, we now check the flags first. (There is no
cache for const folding.)
Elsewhere we don't check flags before folding a predicate (unnecessary,
because `fold_predicate` already checks the flags itself before doing
anything else), and invert the flag checks in a couple of methods to
match the standard order.