find the right error source when we can't unsize
This commit is contained in:
parent
3d9cb043dd
commit
17566221f8
6 changed files with 77 additions and 39 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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() { }
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue