When a `?` operation requires an `Into` conversion with additional bounds (like having a concrete error but wanting to convert to a trait object), we handle it speficically and provide the same kind of information we give other `?` related errors.
```
error[E0277]: `?` couldn't convert the error: `E: std::error::Error` is not satisfied
--> $DIR/bad-question-mark-on-trait-object.rs:5:13
|
LL | fn foo() -> Result<(), Box<dyn std::error::Error>> {
| -------------------------------------- required `E: std::error::Error` because of this
LL | Ok(bar()?)
| ^ the trait `std::error::Error` is not implemented for `E`
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= note: required for `Box<dyn std::error::Error>` to implement `From<E>`
```
Avoid talking about `FromResidual` when other more relevant information is being given, particularly from `rust_on_unimplemented`.
Register `USAGE_OF_TYPE_IR_INHERENT`, remove inherent usages
I implemented a lint to discourage the usage of `rustc_type_ir::inherent` but never actually enabled it. People started using `rustc_type_ir::inherent` methods through globs, lol.
r? fmease or reassign as you please
Make fewer crates depend on `rustc_ast_ir`
I think it simplifies the crate graph and also exposes people less to confusion if downstream crates don't interact with `rustc_ast_ir` directly and instead just use its functionality reexported through more familiar paths.
r? oli-obk since you introduced ast-ir
Don't mention `FromResidual` on bad `?`
Unless `try_trait_v2` is enabled, don't mention that `FromResidual` isn't implemented for a specific type when the implicit `From` conversion of a `?` fails. For the end user on stable, `?` might as well be a compiler intrinsic, so we remove that note to avoid further confusion and allowing other parts of the error to be more prominent.
```
error[E0277]: `?` couldn't convert the error to `u8`
--> $DIR/bad-interconversion.rs:4:20
|
LL | fn result_to_result() -> Result<u64, u8> {
| --------------- expected `u8` because of this
LL | Ok(Err(123_i32)?)
| ------------^ the trait `From<i32>` is not implemented for `u8`
| |
| this can't be annotated with `?` because it has type `Result<_, i32>`
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= help: the following other types implement trait `From<T>`:
`u8` implements `From<Char>`
`u8` implements `From<bool>`
```
Emit dropck normalization errors in borrowck
Borrowck generally assumes that any queries it runs for type checking will succeed, thinking that HIR typeck will have errored first if there was a problem. However as of #98641, dropck isn't run on HIR, so there's no direct guarantee that it doesn't error. While a type being well-formed might be expected to ensure that its fields are well-formed, this is not the case for types containing a type projection:
```rust
pub trait AuthUser {
type Id;
}
pub trait AuthnBackend {
type User: AuthUser;
}
pub struct AuthSession<Backend: AuthnBackend> {
data: Option<<<Backend as AuthnBackend>::User as AuthUser>::Id>,
}
pub trait Authz: Sized {
type AuthnBackend: AuthnBackend<User = Self>;
}
pub fn run_query<User: Authz>(auth: AuthSession<User::AuthnBackend>) {}
// ^ No User: AuthUser bound is required or inferred.
```
While improvements to trait solving might fix this in the future, for now we go for a pragmatic solution of emitting an error from borrowck (by rerunning dropck outside of a query) and making drop elaboration check if an error has been emitted previously before panicking for a failed normalization.
Closes#103899Closes#135039
r? `@compiler-errors` (feel free to re-assign)
Unless `try_trait_v2` is enabled, don't mention that `FromResidual` isn't implemented for a specific type when the implicit `From` conversion of a `?` fails. For the end user on stable, `?` might as well be a compiler intrinsic, so we remove that note to avoid further confusion and allowing other parts of the error to be more prominent.
```
error[E0277]: `?` couldn't convert the error to `u8`
--> $DIR/bad-interconversion.rs:4:20
|
LL | fn result_to_result() -> Result<u64, u8> {
| --------------- expected `u8` because of this
LL | Ok(Err(123_i32)?)
| ------------^ the trait `From<i32>` is not implemented for `u8`
| |
| this can't be annotated with `?` because it has type `Result<_, i32>`
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= help: the following other types implement trait `From<T>`:
`u8` implements `From<Char>`
`u8` implements `From<bool>`
```
Continuing the work started in #136466.
Every method gains a `hir_` prefix, though for the ones that already
have a `par_` or `try_par_` prefix I added the `hir_` after that.
HIR type checking no longer runs dropck, so we may get new errors when
we run it in borrowck. If this happens then rerun the query in a local
infcx and report errors for it.
First of all, note that `Map` has three different relevant meanings.
- The `intravisit::Map` trait.
- The `map::Map` struct.
- The `NestedFilter::Map` associated type.
The `intravisit::Map` trait is impl'd twice.
- For `!`, where the methods are all unreachable.
- For `map::Map`, which gets HIR stuff from the `TyCtxt`.
As part of getting rid of `map::Map`, this commit changes `impl
intravisit::Map for map::Map` to `impl intravisit::Map for TyCtxt`. It's
fairly straightforward except various things are renamed, because the
existing names would no longer have made sense.
- `trait intravisit::Map` becomes `trait intravisit::HirTyCtxt`, so named
because it gets some HIR stuff from a `TyCtxt`.
- `NestedFilter::Map` assoc type becomes `NestedFilter::MaybeTyCtxt`,
because it's always `!` or `TyCtxt`.
- `Visitor::nested_visit_map` becomes `Visitor::maybe_tcx`.
I deliberately made the new trait and associated type names different to
avoid the old `type Map: Map` situation, which I found confusing. We now
have `type MaybeTyCtxt: HirTyCtxt`.
The end goal is to eliminate `Map` altogether.
I added a `hir_` prefix to all of them, that seemed simplest. The
exceptions are `module_items` which became `hir_module_free_items` because
there was already a `hir_module_items`, and `items` which became
`hir_free_items` for consistency with `hir_module_free_items`.
Rollup of 8 pull requests
Successful merges:
- #135549 (Document some safety constraints and use more safe wrappers)
- #135965 (In "specify type" suggestion, skip type params that are already known)
- #136193 (Implement pattern type ffi checks)
- #136646 (Add a TyPat in the AST to reuse the generic arg lowering logic)
- #136874 (Change the issue number for `likely_unlikely` and `cold_path`)
- #136884 (Lower fn items as ZST valtrees and delay a bug)
- #136885 (i686-linux-android: increase CPU baseline to Pentium 4 (without an actual change)
- #136891 (Check sig for errors before checking for unconstrained anonymous lifetime)
r? `@ghost`
`@rustbot` modify labels: rollup
In "specify type" suggestion, skip type params that are already known
When we suggest specifying a type for an expression or pattern, like in a `let` binding, we previously would print the entire type as the type system knew it. We now look at the params that have *no* inference variables, so they are fully known to the type system which means that they don't need to be specified.
This helps in suggestions for types that are really long, because we can usually skip most of the type params and make the annotation as short as possible:
```
error[E0282]: type annotations needed for `Result<_, ((..., ..., ..., ...), ..., ..., ...)>`
--> $DIR/really-long-type-in-let-binding-without-sufficient-type-info.rs:7:9
|
LL | let y = Err(x);
| ^ ------ type must be known at this point
|
help: consider giving `y` an explicit type, where the type for type parameter `T` is specified
|
LL | let y: Result<T, _> = Err(x);
| ++++++++++++++
```
Fix#135919.
Prevent generic pattern types from being used in libstd
Pattern types should follow the same rules that patterns follow. So a pattern type range must not wrap and not be empty. While we reject such invalid ranges at layout computation time, that only happens during monomorphization in the case of const generics. This is the exact same issue as other const generic math has, and since there's no solution there yet, I put these pattern types behind a separate incomplete feature.
These are not necessary for the pattern types MVP (replacing the layout range attributes in libcore and rustc).
cc #136574 (new tracking issue for the `generic_pattern_types` feature gate)
r? ``@lcnr``
cc ``@scottmcm`` ``@joshtriplett``
Ensure that we never try to monomorphize the upcasting or vtable calls of impossible dyn types
Check for impossible obligations in the `dyn Trait` type we're trying to compute its the vtable upcasting and method call slots.
r? lcnr
Remove unnecessary layout assertions for object-safe receivers
The soundness of `DispatchFromDyn` relies on the fact that, like all other built-in marker-like layout traits (e.g. `Sized`, `CoerceUnsized`), the guarantees that they enforce in *generic* code via traits will result in assumptions that we can rely on in codegen.
Specifically, `DispatchFromDyn` ensures that we end up with a receiver that is a valid pointer type, and its implementation validity recursively ensures that the ABI of that pointer type upholds the `Scalar` or `ScalarPair` representation for sized and unsized pointees, respectively.
The check that this layout guarantee holds for arbitrary, possibly generic receiver types that also may exist in possibly impossible-to-instantiate where clauses is overkill IMO, and leads to several ICEs due to the fact that computing layouts before monomorphization is going to be fallible at best.
This PR removes the check altogether, since it just exists as a sanity check from very long ago, 6f2a161b1b.
Fixes#125810Fixes#90110
This PR is an alternative to #136195. cc `@adetaylor.` I didn't realize in that PR that the layout checks that were being modified were simply *sanity checks*, rather than being actually necessary for soundness.
When we suggest specifying a type for an expression or pattern, like in a `let` binding, we previously would print the entire type as the type system knew it. We now look at the params that have *no* inference variables, so they are fully known to the type system which means that they don't need to be specified.
This helps in suggestions for types that are really long, because we can usually skip most of the type params and make the annotation as short as possible:
```
error[E0282]: type annotations needed for `Result<_, ((..., ..., ..., ...), ..., ..., ...)>`
--> $DIR/really-long-type-in-let-binding-without-sufficient-type-info.rs:7:9
|
LL | let y = Err(x);
| ^ ------ type must be known at this point
|
help: consider giving `y` an explicit type, where the type for type parameter `T` is specified
|
LL | let y: Result<T, _> = Err(x);
| ++++++++++++++
```
Shorten error message for callable with wrong return type
```
error: expected `{closure@...}` to return `Ret`, but it returns `Other`
```
instead of
```
error: expected `{closure@...}` to be a closure that returns `Ret`, but it returns `Other`
```
Highlight clarifying information in "expected/found" error
When the expected and found types have the same textual representation, we add clarifying in parentheses. We now visually highlight it in the output.
Detect a corner case where the clarifying information would be the same for both types and skip it, as it doesn't add anything useful.

Tweak fn pointer suggestion span
Use a more targeted span when suggesting casting an `fn` item to an `fn` pointer.
```
error[E0308]: cannot coerce functions which must be inlined to function pointers
--> $DIR/cast.rs:10:33
|
LL | let _: fn(isize) -> usize = callee;
| ------------------ ^^^^^^ cannot coerce functions which must be inlined to function pointers
| |
| expected due to this
|
= note: expected fn pointer `fn(_) -> _`
found fn item `fn(_) -> _ {callee}`
= note: fn items are distinct from fn pointers
help: consider casting to a fn pointer
|
LL | let _: fn(isize) -> usize = callee as fn(isize) -> usize;
| +++++++++++++++++++++
```
```
error[E0308]: mismatched types
--> $DIR/fn-pointer-mismatch.rs:42:30
|
LL | let d: &fn(u32) -> u32 = foo;
| --------------- ^^^ expected `&fn(u32) -> u32`, found fn item
| |
| expected due to this
|
= note: expected reference `&fn(_) -> _`
found fn item `fn(_) -> _ {foo}`
help: consider using a reference
|
LL | let d: &fn(u32) -> u32 = &foo;
| +
```
Previously we'd point at the whole expression for replacement, instead of marking what was being added.
We could also modify the suggestions for `&(name as fn())`, but for that we require storing more accurate spans than we have now.
Rework "long type names" printing logic
Make it so more type-system types can be printed in a shortened version (like `Predicate`s).
Centralize printing the information about the "full type name path".
Make the "long type path" for the file where long types are written part of `Diag`, so that it becomes easier to keep track of it, and ensure it will always will be printed out last in the diagnostic by making its addition to the output implicit.
Tweak the shortening of types in "expected/found" labels.
Remove dead file `note.rs`.
Rename `tcx.ensure()` to `tcx.ensure_ok()`, and improve the associated docs
This is all based on my archaeology for https://rust-lang.zulipchat.com/#narrow/channel/182449-t-compiler.2Fhelp/topic/.60TyCtxtEnsure.60.
The main renamings are:
- `tcx.ensure()` → `tcx.ensure_ok()`
- `tcx.ensure_with_value()` → `tcx.ensure_done()`
- Query modifier `ensure_forwards_result_if_red` → `return_result_from_ensure_ok`
Hopefully these new names are a better fit for the *actual* function and purpose of these query call modes.
When the expected and found types have the same textual representation, we add clarifying in parentheses. We now visually highlight it in the output.
Detect a corner case where the clarifying information would be the same for both types and skip it, as it doesn't add anything useful.
```
error: expected `{closure@...}` to return `Ret`, but it returns `Other`
```
instead of
```
error: expected `{closure@...}` to be a closure that returns `Ret`, but it returns `Other`
```
Use a more targeted span when suggesting casting an `fn` item to an `fn` pointer.
```
error[E0308]: cannot coerce functions which must be inlined to function pointers
--> $DIR/cast.rs:10:33
|
LL | let _: fn(isize) -> usize = callee;
| ------------------ ^^^^^^ cannot coerce functions which must be inlined to function pointers
| |
| expected due to this
|
= note: expected fn pointer `fn(_) -> _`
found fn item `fn(_) -> _ {callee}`
= note: fn items are distinct from fn pointers
help: consider casting to a fn pointer
|
LL | let _: fn(isize) -> usize = callee as fn(isize) -> usize;
| +++++++++++++++++++++
```
```
error[E0308]: mismatched types
--> $DIR/fn-pointer-mismatch.rs:42:30
|
LL | let d: &fn(u32) -> u32 = foo;
| --------------- ^^^ expected `&fn(u32) -> u32`, found fn item
| |
| expected due to this
|
= note: expected reference `&fn(_) -> _`
found fn item `fn(_) -> _ {foo}`
help: consider using a reference
|
LL | let d: &fn(u32) -> u32 = &foo;
| +
```
Previously we'd point at the whole expression for replacement, instead of marking what was being added.
We could also modify the suggestions for `&(name as fn())`, but for that we require storing more accurate spans than we have now.
Implement MIR lowering for unsafe binders
This is the final bit of the unsafe binders puzzle. It implements MIR, CTFE, and codegen for unsafe binders, and enforces that (for now) they are `Copy`. Later on, I'll introduce a new trait that relaxes this requirement to being "is `Copy` or `ManuallyDrop<T>`" which more closely models how we treat union fields.
Namely, wrapping unsafe binders is now `Rvalue::WrapUnsafeBinder`, which acts much like an `Rvalue::Aggregate`. Unwrapping unsafe binders are implemented as a MIR projection `ProjectionElem::UnwrapUnsafeBinder`, which acts much like `ProjectionElem::Field`.
Tracking:
- https://github.com/rust-lang/rust/issues/130516
Manually walk into WF obligations in `BestObligation` proof tree visitor
When we encounter a `WellFormed` obligation in the `BestObligation` proof tree visitor, ignore the proof tree and call `wf::unnormalized_obligations` to derive well-formed obligations with the correct cause codes. This is to avoid having to replicate the somewhat delicate logic that `wf.rs` does to set up its obligation causes... Don't see a better way to do this.
vibes?? r? lcnr
Make it so more type-system types can be printed in a shortened version (like `Predicate`s).
Centralize printing the information about the "full type name path".
Make the "long type path" for the file where long types are written part of `Diag`, so that it becomes easier to keep track of it, and ensure it will always will be printed out last in the diagnostic by making its addition to the output implicit.
Tweak the shortening of types in "expected/found" labels.
Remove dead file `note.rs`.
Compiler: Finalize dyn compatibility renaming
Update the Reference link to use the new URL fragment from https://github.com/rust-lang/reference/pull/1666 (this change has finally hit stable). Fixes a FIXME.
Follow-up to #130826.
Part of #130852.
~~Blocking it on #133372.~~ (merged)
r? ghost
When encountering unexpected closure return type, point at return type/expression
```
error[E0271]: expected `{closure@fallback-closure-wrap.rs:18:40}` to be a closure that returns `()`, but it returns `!`
--> $DIR/fallback-closure-wrap.rs:19:9
|
LL | let error = Closure::wrap(Box::new(move || {
| -------
LL | panic!("Can't connect to server.");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `!`
|
= note: expected unit type `()`
found type `!`
= note: required for the cast from `Box<{closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47}>` to `Box<dyn FnMut()>`
```
```
error[E0271]: expected `{closure@dont-ice-for-type-mismatch-in-closure-in-async.rs:6:10}` to be a closure that returns `bool`, but it returns `Option<()>`
--> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:6:16
|
LL | call(|| -> Option<()> {
| ---- ------^^^^^^^^^^
| | |
| | expected `bool`, found `Option<()>`
| required by a bound introduced by this call
|
= note: expected type `bool`
found enum `Option<()>`
note: required by a bound in `call`
--> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:3:25
|
LL | fn call(_: impl Fn() -> bool) {}
| ^^^^ required by this bound in `call`
```
```
error[E0271]: expected `{closure@f670.rs:28:13}` to be a closure that returns `Result<(), _>`, but it returns `!`
--> f670.rs:28:20
|
28 | let c = |e| -> ! {
| -------^
| |
| expected `Result<(), _>`, found `!`
...
32 | f().or_else(c);
| ------- required by a bound introduced by this call
-Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs:1433:28
|
= note: expected enum `Result<(), _>`
found type `!`
note: required by a bound in `Result::<T, E>::or_else`
--> /home/gh-estebank/rust/library/core/src/result.rs:1406:39
|
1406 | pub fn or_else<F, O: FnOnce(E) -> Result<T, F>>(self, op: O) -> Result<T, F> {
| ^^^^^^^^^^^^ required by this bound in `Result::<T, E>::or_else`
```
CC #111539.
Fix deduplication mismatches in vtables leading to upcasting unsoundness
We currently have two cases where subtleties in supertraits can trigger disagreements in the vtable layout, e.g. leading to a different vtable layout being accessed at a callsite compared to what was prepared during unsizing. Namely:
### #135315
In this example, we were not normalizing supertraits when preparing vtables. In the example,
```
trait Supertrait<T> {
fn _print_numbers(&self, mem: &[usize; 100]) {
println!("{mem:?}");
}
}
impl<T> Supertrait<T> for () {}
trait Identity {
type Selff;
}
impl<Selff> Identity for Selff {
type Selff = Selff;
}
trait Middle<T>: Supertrait<()> + Supertrait<T> {
fn say_hello(&self, _: &usize) {
println!("Hello!");
}
}
impl<T> Middle<T> for () {}
trait Trait: Middle<<() as Identity>::Selff> {}
impl Trait for () {}
fn main() {
(&() as &dyn Trait as &dyn Middle<()>).say_hello(&0);
}
```
When we prepare `dyn Trait`, we see a supertrait of `Middle<<() as Identity>::Selff>`, which itself has two supertraits `Supertrait<()>` and `Supertrait<<() as Identity>::Selff>`. These two supertraits are identical, but they are not duplicated because we were using structural equality and *not* considering normalization. This leads to a vtable layout with two trait pointers.
When we upcast to `dyn Middle<()>`, those two supertraits are now the same, leading to a vtable layout with only one trait pointer. This leads to an offset error, and we call the wrong method.
### #135316
This one is a bit more interesting, and is the bulk of the changes in this PR. It's a bit similar, except it uses binder equality instead of normalization to make the compiler get confused about two vtable layouts. In the example,
```
trait Supertrait<T> {
fn _print_numbers(&self, mem: &[usize; 100]) {
println!("{mem:?}");
}
}
impl<T> Supertrait<T> for () {}
trait Trait<T, U>: Supertrait<T> + Supertrait<U> {
fn say_hello(&self, _: &usize) {
println!("Hello!");
}
}
impl<T, U> Trait<T, U> for () {}
fn main() {
(&() as &'static dyn for<'a> Trait<&'static (), &'a ()>
as &'static dyn Trait<&'static (), &'static ()>)
.say_hello(&0);
}
```
When we prepare the vtable for `dyn for<'a> Trait<&'static (), &'a ()>`, we currently consider the PolyTraitRef of the vtable as the key for a supertrait. This leads two two supertraits -- `Supertrait<&'static ()>` and `for<'a> Supertrait<&'a ()>`.
However, we can upcast[^up] without offsetting the vtable from `dyn for<'a> Trait<&'static (), &'a ()>` to `dyn Trait<&'static (), &'static ()>`. This is just instantiating the principal trait ref for a specific `'a = 'static`. However, when considering those supertraits, we now have only one distinct supertrait -- `Supertrait<&'static ()>` (which is deduplicated since there are two supertraits with the same substitutions). This leads to similar offsetting issues, leading to the wrong method being called.
[^up]: I say upcast but this is a cast that is allowed on stable, since it's not changing the vtable at all, just instantiating the binder of the principal trait ref for some lifetime.
The solution here is to recognize that a vtable isn't really meaningfully higher ranked, and to just treat a vtable as corresponding to a `TraitRef` so we can do this deduplication more faithfully. That is to say, the vtable for `dyn for<'a> Tr<'a>` and `dyn Tr<'x>` are always identical, since they both would correspond to a set of free regions on an impl... Do note that `Tr<for<'a> fn(&'a ())>` and `Tr<fn(&'static ())>` are still distinct.
----
There's a bit more that can be cleaned up. In codegen, we can stop using `PolyExistentialTraitRef` basically everywhere. We can also fix SMIR to stop storing `PolyExistentialTraitRef` in its vtable allocations.
As for testing, it's difficult to actually turn this into something that can be tested with `rustc_dump_vtable`, since having multiple supertraits that are identical is a recipe for ambiguity errors. Maybe someone else is more creative with getting that attr to work, since the tests I added being run-pass tests is a bit unsatisfying. Miri also doesn't help here, since it doesn't really generate vtables that are offset by an index in the same way as codegen.
r? `@lcnr` for the vibe check? Or reassign, idk. Maybe let's talk about whether this makes sense.
<sup>(I guess an alternative would also be to not do any deduplication of vtable supertraits (or only a really conservative subset) rather than trying to normalize and deduplicate more faithfully here. Not sure if that works and is sufficient tho.)</sup>
cc `@steffahn` -- ty for the minimizations
cc `@WaffleLapkin` -- since you're overseeing the feature stabilization :3
Fixes#135315Fixes#135316
```
error[E0271]: expected `{closure@return-type-doesnt-match-bound.rs:18:13}` to be a closure that returns `Result<(), _>`, but it returns `!`
--> tests/ui/closures/return-type-doesnt-match-bound.rs:18:20
|
18 | let c = |e| -> ! { //~ ERROR to be a closure that returns
| -------^
| |
| expected `Result<(), _>`, found `!`
...
22 | f().or_else(c);
| ------- -
| |
| required by a bound introduced by this call
|
= note: expected enum `Result<(), _>`
found type `!`
note: required by a bound in `Result::<T, E>::or_else`
--> /home/gh-estebank/rust/library/core/src/result.rs:1406:39
|
1406 | pub fn or_else<F, O: FnOnce(E) -> Result<T, F>>(self, op: O) -> Result<T, F> {
| ^^^^^^^^^^^^ required by this bound in `Result::<T, E>::or_else`
```
```
error[E0271]: expected `{closure@fallback-closure-wrap.rs:18:40}` to be a closure that returns `()`, but it returns `!`
--> $DIR/fallback-closure-wrap.rs:19:9
|
LL | let error = Closure::wrap(Box::new(move || {
| -------
LL | panic!("Can't connect to server.");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `!`
|
= note: expected unit type `()`
found type `!`
= note: required for the cast from `Box<{closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47}>` to `Box<dyn FnMut()>`
```
```
error[E0271]: expected `{closure@dont-ice-for-type-mismatch-in-closure-in-async.rs:6:10}` to be a closure that returns `bool`, but it returns `Option<()>`
--> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:6:16
|
LL | call(|| -> Option<()> {
| ---- ------^^^^^^^^^^
| | |
| | expected `bool`, found `Option<()>`
| required by a bound introduced by this call
|
= note: expected type `bool`
found enum `Option<()>`
note: required by a bound in `call`
--> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:3:25
|
LL | fn call(_: impl Fn() -> bool) {}
| ^^^^ required by this bound in `call`
```
```
error[E0271]: expected `{closure@f670.rs:28:13}` to be a closure that returns `Result<(), _>`, but it returns `!`
--> f670.rs:28:20
|
28 | let c = |e| -> ! {
| -------^
| |
| expected `Result<(), _>`, found `!`
...
32 | f().or_else(c);
| ------- required by a bound introduced by this call
-Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs:1433:28
|
= note: expected enum `Result<(), _>`
found type `!`
note: required by a bound in `Result::<T, E>::or_else`
--> /home/gh-estebank/rust/library/core/src/result.rs:1406:39
|
1406 | pub fn or_else<F, O: FnOnce(E) -> Result<T, F>>(self, op: O) -> Result<T, F> {
| ^^^^^^^^^^^^ required by this bound in `Result::<T, E>::or_else`
```
Simplify and consolidate the way we handle construct `OutlivesEnvironment` for lexical region resolution
This is best reviewed commit-by-commit. I tried to consolidate the API for lexical region resolution *first*, then change the API when it was finally behind a single surface.
r? lcnr or reassign
Properly check that array length is valid type during built-in unsizing in index
This results in duplicated errors, but this class of errors is not new; in general, we aren't really equipped to detect cases where a WF error due to a field type would be shadowed by the parent struct of that field also not being WF.
This also adds a note for these types of mismatches to make it clear that this is due to an array type.
Fixes#134352
r? boxyuwu
Rollup of 7 pull requests
Successful merges:
- #135625 ([cfg_match] Document the use of expressions.)
- #135902 (Do not consider child bound assumptions for rigid alias)
- #135943 (Rename `Piece::String` to `Piece::Lit`)
- #136104 (Add mermaid graphs of NLL regions and SCCs to polonius MIR dump)
- #136143 (Update books)
- #136147 (ABI-required target features: warn when they are missing in base CPU)
- #136164 (Refactor FnKind variant to hold &Fn)
r? `@ghost`
`@rustbot` modify labels: rollup
Rename `Piece::String` to `Piece::Lit`
This renames Piece::String to Piece::Lit to avoid shadowing std::string::String and removes "pub use Piece::*;".
Do not consider child bound assumptions for rigid alias
r? lcnr
See first commit for the important details. For second commit, I also stacked a somewhat opinionated name change, though I can separate that if needed.
Fixes https://github.com/rust-lang/trait-system-refactor-initiative/issues/149
Pass spans to `perform_locally_in_new_solver`
Nothing changes yet, but we may be able to use these spans in the future once we start dealing w the response region constraints better.
r? lcnr
Use identifiers more in diagnostics code
This should make the diagnostics code slightly more correct when rendering idents in mixed crate edition situations. Kinda a no-op, but a cleanup regardless.
r? oli-obk or reassign
Use short type string in E0308 secondary span label
We were previously printing the full type on the "this expression has type" label.
```
error[E0308]: mismatched types
--> $DIR/secondary-label-with-long-type.rs:8:9
|
LL | let () = x;
| ^^ - this expression has type `((..., ..., ..., ...), ..., ..., ...)`
| |
| expected `((..., ..., ..., ...), ..., ..., ...)`, found `()`
|
= note: expected tuple `((..., ..., ..., ...), ..., ..., ...)`
found unit type `()`
= note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/secondary-label-with-long-type/secondary-label-with-long-type.long-type-3987761834644699448.txt'
= note: consider using `--verbose` to print the full type name to the console
```
Reported in a comment of #135919.
Forbid usage of `hir` `Infer` const/ty variants in ambiguous contexts
The feature `generic_arg_infer` allows providing `_` as an argument to const generics in order to infer them. This introduces a syntactic ambiguity as to whether generic arguments are type or const arguments. In order to get around this we introduced a fourth `GenericArg` variant, `Infer` used to represent `_` as an argument to generic parameters when we don't know if its a type or a const argument.
This made hir visitors that care about `TyKind::Infer` or `ConstArgKind::Infer` very error prone as checking for `TyKind::Infer`s in `visit_ty` would find *some* type infer arguments but not *all* of them as they would sometimes be lowered to `GenericArg::Infer` instead.
Additionally the `visit_infer` method would previously only visit `GenericArg::Infer` not *all* infers (e.g. `TyKind::Infer`), this made it very easy to override `visit_infer` and expect it to visit all infers when in reality it would only visit *some* infers.
---
This PR aims to fix those issues by making the `TyKind` and `ConstArgKind` types generic over whether the infer types/consts are represented by `Ty/ConstArgKind::Infer` or out of line (e.g. by a `GenericArg::Infer` or accessible by overiding `visit_infer`). We then make HIR Visitors convert all const args and types to the versions where infer vars are stored out of line and call `visit_infer` in cases where a `Ty`/`Const` would previously have had a `Ty/ConstArgKind::Infer` variant:
API Summary
```rust
enum AmbigArg {}
enum Ty/ConstArgKind<Unambig = ()> {
...
Infer(Unambig),
}
impl Ty/ConstArg {
fn try_as_ambig_ty/ct(self) -> Option<Ty/ConstArg<AmbigArg>>;
}
impl Ty/ConstArg<AmbigArg> {
fn as_unambig_ty/ct(self) -> Ty/ConstArg;
}
enum InferKind {
Ty(Ty),
Const(ConstArg),
Ambig(InferArg),
}
trait Visitor {
...
fn visit_ty/const_arg(&mut self, Ty/ConstArg<AmbigArg>) -> Self::Result;
fn visit_infer(&mut self, id: HirId, sp: Span, kind: InferKind) -> Self::Result;
}
// blanket impl'd, not meant to be overriden
trait VisitorExt {
fn visit_ty/const_arg_unambig(&mut self, Ty/ConstArg) -> Self::Result;
}
fn walk_unambig_ty/const_arg(&mut V, Ty/ConstArg) -> Self::Result;
fn walk_ty/const_arg(&mut V, Ty/ConstArg<AmbigArg>) -> Self::Result;
```
The end result is that `visit_infer` visits *all* infer args and is also the *only* way to visit an infer arg, `visit_ty` and `visit_const_arg` can now no longer encounter a `Ty/ConstArgKind::Infer`. Representing this in the type system means that it is now very difficult to mess things up, either accessing `TyKind::Infer` "just works" and you won't miss *some* type infers- or it doesn't work and you have to look at `visit_infer` or some `GenericArg::Infer` which forces you to think about the full complexity involved.
Unfortunately there is no lint right now about explicitly matching on uninhabited variants, I can't find the context for why this is the case 🤷♀️
I'm not convinced the framing of un/ambig ty/consts is necessarily the right one but I'm not sure what would be better. I somewhat like calling them full/partial types based on the fact that `Ty<Partial>`/`Ty<Full>` directly specifies how many of the type kinds are actually represented compared to `Ty<Ambig>` which which leaves that to the reader to figure out based on the logical consequences of it the type being in an ambiguous position.
---
tool changes have been modified in their own commits for easier reviewing by anyone getting cc'd from subtree changes. I also attempted to split out "bug fixes arising from the refactoring" into their own commit so they arent lumped in with a big general refactor commit
Fixes#112110
Remove usages of `QueryNormalizer` in the compiler
I want to get rid of the `QueryNormalizer`, possibly changing it to be special cased just for normalizing erasing regions, or perhaps adapting `normalize_erasing_regions` to use the assoc type normalizer if caching is sufficient and removing it altogther.
This removes the last two usages of `.query_normalize` in the *compiler*. There are a few usages left in rustdoc and clippy, which exist only because the query normalizer is more resilient to errors and non-well-formed alias types. I will remove those next.
r? lcnr or reassign
We were previously printing the full type on the "this expression has type" label.
```
error[E0308]: mismatched types
--> $DIR/secondary-label-with-long-type.rs:8:9
|
LL | let () = x;
| ^^ - this expression has type `((..., ..., ..., ...), ..., ..., ...)`
| |
| expected `((..., ..., ..., ...), ..., ..., ...)`, found `()`
|
= note: expected tuple `((..., ..., ..., ...), ..., ..., ...)`
found unit type `()`
= note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/secondary-label-with-long-type/secondary-label-with-long-type.long-type-3987761834644699448.txt'
= note: consider using `--verbose` to print the full type name to the console
```
Reported in a comment of #135919.
Add missing check for async body when suggesting await on futures.
Currently the compiler suggests adding `.await` to resolve some type conflicts without checking if the conflict happens in an async context. This can lead to the compiler suggesting `.await` in function signatures where it is invalid. Example:
```rs
trait A {
fn a() -> impl Future<Output = ()>;
}
struct B;
impl A for B {
fn a() -> impl Future<Output = impl Future<Output = ()>> {
async { async { () } }
}
}
```
```
error[E0271]: expected `impl Future<Output = impl Future<Output = ()>>` to be a future that resolves to `()`, but it resolves to `impl Future<Output = ()>`
--> bug.rs:6:15
|
6 | fn a() -> impl Future<Output = impl Future<Output = ()>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found future
|
note: calling an async function returns a future
--> bug.rs:6:15
|
6 | fn a() -> impl Future<Output = impl Future<Output = ()>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `A::{synthetic#0}`
--> bug.rs:2:27
|
2 | fn a() -> impl Future<Output = ()>;
| ^^^^^^^^^^^ required by this bound in `A::{synthetic#0}`
help: consider `await`ing on the `Future`
|
6 | fn a() -> impl Future<Output = impl Future<Output = ()>>.await {
| ++++++
```
The documentation of suggest_await_on_expect_found (`compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs:156`) even mentions such a check but does not actually implement it.
This PR adds that check to ensure `.await` is only suggested within async blocks.
There were 3 unit tests whose expected output needed to be changed because they had the suggestion outside of async. One of them (`tests/ui/async-await/dont-suggest-missing-await.rs`) actually tests that exact problem but expects it to be present.
Thanks to `@llenck` for initially noticing the bug and helping with fixing it
Don't pick `T: FnPtr` nested goals as the leaf goal in diagnostics for new solver
r? `@lcnr`
See `tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.rs` for a minimized example of what code this affects the diagnostics off. The output of running nightly `-Znext-solver` on that test is the following:
```
error[E0277]: the trait bound `Foo: Trait` is not satisfied
--> src/lib.rs:14:20
|
14 | requires_trait(Foo);
| -------------- ^^^ the trait `FnPtr` is not implemented for `Foo`
| |
| required by a bound introduced by this call
|
note: required for `Foo` to implement `Trait`
--> src/lib.rs:7:16
|
7 | impl<T: FnPtr> Trait for T {}
| ----- ^^^^^ ^
| |
| unsatisfied trait bound introduced here
note: required by a bound in `requires_trait`
--> src/lib.rs:11:22
|
11 | fn requires_trait<T: Trait>(_: T) {}
| ^^^^^ required by this bound in `requires_trait`
```
Part of rust-lang/trait-system-refactor-initiative#148
Use `structurally_normalize` instead of manual `normalizes-to` goals in alias relate errors
r? `@lcnr`
I added `structurally_normalize_term` so that code that is generic over ty or const can use the structurally normalize helpers. See `tests/ui/traits/next-solver/diagnostics/alias_relate_error_uses_structurally_normalize.rs` for a description of the reason for the (now fixed) ICEs
This CL makes a number of small changes to dyn compatibility errors:
- "object safety" has been renamed to "dyn-compatibility" throughout
- "Convert to enum" suggestions are no longer generated when there
exists a type-generic impl of the trait or an impl for `dyn OtherTrait`
- Several error messages are reorganized for user readability
Additionally, the dyn compatibility error creation code has been
split out into functions.
cc #132713
cc #133267
remove support for the (unstable) #[start] attribute
As explained by `@Noratrieb:`
`#[start]` should be deleted. It's nothing but an accidentally leaked implementation detail that's a not very useful mix between "portable" entrypoint logic and bad abstraction.
I think the way the stable user-facing entrypoint should work (and works today on stable) is pretty simple:
- `std`-using cross-platform programs should use `fn main()`. the compiler, together with `std`, will then ensure that code ends up at `main` (by having a platform-specific entrypoint that gets directed through `lang_start` in `std` to `main` - but that's just an implementation detail)
- `no_std` platform-specific programs should use `#![no_main]` and define their own platform-specific entrypoint symbol with `#[no_mangle]`, like `main`, `_start`, `WinMain` or `my_embedded_platform_wants_to_start_here`. most of them only support a single platform anyways, and need cfg for the different platform's ways of passing arguments or other things *anyways*
`#[start]` is in a super weird position of being neither of those two. It tries to pretend that it's cross-platform, but its signature is a total lie. Those arguments are just stubbed out to zero on ~~Windows~~ wasm, for example. It also only handles the platform-specific entrypoints for a few platforms that are supported by `std`, like Windows or Unix-likes. `my_embedded_platform_wants_to_start_here` can't use it, and neither could a libc-less Linux program.
So we have an attribute that only works in some cases anyways, that has a signature that's a total lie (and a signature that, as I might want to add, has changed recently, and that I definitely would not be comfortable giving *any* stability guarantees on), and where there's a pretty easy way to get things working without it in the first place.
Note that this feature has **not** been RFCed in the first place.
*This comment was posted [in May](https://github.com/rust-lang/rust/issues/29633#issuecomment-2088596042) and so far nobody spoke up in that issue with a usecase that would require keeping the attribute.*
Closes https://github.com/rust-lang/rust/issues/29633
try-job: x86_64-gnu-nopt
try-job: x86_64-msvc-1
try-job: x86_64-msvc-2
try-job: test-various
Rework dyn trait lowering to stop being so intertwined with trait alias expansion
This PR reworks the trait object lowering code to stop handling trait aliases so funky, and removes the `TraitAliasExpander` in favor of a much simpler design. This refactoring is important for making the code that I'm writing in https://github.com/rust-lang/rust/pull/133397 understandable and easy to maintain, so the diagnostics regressions are IMO inevitable.
In the old trait object lowering code, we used to be a bit sloppy with the lists of traits in their unexpanded and expanded forms. This PR largely rewrites this logic to expand the trait aliases *once* and handle them more responsibly throughout afterwards.
Please review this with whitespace disabled.
r? lcnr
new solver: prefer trivial builtin impls
As discussed [on zulip](https://rust-lang.zulipchat.com/#narrow/channel/364551-t-types.2Ftrait-system-refactor/topic/needs_help.3A.20trivial.20builtin.20impls), this PR:
- adds a new `BuiltinImplSource::Trivial` source, and marks the `Sized` builtin impls as trivial
- prefers these trivial builtin impls in `merge_trait_candidates`
The comments can likely be wordsmithed a bit better, and I ~stole~ was inspired by the old solver ones. Let me know how you want them improved.
When enabling the new solver for tests, 3 UI tests now pass:
- `regions/issue-26448-1.rs` and its sibling `regions/issue-26448-2.rs` were rejected by the new solver but accepted by the old one
- and `issues/issue-42796.rs` where the old solver emitted some overflow errors in addition to the expected error
(For some reason one of these tests is run-pass, but I can take care of that another day)
r? lcnr
Detect if-else chains with a missing final else in type errors
```
error[E0308]: `if` and `else` have incompatible types
--> $DIR/if-else-chain-missing-else.rs:12:12
|
LL | let x = if let Ok(x) = res {
| ______________-
LL | | x
| | - expected because of this
LL | | } else if let Err(e) = res {
| | ____________^
LL | || return Err(e);
LL | || };
| || ^
| ||_____|
| |_____`if` and `else` have incompatible types
| expected `i32`, found `()`
|
= note: `if` expressions without `else` evaluate to `()`
= note: consider adding an `else` block that evaluates to the expected type
```
We probably want a longer explanation and fewer spans on this case.
Partially address #133316.
```
error[E0308]: `if` and `else` have incompatible types
--> $DIR/if-else-chain-missing-else.rs:12:12
|
LL | let x = if let Ok(x) = res {
| ______________-
LL | | x
| | - expected because of this
LL | | } else if let Err(e) = res {
| | ____________^
LL | || return Err(e);
LL | || };
| || ^
| ||_____|
| |_____`if` and `else` have incompatible types
| expected `i32`, found `()`
|
= note: `if` expressions without `else` evaluate to `()`
= note: consider adding an `else` block that evaluates to the expected type
```
We probably want a longer explanation and fewer spans on this case.
Partially address #133316.
Prefer lower `TraitUpcasting` candidates in selection
Fixes#135463. The underlying cause is this ambiguity, but it's more clear (and manifests as a coercion error, rather than a MIR validation error) when it's written the way I did in the UI test.
Sorry this is cursed r? lcnr
Treat safe target_feature functions as unsafe by default [less invasive variant]
This unblocks
* #134090
As I stated in https://github.com/rust-lang/rust/pull/134090#issuecomment-2541332415 I think the previous impl was too easy to get wrong, as by default it treated safe target feature functions as safe and had to add additional checks for when they weren't. Now the logic is inverted. By default they are unsafe and you have to explicitly handle safe target feature functions.
This is the less (imo) invasive variant of #134317, as it doesn't require changing the Safety enum, so it only affects FnDefs and nothing else, as it should.
Make sure we can produce `ConstArgHasWrongType` errors for valtree consts
I forgot about `ty::ConstKind::Value` in #134771.
The error message here could use some work -- both in the new trait solver and the old trait solver. But unrelated to the issue here.
Fixes https://github.com/rust-lang/rust/issues/135361 -- this was only ICEing in coherence because coherence uses the new trait solver, but I don't think the minimization is worth committing compared to the test I added.
r? ```@lcnr``` or ```@BoxyUwU```
Exclude dependencies of `std` for diagnostics
Currently crates in the sysroot can show up in diagnostic suggestions, such as in https://github.com/rust-lang/rust/issues/135232. To prevent this, duplicate `all_traits` into `visible_traits` which only shows traits in non-private crates.
Setting `#![feature(rustc_private)]` overrides this and makes items in private crates visible as well, since `rustc_private` enables use of `std`'s private dependencies.
This may be reviewed per-commit.
Fixes: https://github.com/rust-lang/rust/issues/135232
Add an alternative to `tcx.all_traits()` that only shows traits that the
user might be able to use, for diagnostic purposes. With this available,
make use of it for diagnostics including associated type errors, which
is part of the problem with [1].
Includes a few comment updates for related API.
[1]: https://github.com/rust-lang/rust/issues/135232
fix ICE with references to infinite structs in consts
fixes https://github.com/rust-lang/rust/issues/114484
Normalizing `<Type as Pointee>::Metadata` may emit a (non-fatal) error during trait selection if finding the struct tail of `Type` hits the recursion limit. When this happens, prior this PR, we would treat the projection as rigid, i.e. don't normalize it further. This PR changes it so that we normalize to `ty::Error` instead.
This is important, because to compute the layout of `&Type` we need to compute the layout of `<Type as Pointee>::Metadata`
2ae9916816/compiler/rustc_ty_utils/src/layout.rs (L247-L273)
and computing the layout of a rigid alias will (correctly) fail and needs to report an error to the user. For example:
```rust
trait Project {
type Assoc;
}
fn foo<T: Project>() {
[(); {
let _: Option<T::Assoc> = None;
// ^^^^^^^^ this projection is rigid, so we can't know it's layout
0
}];
}
```
```
error: constant expression depends on a generic parameter
--> src/lib.rs:6:10
|
6 | [(); {
| __________^
7 | | let _: Option<T::Assoc> = None;
8 | | // ^^^^^^^^ this projection is rigid, so we can't know it's layout
9 | | 0
10 | | }];
| |_____^
|
= note: this may fail depending on what value the parameter takes
```
For non-generic rigid projections we will currently ICE, because we incorrectly assume that `LayoutError::Unknown` means that a const must be generic (https://github.com/rust-lang/rust/issues/135138). This is being fixed and turned into a proper error in https://github.com/rust-lang/rust/pull/135158.
```rust
#![feature(trivial_bounds)]
trait Project {
type Assoc;
}
fn foo()
where
u8: Project,
{
[(); {
let _: Option<<u8 as Project>::Assoc> = None; // ICEs currently, but will be an error
0
}];
}
```
However, if we hit the recursion limit when normalizing `<Type as Pointee>::Metadata` we don't want to report a layout error, because we already emitted the recursion error. So by normalizing to `ty::Error` here, we get a `LayoutError::ReferencesError` instead of a `LayoutError::Unknown` and don't report the layout error to the user.