@@ -43,6 +43,7 @@ use rustc_middle::ty::subst::SubstsRef;
4343use rustc_middle:: ty:: { self , Ty , TypeAndMut , TypeFoldable } ;
4444use rustc_session:: lint;
4545use rustc_session:: Session ;
46+ use rustc_span:: symbol:: sym;
4647use rustc_span:: Span ;
4748use rustc_trait_selection:: traits;
4849use rustc_trait_selection:: traits:: error_reporting:: report_object_safety_error;
@@ -333,23 +334,87 @@ impl<'a, 'tcx> CastCheck<'tcx> {
333334 "only `u8` can be cast as `char`, not `{}`" ,
334335 self . expr_ty
335336 )
337+ . span_label ( self . span , "invalid cast" )
336338 . emit ( ) ;
337339 }
338340 CastError :: NonScalar => {
339- type_error_struct ! (
341+ let mut err = type_error_struct ! (
340342 fcx. tcx. sess,
341343 self . span,
342344 self . expr_ty,
343345 E0605 ,
344346 "non-primitive cast: `{}` as `{}`" ,
345347 self . expr_ty,
346348 fcx. ty_to_string( self . cast_ty)
347- )
348- . note (
349- "an `as` expression can only be used to convert between \
350- primitive types. Consider using the `From` trait",
351- )
352- . emit ( ) ;
349+ ) ;
350+ let mut sugg = None ;
351+ if let ty:: Ref ( reg, _, mutbl) = self . cast_ty . kind {
352+ if fcx
353+ . try_coerce (
354+ self . expr ,
355+ fcx. tcx . mk_ref ( reg, TypeAndMut { ty : self . expr_ty , mutbl } ) ,
356+ self . cast_ty ,
357+ AllowTwoPhase :: No ,
358+ )
359+ . is_ok ( )
360+ {
361+ sugg = Some ( format ! ( "&{}" , mutbl. prefix_str( ) ) ) ;
362+ }
363+ }
364+ if let Some ( sugg) = sugg {
365+ err. span_label ( self . span , "invalid cast" ) ;
366+ err. span_suggestion_verbose (
367+ self . expr . span . shrink_to_lo ( ) ,
368+ "borrow the value for the cast to be valid" ,
369+ sugg,
370+ Applicability :: MachineApplicable ,
371+ ) ;
372+ } else if !matches ! (
373+ self . cast_ty. kind,
374+ ty:: FnDef ( ..) | ty:: FnPtr ( ..) | ty:: Closure ( ..)
375+ ) {
376+ let mut label = true ;
377+ // Check `impl From<self.expr_ty> for self.cast_ty {}` for accurate suggestion:
378+ if let Ok ( snippet) = fcx. tcx . sess . source_map ( ) . span_to_snippet ( self . expr . span ) {
379+ if let Some ( from_trait) = fcx. tcx . get_diagnostic_item ( sym:: from_trait) {
380+ let ty = fcx. resolve_vars_if_possible ( & self . cast_ty ) ;
381+ // Erase regions to avoid panic in `prove_value` when calling
382+ // `type_implements_trait`.
383+ let ty = fcx. tcx . erase_regions ( & ty) ;
384+ let expr_ty = fcx. resolve_vars_if_possible ( & self . expr_ty ) ;
385+ let expr_ty = fcx. tcx . erase_regions ( & expr_ty) ;
386+ let ty_params = fcx. tcx . mk_substs_trait ( expr_ty, & [ ] ) ;
387+ // Check for infer types because cases like `Option<{integer}>` would
388+ // panic otherwise.
389+ if !expr_ty. has_infer_types ( )
390+ && fcx. tcx . type_implements_trait ( (
391+ from_trait,
392+ ty,
393+ ty_params,
394+ fcx. param_env ,
395+ ) )
396+ {
397+ label = false ;
398+ err. span_suggestion (
399+ self . span ,
400+ "consider using the `From` trait instead" ,
401+ format ! ( "{}::from({})" , self . cast_ty, snippet) ,
402+ Applicability :: MaybeIncorrect ,
403+ ) ;
404+ }
405+ }
406+ }
407+ let msg = "an `as` expression can only be used to convert between primitive \
408+ types or to coerce to a specific trait object";
409+ if label {
410+ err. span_label ( self . span , msg) ;
411+ } else {
412+ err. note ( msg) ;
413+ }
414+ } else {
415+ err. span_label ( self . span , "invalid cast" ) ;
416+ }
417+ err. emit ( ) ;
353418 }
354419 CastError :: SizedUnsizedCast => {
355420 use crate :: structured_errors:: { SizedUnsizedCastError , StructuredDiagnostic } ;
@@ -370,21 +435,22 @@ impl<'a, 'tcx> CastCheck<'tcx> {
370435 } ;
371436 let mut err = struct_span_err ! (
372437 fcx. tcx. sess,
373- self . span,
438+ if unknown_cast_to { self . cast_span } else { self . span } ,
374439 E0641 ,
375440 "cannot cast {} a pointer of an unknown kind" ,
376441 if unknown_cast_to { "to" } else { "from" }
377442 ) ;
378- err. note (
379- "the type information given here is insufficient to check whether \
380- the pointer cast is valid",
381- ) ;
382443 if unknown_cast_to {
383- err. span_suggestion_short (
384- self . cast_span ,
385- "consider giving more type information" ,
386- String :: new ( ) ,
387- Applicability :: Unspecified ,
444+ err. span_label ( self . cast_span , "needs more type information" ) ;
445+ err. note (
446+ "the type information given here is insufficient to check whether \
447+ the pointer cast is valid",
448+ ) ;
449+ } else {
450+ err. span_label (
451+ self . span ,
452+ "the type information given here is insufficient to check whether \
453+ the pointer cast is valid",
388454 ) ;
389455 }
390456 err. emit ( ) ;
@@ -438,13 +504,16 @@ impl<'a, 'tcx> CastCheck<'tcx> {
438504 Ok ( s) => {
439505 err. span_suggestion (
440506 self . cast_span ,
441- "try casting to a `Box` instead" ,
507+ "you can cast to a `Box` instead" ,
442508 format ! ( "Box<{}>" , s) ,
443509 Applicability :: MachineApplicable ,
444510 ) ;
445511 }
446512 Err ( _) => {
447- err. span_help ( self . cast_span , & format ! ( "did you mean `Box<{}>`?" , tstr) ) ;
513+ err. span_help (
514+ self . cast_span ,
515+ & format ! ( "you might have meant `Box<{}>`" , tstr) ,
516+ ) ;
448517 }
449518 }
450519 }
0 commit comments