about summary refs log tree commit diff
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2020-06-18 15:20:57 -0700
committerGitHub <noreply@github.com>2020-06-18 15:20:57 -0700
commit9ca811772c2fddefeda4567cdfb8c790c94e0085 (patch)
treea4ede3c4340f0e6bbe965db8098227aa1c5a2943
parentf4b5f581a9c2604a951043decd6acf4e2852fe35 (diff)
parente857696cf8c3b4a4381d00424f165c10f93a9ebd (diff)
downloadrust-9ca811772c2fddefeda4567cdfb8c790c94e0085.tar.gz
rust-9ca811772c2fddefeda4567cdfb8c790c94e0085.zip
Rollup merge of #73361 - estebank:non-primitive-cast, r=davidtwco
Tweak "non-primitive cast" error

- Suggest borrowing expression if it would allow cast to work.
- Suggest using `<Type>::from(<expr>)` when appropriate.
- Minor tweak to `;` typo suggestion.

Partily address #47136.
-rw-r--r--src/libcore/convert/mod.rs1
-rw-r--r--src/librustc_parse/parser/diagnostics.rs2
-rw-r--r--src/librustc_span/symbol.rs1
-rw-r--r--src/librustc_typeck/check/cast.rs107
-rw-r--r--src/test/ui/cast/cast-from-nil.stderr4
-rw-r--r--src/test/ui/cast/cast-to-bare-fn.stderr8
-rw-r--r--src/test/ui/cast/cast-to-nil.stderr4
-rw-r--r--src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr2
-rw-r--r--src/test/ui/closures/closure-no-fn-3.stderr4
-rw-r--r--src/test/ui/coercion/coerce-to-bang-cast.stderr8
-rw-r--r--src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr2
-rw-r--r--src/test/ui/error-codes/E0604.stderr2
-rw-r--r--src/test/ui/error-codes/E0605.stderr8
-rw-r--r--src/test/ui/error-festival.stderr6
-rw-r--r--src/test/ui/fat-ptr-cast.stderr4
-rw-r--r--src/test/ui/issues/issue-10991.stderr4
-rw-r--r--src/test/ui/issues/issue-16048.rs4
-rw-r--r--src/test/ui/issues/issue-16048.stderr8
-rw-r--r--src/test/ui/issues/issue-17441.stderr2
-rw-r--r--src/test/ui/issues/issue-22289.stderr7
-rw-r--r--src/test/ui/issues/issue-22312.rs2
-rw-r--r--src/test/ui/issues/issue-22312.stderr7
-rw-r--r--src/test/ui/issues/issue-2995.stderr4
-rw-r--r--src/test/ui/issues/issue-45730.stderr18
-rw-r--r--src/test/ui/mismatched_types/cast-rfc0401.stderr22
-rw-r--r--src/test/ui/mismatched_types/issue-26480.stderr3
-rw-r--r--src/test/ui/nonscalar-cast.fixed16
-rw-r--r--src/test/ui/nonscalar-cast.rs8
-rw-r--r--src/test/ui/nonscalar-cast.stderr6
-rw-r--r--src/test/ui/order-dependent-cast-inference.stderr6
-rw-r--r--src/test/ui/tag-variant-cast-non-nullary.fixed20
-rw-r--r--src/test/ui/tag-variant-cast-non-nullary.rs11
-rw-r--r--src/test/ui/tag-variant-cast-non-nullary.stderr6
-rw-r--r--src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr4
-rw-r--r--src/test/ui/uninhabited/uninhabited-enum-cast.stderr4
35 files changed, 204 insertions, 121 deletions
diff --git a/src/libcore/convert/mod.rs b/src/libcore/convert/mod.rs
index eef9ee7cb00..8ff1ced53b0 100644
--- a/src/libcore/convert/mod.rs
+++ b/src/libcore/convert/mod.rs
@@ -374,6 +374,7 @@ pub trait Into<T>: Sized {
 /// [`Into`]: trait.Into.html
 /// [`from`]: trait.From.html#tymethod.from
 /// [book]: ../../book/ch09-00-error-handling.html
+#[rustc_diagnostic_item = "from_trait"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_on_unimplemented(on(
     all(_Self = "&str", T = "std::string::String"),
diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs
index 8792605c08d..fc9ffc30924 100644
--- a/src/librustc_parse/parser/diagnostics.rs
+++ b/src/librustc_parse/parser/diagnostics.rs
@@ -961,7 +961,7 @@ impl<'a> Parser<'a> {
             self.bump();
             let sp = self.prev_token.span;
             self.struct_span_err(sp, &msg)
-                .span_suggestion(sp, "change this to `;`", ";".to_string(), appl)
+                .span_suggestion_short(sp, "change this to `;`", ";".to_string(), appl)
                 .emit();
             return Ok(());
         } else if self.look_ahead(0, |t| {
diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs
index fdeb58b7b7a..6f334bf37f5 100644
--- a/src/librustc_span/symbol.rs
+++ b/src/librustc_span/symbol.rs
@@ -345,6 +345,7 @@ symbols! {
         from_method,
         from_ok,
         from_usize,
+        from_trait,
         fundamental,
         future,
         Future,
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index c55f0cf1fcb..78474dac76f 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -43,6 +43,7 @@ use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, Ty, TypeAndMut, TypeFoldable};
 use rustc_session::lint;
 use rustc_session::Session;
+use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
@@ -333,10 +334,11 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                     "only `u8` can be cast as `char`, not `{}`",
                     self.expr_ty
                 )
+                .span_label(self.span, "invalid cast")
                 .emit();
             }
             CastError::NonScalar => {
-                type_error_struct!(
+                let mut err = type_error_struct!(
                     fcx.tcx.sess,
                     self.span,
                     self.expr_ty,
@@ -344,12 +346,75 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                     "non-primitive cast: `{}` as `{}`",
                     self.expr_ty,
                     fcx.ty_to_string(self.cast_ty)
-                )
-                .note(
-                    "an `as` expression can only be used to convert between \
-                                         primitive types. Consider using the `From` trait",
-                )
-                .emit();
+                );
+                let mut sugg = None;
+                if let ty::Ref(reg, _, mutbl) = self.cast_ty.kind {
+                    if fcx
+                        .try_coerce(
+                            self.expr,
+                            fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }),
+                            self.cast_ty,
+                            AllowTwoPhase::No,
+                        )
+                        .is_ok()
+                    {
+                        sugg = Some(format!("&{}", mutbl.prefix_str()));
+                    }
+                }
+                if let Some(sugg) = sugg {
+                    err.span_label(self.span, "invalid cast");
+                    err.span_suggestion_verbose(
+                        self.expr.span.shrink_to_lo(),
+                        "borrow the value for the cast to be valid",
+                        sugg,
+                        Applicability::MachineApplicable,
+                    );
+                } else if !matches!(
+                    self.cast_ty.kind,
+                    ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..)
+                ) {
+                    let mut label = true;
+                    // Check `impl From<self.expr_ty> for self.cast_ty {}` for accurate suggestion:
+                    if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
+                        if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::from_trait) {
+                            let ty = fcx.resolve_vars_if_possible(&self.cast_ty);
+                            // Erase regions to avoid panic in `prove_value` when calling
+                            // `type_implements_trait`.
+                            let ty = fcx.tcx.erase_regions(&ty);
+                            let expr_ty = fcx.resolve_vars_if_possible(&self.expr_ty);
+                            let expr_ty = fcx.tcx.erase_regions(&expr_ty);
+                            let ty_params = fcx.tcx.mk_substs_trait(expr_ty, &[]);
+                            // Check for infer types because cases like `Option<{integer}>` would
+                            // panic otherwise.
+                            if !expr_ty.has_infer_types()
+                                && fcx.tcx.type_implements_trait((
+                                    from_trait,
+                                    ty,
+                                    ty_params,
+                                    fcx.param_env,
+                                ))
+                            {
+                                label = false;
+                                err.span_suggestion(
+                                    self.span,
+                                    "consider using the `From` trait instead",
+                                    format!("{}::from({})", self.cast_ty, snippet),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+                        }
+                    }
+                    let msg = "an `as` expression can only be used to convert between primitive \
+                               types or to coerce to a specific trait object";
+                    if label {
+                        err.span_label(self.span, msg);
+                    } else {
+                        err.note(msg);
+                    }
+                } else {
+                    err.span_label(self.span, "invalid cast");
+                }
+                err.emit();
             }
             CastError::SizedUnsizedCast => {
                 use crate::structured_errors::{SizedUnsizedCastError, StructuredDiagnostic};
@@ -370,21 +435,22 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 };
                 let mut err = struct_span_err!(
                     fcx.tcx.sess,
-                    self.span,
+                    if unknown_cast_to { self.cast_span } else { self.span },
                     E0641,
                     "cannot cast {} a pointer of an unknown kind",
                     if unknown_cast_to { "to" } else { "from" }
                 );
-                err.note(
-                    "the type information given here is insufficient to check whether \
-                          the pointer cast is valid",
-                );
                 if unknown_cast_to {
-                    err.span_suggestion_short(
-                        self.cast_span,
-                        "consider giving more type information",
-                        String::new(),
-                        Applicability::Unspecified,
+                    err.span_label(self.cast_span, "needs more type information");
+                    err.note(
+                        "the type information given here is insufficient to check whether \
+                        the pointer cast is valid",
+                    );
+                } else {
+                    err.span_label(
+                        self.span,
+                        "the type information given here is insufficient to check whether \
+                        the pointer cast is valid",
                     );
                 }
                 err.emit();
@@ -438,13 +504,16 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                     Ok(s) => {
                         err.span_suggestion(
                             self.cast_span,
-                            "try casting to a `Box` instead",
+                            "you can cast to a `Box` instead",
                             format!("Box<{}>", s),
                             Applicability::MachineApplicable,
                         );
                     }
                     Err(_) => {
-                        err.span_help(self.cast_span, &format!("did you mean `Box<{}>`?", tstr));
+                        err.span_help(
+                            self.cast_span,
+                            &format!("you might have meant `Box<{}>`", tstr),
+                        );
                     }
                 }
             }
diff --git a/src/test/ui/cast/cast-from-nil.stderr b/src/test/ui/cast/cast-from-nil.stderr
index c8e3628a7de..dab133cfb4b 100644
--- a/src/test/ui/cast/cast-from-nil.stderr
+++ b/src/test/ui/cast/cast-from-nil.stderr
@@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `()` as `u32`
   --> $DIR/cast-from-nil.rs:2:21
    |
 LL | fn main() { let u = (assert!(true) as u32); }
-   |                     ^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |                     ^^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/cast/cast-to-bare-fn.stderr b/src/test/ui/cast/cast-to-bare-fn.stderr
index 84933dca929..d97b0c5f8aa 100644
--- a/src/test/ui/cast/cast-to-bare-fn.stderr
+++ b/src/test/ui/cast/cast-to-bare-fn.stderr
@@ -2,17 +2,13 @@ error[E0605]: non-primitive cast: `fn(isize) {foo}` as `extern "C" fn() -> isize
   --> $DIR/cast-to-bare-fn.rs:5:13
    |
 LL |     let x = foo as extern "C" fn() -> isize;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
 
 error[E0605]: non-primitive cast: `u64` as `fn(isize) -> (isize, isize)`
   --> $DIR/cast-to-bare-fn.rs:7:13
    |
 LL |     let y = v as extern "Rust" fn(isize) -> (isize, isize);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/cast/cast-to-nil.stderr b/src/test/ui/cast/cast-to-nil.stderr
index 478f6b69daf..29a9baffd71 100644
--- a/src/test/ui/cast/cast-to-nil.stderr
+++ b/src/test/ui/cast/cast-to-nil.stderr
@@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `u32` as `()`
   --> $DIR/cast-to-nil.rs:2:21
    |
 LL | fn main() { let u = 0u32 as (); }
-   |                     ^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |                     ^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr b/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr
index ffa02533d8b..9b86f8d4def 100644
--- a/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr
+++ b/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr
@@ -12,7 +12,7 @@ error[E0620]: cast to unsized type: `std::boxed::Box<{integer}>` as `dyn std::ma
 LL |     Box::new(1) as dyn Send;
    |     ^^^^^^^^^^^^^^^--------
    |                    |
-   |                    help: try casting to a `Box` instead: `Box<dyn Send>`
+   |                    help: you can cast to a `Box` instead: `Box<dyn Send>`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/closures/closure-no-fn-3.stderr b/src/test/ui/closures/closure-no-fn-3.stderr
index ab6056b6547..4b3b4be798f 100644
--- a/src/test/ui/closures/closure-no-fn-3.stderr
+++ b/src/test/ui/closures/closure-no-fn-3.stderr
@@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `[closure@$DIR/closure-no-fn-3.rs:6:27: 6:37 b
   --> $DIR/closure-no-fn-3.rs:6:27
    |
 LL |     let baz: fn() -> u8 = (|| { b }) as fn() -> u8;
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/coercion/coerce-to-bang-cast.stderr b/src/test/ui/coercion/coerce-to-bang-cast.stderr
index ff30ebc09c6..d3adbd5158d 100644
--- a/src/test/ui/coercion/coerce-to-bang-cast.stderr
+++ b/src/test/ui/coercion/coerce-to-bang-cast.stderr
@@ -2,17 +2,13 @@ error[E0605]: non-primitive cast: `i32` as `!`
   --> $DIR/coerce-to-bang-cast.rs:6:13
    |
 LL |     let y = {return; 22} as !;
-   |             ^^^^^^^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |             ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error[E0605]: non-primitive cast: `i32` as `!`
   --> $DIR/coerce-to-bang-cast.rs:11:13
    |
 LL |     let y = 22 as !;
-   |             ^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |             ^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr
index 5b2c4116c4b..e4d256c0ad1 100644
--- a/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr
+++ b/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr
@@ -16,7 +16,7 @@ error[E0604]: only `u8` can be cast as `char`, not `i8`
   --> $DIR/const-eval-overflow-4b.rs:25:13
    |
 LL |     : [u32; 5i8 as char as usize]
-   |             ^^^^^^^^^^^
+   |             ^^^^^^^^^^^ invalid cast
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/error-codes/E0604.stderr b/src/test/ui/error-codes/E0604.stderr
index 5861bdcb7a9..18835310bd5 100644
--- a/src/test/ui/error-codes/E0604.stderr
+++ b/src/test/ui/error-codes/E0604.stderr
@@ -2,7 +2,7 @@ error[E0604]: only `u8` can be cast as `char`, not `u32`
   --> $DIR/E0604.rs:2:5
    |
 LL |     1u32 as char;
-   |     ^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^ invalid cast
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0605.stderr b/src/test/ui/error-codes/E0605.stderr
index 95e899db8b7..f23d2008e0b 100644
--- a/src/test/ui/error-codes/E0605.stderr
+++ b/src/test/ui/error-codes/E0605.stderr
@@ -2,17 +2,13 @@ error[E0605]: non-primitive cast: `u8` as `std::vec::Vec<u8>`
   --> $DIR/E0605.rs:3:5
    |
 LL |     x as Vec<u8>;
-   |     ^^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |     ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error[E0605]: non-primitive cast: `*const u8` as `&u8`
   --> $DIR/E0605.rs:6:5
    |
 LL |     v as &u8;
-   |     ^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |     ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/error-festival.stderr b/src/test/ui/error-festival.stderr
index 7f524230ef0..905195d4ad9 100644
--- a/src/test/ui/error-festival.stderr
+++ b/src/test/ui/error-festival.stderr
@@ -42,15 +42,13 @@ error[E0604]: only `u8` can be cast as `char`, not `u32`
   --> $DIR/error-festival.rs:25:5
    |
 LL |     0u32 as char;
-   |     ^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^ invalid cast
 
 error[E0605]: non-primitive cast: `u8` as `std::vec::Vec<u8>`
   --> $DIR/error-festival.rs:29:5
    |
 LL |     x as Vec<u8>;
-   |     ^^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |     ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error[E0054]: cannot cast as `bool`
   --> $DIR/error-festival.rs:33:24
diff --git a/src/test/ui/fat-ptr-cast.stderr b/src/test/ui/fat-ptr-cast.stderr
index 93e1471838f..56d5a26beb0 100644
--- a/src/test/ui/fat-ptr-cast.stderr
+++ b/src/test/ui/fat-ptr-cast.stderr
@@ -34,9 +34,7 @@ error[E0605]: non-primitive cast: `std::boxed::Box<[i32]>` as `usize`
   --> $DIR/fat-ptr-cast.rs:14:5
    |
 LL |     b as usize;
-   |     ^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |     ^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error[E0606]: casting `*const [i32]` as `usize` is invalid
   --> $DIR/fat-ptr-cast.rs:15:5
diff --git a/src/test/ui/issues/issue-10991.stderr b/src/test/ui/issues/issue-10991.stderr
index f12539b47cf..5b8a1823386 100644
--- a/src/test/ui/issues/issue-10991.stderr
+++ b/src/test/ui/issues/issue-10991.stderr
@@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `()` as `usize`
   --> $DIR/issue-10991.rs:3:14
    |
 LL |     let _t = nil as usize;
-   |              ^^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |              ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-16048.rs b/src/test/ui/issues/issue-16048.rs
index 7d24f3a40a7..eaf6acff26b 100644
--- a/src/test/ui/issues/issue-16048.rs
+++ b/src/test/ui/issues/issue-16048.rs
@@ -18,12 +18,12 @@ impl<'a> Test<'a> for Foo<'a> {
 }
 
 impl<'a> NoLifetime for Foo<'a> {
-    fn get<'p, T : Test<'a>>(&self) -> T {
+    fn get<'p, T: Test<'a> + From<Foo<'a>>>(&self) -> T {
     //~^ ERROR E0195
     //~| NOTE lifetimes do not match method in trait
         return *self as T;
         //~^ ERROR non-primitive cast: `Foo<'a>` as `T`
-        //~| NOTE an `as` expression can only be used to convert between primitive types.
+        //~| NOTE an `as` expression can only be used to convert between primitive types
     }
 }
 
diff --git a/src/test/ui/issues/issue-16048.stderr b/src/test/ui/issues/issue-16048.stderr
index a137bcdf191..73610942d7a 100644
--- a/src/test/ui/issues/issue-16048.stderr
+++ b/src/test/ui/issues/issue-16048.stderr
@@ -4,16 +4,16 @@ error[E0195]: lifetime parameters or bounds on method `get` do not match the tra
 LL |     fn get<'p, T : Test<'p>>(&self) -> T;
    |           ------------------ lifetimes in impl do not match this method in trait
 ...
-LL |     fn get<'p, T : Test<'a>>(&self) -> T {
-   |           ^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
+LL |     fn get<'p, T: Test<'a> + From<Foo<'a>>>(&self) -> T {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
 
 error[E0605]: non-primitive cast: `Foo<'a>` as `T`
   --> $DIR/issue-16048.rs:24:16
    |
 LL |         return *self as T;
-   |                ^^^^^^^^^^
+   |                ^^^^^^^^^^ help: consider using the `From` trait instead: `T::from(*self)`
    |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-17441.stderr b/src/test/ui/issues/issue-17441.stderr
index 0ab035515a0..b63a3995d25 100644
--- a/src/test/ui/issues/issue-17441.stderr
+++ b/src/test/ui/issues/issue-17441.stderr
@@ -16,7 +16,7 @@ error[E0620]: cast to unsized type: `std::boxed::Box<usize>` as `dyn std::fmt::D
 LL |     let _bar = Box::new(1_usize) as dyn std::fmt::Debug;
    |                ^^^^^^^^^^^^^^^^^^^^^-------------------
    |                                     |
-   |                                     help: try casting to a `Box` instead: `Box<dyn std::fmt::Debug>`
+   |                                     help: you can cast to a `Box` instead: `Box<dyn std::fmt::Debug>`
 
 error[E0620]: cast to unsized type: `usize` as `dyn std::fmt::Debug`
   --> $DIR/issue-17441.rs:8:16
diff --git a/src/test/ui/issues/issue-22289.stderr b/src/test/ui/issues/issue-22289.stderr
index cc7ace30cab..4c35deb1fbe 100644
--- a/src/test/ui/issues/issue-22289.stderr
+++ b/src/test/ui/issues/issue-22289.stderr
@@ -2,9 +2,12 @@ error[E0605]: non-primitive cast: `i32` as `&(dyn std::any::Any + 'static)`
   --> $DIR/issue-22289.rs:2:5
    |
 LL |     0 as &dyn std::any::Any;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
    |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+help: borrow the value for the cast to be valid
+   |
+LL |     &0 as &dyn std::any::Any;
+   |     ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-22312.rs b/src/test/ui/issues/issue-22312.rs
index 250fec25887..4e359b3412a 100644
--- a/src/test/ui/issues/issue-22312.rs
+++ b/src/test/ui/issues/issue-22312.rs
@@ -1,6 +1,6 @@
 use std::ops::Index;
 
-pub trait Array2D: Index<usize> {
+pub trait Array2D: Index<usize> + Sized {
     fn rows(&self) -> usize;
     fn columns(&self) -> usize;
     fn get<'a>(&'a self, y: usize, x: usize) -> Option<&'a <Self as Index<usize>>::Output> {
diff --git a/src/test/ui/issues/issue-22312.stderr b/src/test/ui/issues/issue-22312.stderr
index fc32fd376b7..28564b07463 100644
--- a/src/test/ui/issues/issue-22312.stderr
+++ b/src/test/ui/issues/issue-22312.stderr
@@ -2,9 +2,12 @@ error[E0605]: non-primitive cast: `Self` as `&dyn std::ops::Index<usize, Output
   --> $DIR/issue-22312.rs:11:24
    |
 LL |         let indexer = &(*self as &dyn Index<usize, Output = <Self as Index<usize>>::Output>);
-   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
    |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+help: borrow the value for the cast to be valid
+   |
+LL |         let indexer = &(&*self as &dyn Index<usize, Output = <Self as Index<usize>>::Output>);
+   |                         ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-2995.stderr b/src/test/ui/issues/issue-2995.stderr
index c316780d5f6..9f5968399a3 100644
--- a/src/test/ui/issues/issue-2995.stderr
+++ b/src/test/ui/issues/issue-2995.stderr
@@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `*const isize` as `&isize`
   --> $DIR/issue-2995.rs:2:22
    |
 LL |     let _q: &isize = p as &isize;
-   |                      ^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |                      ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-45730.stderr b/src/test/ui/issues/issue-45730.stderr
index d4ddba52df1..d00f3d91b49 100644
--- a/src/test/ui/issues/issue-45730.stderr
+++ b/src/test/ui/issues/issue-45730.stderr
@@ -1,30 +1,24 @@
 error[E0641]: cannot cast to a pointer of an unknown kind
-  --> $DIR/issue-45730.rs:3:23
+  --> $DIR/issue-45730.rs:3:28
    |
 LL |     let x: *const _ = 0 as _;
-   |                       ^^^^^-
-   |                            |
-   |                            help: consider giving more type information
+   |                            ^ needs more type information
    |
    = note: the type information given here is insufficient to check whether the pointer cast is valid
 
 error[E0641]: cannot cast to a pointer of an unknown kind
-  --> $DIR/issue-45730.rs:5:23
+  --> $DIR/issue-45730.rs:5:28
    |
 LL |     let x: *const _ = 0 as *const _;
-   |                       ^^^^^--------
-   |                            |
-   |                            help: consider giving more type information
+   |                            ^^^^^^^^ needs more type information
    |
    = note: the type information given here is insufficient to check whether the pointer cast is valid
 
 error[E0641]: cannot cast to a pointer of an unknown kind
-  --> $DIR/issue-45730.rs:8:13
+  --> $DIR/issue-45730.rs:8:44
    |
 LL |     let x = 0 as *const i32 as *const _ as *mut _;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------
-   |                                            |
-   |                                            help: consider giving more type information
+   |                                            ^^^^^^ needs more type information
    |
    = note: the type information given here is insufficient to check whether the pointer cast is valid
 
diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr
index f94dfd100a6..95936de218b 100644
--- a/src/test/ui/mismatched_types/cast-rfc0401.stderr
+++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr
@@ -24,41 +24,31 @@ error[E0605]: non-primitive cast: `*const u8` as `&u8`
   --> $DIR/cast-rfc0401.rs:29:13
    |
 LL |     let _ = v as &u8;
-   |             ^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |             ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error[E0605]: non-primitive cast: `*const u8` as `E`
   --> $DIR/cast-rfc0401.rs:30:13
    |
 LL |     let _ = v as E;
-   |             ^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |             ^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error[E0605]: non-primitive cast: `*const u8` as `fn()`
   --> $DIR/cast-rfc0401.rs:31:13
    |
 LL |     let _ = v as fn();
-   |             ^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |             ^^^^^^^^^ invalid cast
 
 error[E0605]: non-primitive cast: `*const u8` as `(u32,)`
   --> $DIR/cast-rfc0401.rs:32:13
    |
 LL |     let _ = v as (u32,);
-   |             ^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |             ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error[E0605]: non-primitive cast: `std::option::Option<&*const u8>` as `*const u8`
   --> $DIR/cast-rfc0401.rs:33:13
    |
 LL |     let _ = Some(&v) as *const u8;
-   |             ^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |             ^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error[E0606]: casting `*const u8` as `f32` is invalid
   --> $DIR/cast-rfc0401.rs:35:13
@@ -102,7 +92,7 @@ error[E0604]: only `u8` can be cast as `char`, not `u32`
   --> $DIR/cast-rfc0401.rs:41:13
    |
 LL |     let _ = 0x61u32 as char;
-   |             ^^^^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^^ invalid cast
 
 error[E0606]: casting `bool` as `f32` is invalid
   --> $DIR/cast-rfc0401.rs:43:13
diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr
index 69a9d03e474..d39b0a32077 100644
--- a/src/test/ui/mismatched_types/issue-26480.stderr
+++ b/src/test/ui/mismatched_types/issue-26480.stderr
@@ -17,12 +17,11 @@ error[E0605]: non-primitive cast: `{integer}` as `()`
   --> $DIR/issue-26480.rs:22:19
    |
 LL |     ($x:expr) => ($x as ())
-   |                   ^^^^^^^^
+   |                   ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 ...
 LL |     cast!(2);
    |     --------- in this macro invocation
    |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/nonscalar-cast.fixed b/src/test/ui/nonscalar-cast.fixed
new file mode 100644
index 00000000000..0a4b98469b2
--- /dev/null
+++ b/src/test/ui/nonscalar-cast.fixed
@@ -0,0 +1,16 @@
+// run-rustfix
+
+#[derive(Debug)]
+struct Foo {
+    x: isize
+}
+
+impl From<Foo> for isize {
+    fn from(val: Foo) -> isize {
+        val.x
+    }
+}
+
+fn main() {
+    println!("{}", isize::from(Foo { x: 1 })); //~ non-primitive cast: `Foo` as `isize` [E0605]
+}
diff --git a/src/test/ui/nonscalar-cast.rs b/src/test/ui/nonscalar-cast.rs
index 7e6f1fd038f..59fcf09666b 100644
--- a/src/test/ui/nonscalar-cast.rs
+++ b/src/test/ui/nonscalar-cast.rs
@@ -1,8 +1,16 @@
+// run-rustfix
+
 #[derive(Debug)]
 struct Foo {
     x: isize
 }
 
+impl From<Foo> for isize {
+    fn from(val: Foo) -> isize {
+        val.x
+    }
+}
+
 fn main() {
     println!("{}", Foo { x: 1 } as isize); //~ non-primitive cast: `Foo` as `isize` [E0605]
 }
diff --git a/src/test/ui/nonscalar-cast.stderr b/src/test/ui/nonscalar-cast.stderr
index 9338688b037..2a703712187 100644
--- a/src/test/ui/nonscalar-cast.stderr
+++ b/src/test/ui/nonscalar-cast.stderr
@@ -1,10 +1,10 @@
 error[E0605]: non-primitive cast: `Foo` as `isize`
-  --> $DIR/nonscalar-cast.rs:7:20
+  --> $DIR/nonscalar-cast.rs:15:20
    |
 LL |     println!("{}", Foo { x: 1 } as isize);
-   |                    ^^^^^^^^^^^^^^^^^^^^^
+   |                    ^^^^^^^^^^^^^^^^^^^^^ help: consider using the `From` trait instead: `isize::from(Foo { x: 1 })`
    |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/order-dependent-cast-inference.stderr b/src/test/ui/order-dependent-cast-inference.stderr
index ad50b415869..9f4ac0fea36 100644
--- a/src/test/ui/order-dependent-cast-inference.stderr
+++ b/src/test/ui/order-dependent-cast-inference.stderr
@@ -1,10 +1,8 @@
 error[E0641]: cannot cast to a pointer of an unknown kind
-  --> $DIR/order-dependent-cast-inference.rs:5:17
+  --> $DIR/order-dependent-cast-inference.rs:5:22
    |
 LL |     let mut y = 0 as *const _;
-   |                 ^^^^^--------
-   |                      |
-   |                      help: consider giving more type information
+   |                      ^^^^^^^^ needs more type information
    |
    = note: the type information given here is insufficient to check whether the pointer cast is valid
 
diff --git a/src/test/ui/tag-variant-cast-non-nullary.fixed b/src/test/ui/tag-variant-cast-non-nullary.fixed
new file mode 100644
index 00000000000..53e68c2ac6a
--- /dev/null
+++ b/src/test/ui/tag-variant-cast-non-nullary.fixed
@@ -0,0 +1,20 @@
+// run-rustfix
+#![allow(dead_code, unused_variables)]
+enum NonNullary {
+    Nullary,
+    Other(isize),
+}
+
+impl From<NonNullary> for isize {
+    fn from(val: NonNullary) -> isize {
+        match val {
+            NonNullary::Nullary => 0,
+            NonNullary::Other(i) => i,
+        }
+    }
+}
+
+fn main() {
+    let v = NonNullary::Nullary;
+    let val = isize::from(v); //~ ERROR non-primitive cast: `NonNullary` as `isize` [E0605]
+}
diff --git a/src/test/ui/tag-variant-cast-non-nullary.rs b/src/test/ui/tag-variant-cast-non-nullary.rs
index bb34e82cdca..0d0c6188ad1 100644
--- a/src/test/ui/tag-variant-cast-non-nullary.rs
+++ b/src/test/ui/tag-variant-cast-non-nullary.rs
@@ -1,8 +1,19 @@
+// run-rustfix
+#![allow(dead_code, unused_variables)]
 enum NonNullary {
     Nullary,
     Other(isize),
 }
 
+impl From<NonNullary> for isize {
+    fn from(val: NonNullary) -> isize {
+        match val {
+            NonNullary::Nullary => 0,
+            NonNullary::Other(i) => i,
+        }
+    }
+}
+
 fn main() {
     let v = NonNullary::Nullary;
     let val = v as isize; //~ ERROR non-primitive cast: `NonNullary` as `isize` [E0605]
diff --git a/src/test/ui/tag-variant-cast-non-nullary.stderr b/src/test/ui/tag-variant-cast-non-nullary.stderr
index 87ec20f20d7..ae2f5a7aead 100644
--- a/src/test/ui/tag-variant-cast-non-nullary.stderr
+++ b/src/test/ui/tag-variant-cast-non-nullary.stderr
@@ -1,10 +1,10 @@
 error[E0605]: non-primitive cast: `NonNullary` as `isize`
-  --> $DIR/tag-variant-cast-non-nullary.rs:8:15
+  --> $DIR/tag-variant-cast-non-nullary.rs:19:15
    |
 LL |     let val = v as isize;
-   |               ^^^^^^^^^^
+   |               ^^^^^^^^^^ help: consider using the `From` trait instead: `isize::from(v)`
    |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr
index 4fbbf347528..a6b7e35b488 100644
--- a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr
+++ b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr
@@ -16,9 +16,7 @@ error[E0605]: non-primitive cast: `impl std::fmt::Debug` as `&'static str`
   --> $DIR/never_reveal_concrete_type.rs:14:13
    |
 LL |     let _ = x as &'static str;
-   |             ^^^^^^^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |             ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/uninhabited/uninhabited-enum-cast.stderr b/src/test/ui/uninhabited/uninhabited-enum-cast.stderr
index a39af7832f8..a9f10dfec99 100644
--- a/src/test/ui/uninhabited/uninhabited-enum-cast.stderr
+++ b/src/test/ui/uninhabited/uninhabited-enum-cast.stderr
@@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `E` as `isize`
   --> $DIR/uninhabited-enum-cast.rs:4:20
    |
 LL |     println!("{}", (e as isize).to_string());
-   |                    ^^^^^^^^^^^^
-   |
-   = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
+   |                    ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error: aborting due to previous error