Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tweak "non-primitive cast" error #73361

Merged
merged 1 commit into from
Jun 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/libcore/convert/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_parse/parser/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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| {
Expand Down
1 change: 1 addition & 0 deletions src/librustc_span/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ symbols! {
from_method,
from_ok,
from_usize,
from_trait,
fundamental,
future,
Future,
Expand Down
107 changes: 88 additions & 19 deletions src/librustc_typeck/check/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -333,23 +334,87 @@ 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,
E0605,
"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};
Expand All @@ -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();
Expand Down Expand Up @@ -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),
);
}
}
}
Expand Down
4 changes: 1 addition & 3 deletions src/test/ui/cast/cast-from-nil.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
8 changes: 2 additions & 6 deletions src/test/ui/cast/cast-to-bare-fn.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 1 addition & 3 deletions src/test/ui/cast/cast-to-nil.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 1 addition & 3 deletions src/test/ui/closures/closure-no-fn-3.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
8 changes: 2 additions & 6 deletions src/test/ui/coercion/coerce-to-bang-cast.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/error-codes/E0604.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
8 changes: 2 additions & 6 deletions src/test/ui/error-codes/E0605.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
6 changes: 2 additions & 4 deletions src/test/ui/error-festival.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 1 addition & 3 deletions src/test/ui/fat-ptr-cast.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 1 addition & 3 deletions src/test/ui/issues/issue-10991.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-16048.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/test/ui/issues/issue-16048.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-17441.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 5 additions & 2 deletions src/test/ui/issues/issue-22289.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Loading