- 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.
/// [`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"),
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| {
from_method,
from_ok,
from_usize,
+ from_trait,
fundamental,
future,
Future,
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;
"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,
"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};
};
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();
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),
+ );
}
}
}
--> $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
--> $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
--> $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
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
--> $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
--> $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
--> $DIR/const-eval-overflow-4b.rs:25:13
|
LL | : [u32; 5i8 as char as usize]
- | ^^^^^^^^^^^
+ | ^^^^^^^^^^^ invalid cast
error: aborting due to 3 previous errors
--> $DIR/E0604.rs:2:5
|
LL | 1u32 as char;
- | ^^^^^^^^^^^^
+ | ^^^^^^^^^^^^ invalid cast
error: aborting due to previous error
--> $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
--> $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
--> $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
--> $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
}
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
}
}
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
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
--> $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
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> {
--> $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
--> $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
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
--> $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
--> $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
--> $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
--- /dev/null
+// 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]
+}
+// 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]
}
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
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
--- /dev/null
+// 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]
+}
+// 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]
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
--> $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
--> $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