find the right error source when we can't unsize

This commit is contained in:
Jana Dönszelmann 2025-10-03 11:32:17 +02:00
parent 3d9cb043dd
commit 17566221f8
No known key found for this signature in database
6 changed files with 77 additions and 39 deletions

View file

@ -2055,6 +2055,8 @@ impl<'tcx> ProofTreeVisitor<'tcx> for CoerceVisitor<'_, 'tcx> {
return ControlFlow::Continue(());
};
// Make sure this predicate is referring to either an `Unsize` or `CoerceUnsized` trait,
// Otherwise there's nothing to do.
if !self.fcx.tcx.is_lang_item(pred.def_id(), LangItem::Unsize)
&& !self.fcx.tcx.is_lang_item(pred.def_id(), LangItem::CoerceUnsized)
{
@ -2062,8 +2064,19 @@ impl<'tcx> ProofTreeVisitor<'tcx> for CoerceVisitor<'_, 'tcx> {
}
match goal.result() {
// If we prove the `Unsize` or `CoerceUnsized` goal, continue recursing.
Ok(Certainty::Yes) => ControlFlow::Continue(()),
Err(NoSolution) => ControlFlow::Break(()),
Err(NoSolution) => {
// Even if we find no solution, continue recursing if we find a single candidate
// for which we're shallowly certain it holds to get the right error source.
if let [only_candidate] = &goal.candidates()[..]
&& only_candidate.shallow_certainty() == Certainty::Yes
{
only_candidate.visit_nested_no_probe(self)
} else {
ControlFlow::Break(())
}
}
Ok(Certainty::Maybe { .. }) => {
// FIXME: structurally normalize?
if self.fcx.tcx.is_lang_item(pred.def_id(), LangItem::Unsize)
@ -2071,6 +2084,10 @@ impl<'tcx> ProofTreeVisitor<'tcx> for CoerceVisitor<'_, 'tcx> {
&& let ty::Infer(ty::TyVar(vid)) = *pred.self_ty().skip_binder().kind()
&& self.fcx.type_var_is_sized(vid)
{
// We get here when trying to unsize a type variable to a `dyn Trait`,
// knowing that that variable is sized. Unsizing definitely has to happen in that case.
// If the variable weren't sized, we may not need an unsizing coercion.
// In general, we don't want to add coercions too eagerly since it makes error messages much worse.
ControlFlow::Continue(())
} else if let Some(cand) = goal.unique_applicable_candidate()
&& cand.shallow_certainty() == Certainty::Yes

View file

@ -14,7 +14,7 @@ LL + fn test1<T: Foo>(t: &T) {
|
error[E0277]: the size for values of type `T` cannot be known at compilation time
--> $DIR/dst-object-from-unsized-type.rs:16:23
--> $DIR/dst-object-from-unsized-type.rs:17:23
|
LL | fn test2<T: ?Sized + Foo>(t: &T) {
| - this type parameter needs to be `Sized`
@ -29,7 +29,7 @@ LL + fn test2<T: Foo>(t: &T) {
|
error[E0277]: the size for values of type `str` cannot be known at compilation time
--> $DIR/dst-object-from-unsized-type.rs:21:28
--> $DIR/dst-object-from-unsized-type.rs:23:28
|
LL | let _: &[&dyn Foo] = &["hi"];
| ^^^^ doesn't have a size known at compile-time
@ -38,7 +38,7 @@ LL | let _: &[&dyn Foo] = &["hi"];
= note: required for the cast from `&'static str` to `&dyn Foo`
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> $DIR/dst-object-from-unsized-type.rs:26:23
--> $DIR/dst-object-from-unsized-type.rs:29:23
|
LL | let _: &dyn Foo = x as &dyn Foo;
| ^ doesn't have a size known at compile-time

View file

@ -1,41 +1,57 @@
error[E0308]: mismatched types
error[E0277]: the trait bound `&T: CoerceUnsized<&dyn Foo>` is not satisfied in `T`
--> $DIR/dst-object-from-unsized-type.rs:11:23
|
LL | fn test1<T: ?Sized + Foo>(t: &T) {
| - found this type parameter
| - this type parameter needs to be `Sized`
LL | let u: &dyn Foo = t;
| -------- ^ expected `&dyn Foo`, found `&T`
| |
| expected due to this
| ^ within `T`, the trait `Sized` is not implemented for `T`
|
= note: required because it appears within the type `T`
= note: required for `&T` to implement `CoerceUnsized<&dyn Foo>`
= note: required for the cast from `&T` to `&dyn Foo`
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
LL - fn test1<T: ?Sized + Foo>(t: &T) {
LL + fn test1<T: Foo>(t: &T) {
|
= note: expected reference `&dyn Foo`
found reference `&T`
= help: type parameters must be constrained to match other types
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
error[E0605]: non-primitive cast: `&T` as `&dyn Foo`
--> $DIR/dst-object-from-unsized-type.rs:16:23
error[E0277]: the trait bound `&T: CoerceUnsized<&dyn Foo>` is not satisfied in `T`
--> $DIR/dst-object-from-unsized-type.rs:17:23
|
LL | fn test2<T: ?Sized + Foo>(t: &T) {
| - this type parameter needs to be `Sized`
LL | let v: &dyn Foo = t as &dyn Foo;
| ^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
| ^ within `T`, the trait `Sized` is not implemented for `T`
|
= note: required because it appears within the type `T`
= note: required for `&T` to implement `CoerceUnsized<&dyn Foo>`
= note: required for the cast from `&T` to `&dyn Foo`
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
LL - fn test2<T: ?Sized + Foo>(t: &T) {
LL + fn test2<T: Foo>(t: &T) {
|
error[E0308]: mismatched types
--> $DIR/dst-object-from-unsized-type.rs:21:28
error[E0277]: the trait bound `&str: CoerceUnsized<&dyn Foo>` is not satisfied in `str`
--> $DIR/dst-object-from-unsized-type.rs:23:28
|
LL | let _: &[&dyn Foo] = &["hi"];
| ^^^^ expected `&dyn Foo`, found `&str`
| ^^^^ within `str`, the trait `Sized` is not implemented for `str`
|
= note: expected reference `&dyn Foo`
found reference `&'static str`
= help: `str` implements `Foo` so you could box the found value and coerce it to the trait object `Box<dyn Foo>`, you will have to change the expected type as well
= note: `str` is considered to contain a `[u8]` slice for auto trait purposes
= note: required for `&str` to implement `CoerceUnsized<&dyn Foo>`
= note: required for the cast from `&'static str` to `&dyn Foo`
error[E0605]: non-primitive cast: `&[u8]` as `&dyn Foo`
--> $DIR/dst-object-from-unsized-type.rs:26:23
error[E0277]: the trait bound `&[u8]: CoerceUnsized<&dyn Foo>` is not satisfied in `[u8]`
--> $DIR/dst-object-from-unsized-type.rs:29:23
|
LL | let _: &dyn Foo = x as &dyn Foo;
| ^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
| ^ within `[u8]`, the trait `Sized` is not implemented for `[u8]`
|
= note: required because it appears within the type `[u8]`
= note: required for `&[u8]` to implement `CoerceUnsized<&dyn Foo>`
= note: required for the cast from `&[u8]` to `&dyn Foo`
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0308, E0605.
For more information about an error, try `rustc --explain E0308`.
For more information about this error, try `rustc --explain E0277`.

View file

@ -9,22 +9,26 @@ impl Foo for [u8] {}
fn test1<T: ?Sized + Foo>(t: &T) {
let u: &dyn Foo = t;
//~^ ERROR the size for values of type
//[current]~^ ERROR the size for values of type
//[next]~^^ ERROR the trait bound `&T: CoerceUnsized<&dyn Foo>` is not satisfied in `T`
}
fn test2<T: ?Sized + Foo>(t: &T) {
let v: &dyn Foo = t as &dyn Foo;
//~^ ERROR the size for values of type
//[current]~^ ERROR the size for values of type
//[next]~^^ ERROR the trait bound `&T: CoerceUnsized<&dyn Foo>` is not satisfied in `T`
}
fn test3() {
let _: &[&dyn Foo] = &["hi"];
//~^ ERROR the size for values of type
//[current]~^ ERROR the size for values of type
//[next]~^^ ERROR the trait bound `&str: CoerceUnsized<&dyn Foo>` is not satisfied in `str`
}
fn test4(x: &[u8]) {
let _: &dyn Foo = x as &dyn Foo;
//~^ ERROR the size for values of type
//[current]~^ ERROR the size for values of type
//[next]~^^ ERROR the trait bound `&[u8]: CoerceUnsized<&dyn Foo>` is not satisfied in `[u8]`
}
fn main() { }

View file

@ -1,14 +1,13 @@
error[E0308]: mismatched types
error[E0277]: the trait bound `&dyn for<'a> Subtrait<'a, 'a>: CoerceUnsized<&dyn for<'a, 'b> Supertrait<'a, 'b>>` is not satisfied
--> $DIR/higher-ranked-upcasting-ub.rs:22:5
|
LL | fn unsound(x: &dyn for<'a> Subtrait<'a, 'a>) -> &dyn for<'a, 'b> Supertrait<'a, 'b> {
| ----------------------------------- expected `&dyn for<'a, 'b> Supertrait<'a, 'b>` because of return type
LL | x
| ^ expected trait `Supertrait`, found trait `Subtrait`
| ^ the trait `Unsize<dyn for<'a, 'b> Supertrait<'a, 'b>>` is not implemented for `dyn for<'a> Subtrait<'a, 'a>`
|
= note: expected reference `&dyn for<'a, 'b> Supertrait<'a, 'b>`
found reference `&dyn for<'a> Subtrait<'a, 'a>`
= note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information
= note: required for `&dyn for<'a> Subtrait<'a, 'a>` to implement `CoerceUnsized<&dyn for<'a, 'b> Supertrait<'a, 'b>>`
= note: required for the cast from `&dyn for<'a> Subtrait<'a, 'a>` to `&dyn for<'a, 'b> Supertrait<'a, 'b>`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.
For more information about this error, try `rustc --explain E0277`.

View file

@ -19,8 +19,10 @@ impl<'a> Supertrait<'a, 'a> for () {
}
impl<'a> Subtrait<'a, 'a> for () {}
fn unsound(x: &dyn for<'a> Subtrait<'a, 'a>) -> &dyn for<'a, 'b> Supertrait<'a, 'b> {
x //~ ERROR mismatched types
x
//[current]~^ ERROR mismatched types
//[current]~| ERROR mismatched types
//[next]~^^^ ERROR the trait bound `&dyn for<'a> Subtrait<'a, 'a>: CoerceUnsized<&dyn for<'a, 'b> Supertrait<'a, 'b>>` is not satisfied
}
fn transmute<'a, 'b>(x: &'a str) -> &'b str {