-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
improve normalization of Pointee::Metadata
#120354
Conversation
r? @b-naber (rustbot has picked a reviewer for you, use r? to override) |
Some changes occurred to the CTFE / Miri engine cc @rust-lang/miri |
r? types |
3501908
to
e580ae6
Compare
The Miri subtree was changed cc @rust-lang/miri |
Some changes occurred to the core trait solver cc @rust-lang/initiative-trait-system-refactor |
138d7e8
to
469f0b8
Compare
miri: normalize struct tail in ABI compat check fixes #3282 extracted from rust-lang/rust#120354, see rust-lang/rust#120354 (comment) for context r? ```@RalfJung```
Neither am I. We already had that impl where we check for Pretty much what happens here is that if there's a We hackily reimplemented a super trait bound: @lukas-code would you like to change it to a super trait right away or should we leave it to a future PR? If you want to not do so rn, please add a |
Making |
To answer the question of what breaks, it's this test: (in both solvers) rust/tests/ui/sized/recursive-type-pass.rs Lines 1 to 10 in 4a2fe44
But that's probably fine, because that test compiling at all seems more like a side-effect of But there are also a ton of diagnostics regressions, mostly complaining about "type mismatch resolving @rustbot ready |
thanks for your good work and for staying with me while I tried to figure this out myself ❤️ @bors r+ |
…iaskrgr Rollup of 11 pull requests Successful merges: - rust-lang#120351 (Implement SystemTime for UEFI) - rust-lang#120354 (improve normalization of `Pointee::Metadata`) - rust-lang#120776 (Move path implementations into `sys`) - rust-lang#120790 (better error message on download CI LLVM failure) - rust-lang#120806 (Clippy subtree update) - rust-lang#120815 (Improve `Option::inspect` docs) - rust-lang#120822 (Emit more specific diagnostics when enums fail to cast with `as`) - rust-lang#120827 (Print image input file and checksum in CI only) - rust-lang#120836 (hide impls if trait bound is proven from env) - rust-lang#120844 (Build DebugInfo for async closures) - rust-lang#120851 (Remove duplicate release note) r? `@ghost` `@rustbot` modify labels: rollup
…iaskrgr Rollup of 11 pull requests Successful merges: - rust-lang#120351 (Implement SystemTime for UEFI) - rust-lang#120354 (improve normalization of `Pointee::Metadata`) - rust-lang#120776 (Move path implementations into `sys`) - rust-lang#120790 (better error message on download CI LLVM failure) - rust-lang#120806 (Clippy subtree update) - rust-lang#120815 (Improve `Option::inspect` docs) - rust-lang#120822 (Emit more specific diagnostics when enums fail to cast with `as`) - rust-lang#120827 (Print image input file and checksum in CI only) - rust-lang#120836 (hide impls if trait bound is proven from env) - rust-lang#120844 (Build DebugInfo for async closures) - rust-lang#120851 (Remove duplicate release note) r? `@ghost` `@rustbot` modify labels: rollup
Rollup merge of rust-lang#120354 - lukas-code:metadata-normalize, r=lcnr improve normalization of `Pointee::Metadata` This PR makes it so that `<Wrapper<Tail> as Pointee>::Metadata` is normalized to `<Tail as Pointee>::Metadata` if we don't know `Wrapper<Tail>: Sized`. With that, the trait solver can prove projection predicates like `<Wrapper<Tail> as Pointee>::Metadata == <Tail as Pointee>::Metadata`, which makes it possible to use the metadata APIs to cast between the tail and the wrapper: ```rust #![feature(ptr_metadata)] use std::ptr::{self, Pointee}; fn cast_same_meta<T: ?Sized, U: ?Sized>(ptr: *const T) -> *const U where T: Pointee<Metadata = <U as Pointee>::Metadata>, { let (thin, meta) = ptr.to_raw_parts(); ptr::from_raw_parts(thin, meta) } struct Wrapper<T: ?Sized>(T); fn cast_to_wrapper<T: ?Sized>(ptr: *const T) -> *const Wrapper<T> { cast_same_meta(ptr) } ``` Previously, this failed to compile: ``` error[E0271]: type mismatch resolving `<Wrapper<T> as Pointee>::Metadata == <T as Pointee>::Metadata` --> src/lib.rs:16:5 | 15 | fn cast_to_wrapper<T: ?Sized>(ptr: *const T) -> *const Wrapper<T> { | - found this type parameter 16 | cast_same_meta(ptr) | ^^^^^^^^^^^^^^ expected `Wrapper<T>`, found type parameter `T` | = note: expected associated type `<Wrapper<T> as Pointee>::Metadata` found associated type `<T as Pointee>::Metadata` = note: an associated type was expected, but a different one was found ``` (Yes, you can already do this with `as` casts. But using functions is so much :sparkles: *safer* :sparkles:, because you can't change the metadata on accident.) --- This PR essentially changes the built-in impls of `Pointee` from this: ```rust // before impl Pointee for u8 { type Metadata = (); } impl Pointee for [u8] { type Metadata = usize; } // ... impl Pointee for Wrapper<u8> { type Metadata = (); } impl Pointee for Wrapper<[u8]> { type Metadata = usize; } // ... // This impl is only selected if `T` is a type parameter or unnormalizable projection or opaque type. fallback impl<T: ?Sized> Pointee for Wrapper<T> where Wrapper<T>: Sized { type Metadata = (); } // This impl is only selected if `T` is a type parameter or unnormalizable projection or opaque type. fallback impl<T /*: Sized */> Pointee for T { type Metadata = (); } ``` to this: ```rust // after impl Pointee for u8 { type Metadata = (); } impl Pointee for [u8] { type Metadata = usize; } // ... impl<T: ?Sized> Pointee for Wrapper<T> { // in the old solver this will instead project to the "deep" tail directly, // e.g. `Wrapper<Wrapper<T>>::Metadata = T::Metadata` type Metadata = <T as Pointee>::Metadata; } // ... // This impl is only selected if `T` is a type parameter or unnormalizable projection or opaque type. fallback impl<T /*: Sized */> Pointee for T { type Metadata = (); } ```
…r-projections, r=lcnr silence mismatched types errors for implied projections Currently, if a trait bound is not satisfied, then we suppress any errors for the trait's supertraits not being satisfied, but still report errors for super projections not being satisfied. For example: ```rust trait Super { type Assoc; } trait Sub: Super<Assoc = ()> {} ``` Before this PR, if `T: Sub` is not satisfied, then errors for `T: Super` are suppressed, but errors for `<T as Super>::Assoc == ()` are still shown. This PR makes it so that errors about super projections not being satisfied are also suppressed. The errors are only suppressed if the span of the trait obligation matches the span of the super predicate obligation to avoid silencing error that are not related. This PR removes some differences between the spans of supertraits and super projections to make the suppression work correctly. This PR fixes the majority of the diagnostics fallout when making `Thin` a supertrait of `Sized` (in a future PR). cc rust-lang#120354 (comment) cc `@lcnr`
Rollup merge of rust-lang#121863 - lukas-code:silence-mismatched-super-projections, r=lcnr silence mismatched types errors for implied projections Currently, if a trait bound is not satisfied, then we suppress any errors for the trait's supertraits not being satisfied, but still report errors for super projections not being satisfied. For example: ```rust trait Super { type Assoc; } trait Sub: Super<Assoc = ()> {} ``` Before this PR, if `T: Sub` is not satisfied, then errors for `T: Super` are suppressed, but errors for `<T as Super>::Assoc == ()` are still shown. This PR makes it so that errors about super projections not being satisfied are also suppressed. The errors are only suppressed if the span of the trait obligation matches the span of the super predicate obligation to avoid silencing error that are not related. This PR removes some differences between the spans of supertraits and super projections to make the suppression work correctly. This PR fixes the majority of the diagnostics fallout when making `Thin` a supertrait of `Sized` (in a future PR). cc rust-lang#120354 (comment) cc `@lcnr`
…ions, r=lcnr silence mismatched types errors for implied projections Currently, if a trait bound is not satisfied, then we suppress any errors for the trait's supertraits not being satisfied, but still report errors for super projections not being satisfied. For example: ```rust trait Super { type Assoc; } trait Sub: Super<Assoc = ()> {} ``` Before this PR, if `T: Sub` is not satisfied, then errors for `T: Super` are suppressed, but errors for `<T as Super>::Assoc == ()` are still shown. This PR makes it so that errors about super projections not being satisfied are also suppressed. The errors are only suppressed if the span of the trait obligation matches the span of the super predicate obligation to avoid silencing error that are not related. This PR removes some differences between the spans of supertraits and super projections to make the suppression work correctly. This PR fixes the majority of the diagnostics fallout when making `Thin` a supertrait of `Sized` (in a future PR). cc rust-lang/rust#120354 (comment) cc `@lcnr`
make `Thin` a supertrait of `Sized` This is a follow-up to rust-lang#120354 to address rust-lang#120354 (comment) and remove the "fallback impl" hack from `<T as Pointee>::Metadata` normalization in both trait solvers. We make `Thin` and therefore `Pointee<Metadata = ()>` a supertrait of `Sized`, such that every (implicit or explicit) `T: Sized` bound now also requires `T: Thin` and `<T as Pointee>::Metadata == ()`. These new bounds will be used when normalizing `<T as Pointee>::Metadata` instead of a hacky builtin impl that only applies for type parameters and aliases and overlaps with other builtin impls. Note that [RFC 2580](https://rust-lang.github.io/rfcs/2580-ptr-meta.html), which introduced `Pointee` and `Thin`, lists these unresolved questions: > Should `Thin` be added as a supertrait of `Sized`? Or could it ever make sense to have fat pointers to statically-sized types? For now, they are answered with yes and no respectively. If we end up deciding that we do want types that are `Sized + !Thin`, then a possible alternative is to add make `Thin` a defaulted trait bound that can be relaxed with `T: ?Thin` and remove `Thin` as supertrait from `Sized` before the stabilization of `feature(ptr_metadata)`. --- The removal of the "fallback impl" also allows us to always project to the shallow struct tail in the old solver, making the implementation in the old solver almost identical to the new solver. This is required to make `<Wrapper<T> as Pointee>::Metadata` work correctly in the presence of trivial bounds, for example if we know `[T]: Thin`, then we should also know `Wrapper<T>: Thin`. Lastly, this PR implements some diagnostics changes to hide errors about `` type mismatch resolving `<T as Pointee>::Metadata == ()` `` when the actual error comes from `T: Sized`. This is a continuation of rust-lang#121863. r? `@lcnr`
This PR makes it so that
<Wrapper<Tail> as Pointee>::Metadata
is normalized to<Tail as Pointee>::Metadata
if we don't knowWrapper<Tail>: Sized
. With that, the trait solver can prove projection predicates like<Wrapper<Tail> as Pointee>::Metadata == <Tail as Pointee>::Metadata
, which makes it possible to use the metadata APIs to cast between the tail and the wrapper:Previously, this failed to compile:
(Yes, you can already do this with
as
casts. But using functions is so much ✨ safer ✨, because you can't change the metadata on accident.)This PR essentially changes the built-in impls of
Pointee
from this:to this: