@@ -43,6 +43,7 @@ use rustc_middle::ty::subst::SubstsRef;
43
43
use rustc_middle:: ty:: { self , Ty , TypeAndMut , TypeFoldable } ;
44
44
use rustc_session:: lint;
45
45
use rustc_session:: Session ;
46
+ use rustc_span:: symbol:: sym;
46
47
use rustc_span:: Span ;
47
48
use rustc_trait_selection:: traits;
48
49
use rustc_trait_selection:: traits:: error_reporting:: report_object_safety_error;
@@ -333,23 +334,87 @@ impl<'a, 'tcx> CastCheck<'tcx> {
333
334
"only `u8` can be cast as `char`, not `{}`" ,
334
335
self . expr_ty
335
336
)
337
+ . span_label ( self . span , "invalid cast" )
336
338
. emit ( ) ;
337
339
}
338
340
CastError :: NonScalar => {
339
- type_error_struct ! (
341
+ let mut err = type_error_struct ! (
340
342
fcx. tcx. sess,
341
343
self . span,
342
344
self . expr_ty,
343
345
E0605 ,
344
346
"non-primitive cast: `{}` as `{}`" ,
345
347
self . expr_ty,
346
348
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 ( ) ;
353
418
}
354
419
CastError :: SizedUnsizedCast => {
355
420
use crate :: structured_errors:: { SizedUnsizedCastError , StructuredDiagnostic } ;
@@ -370,21 +435,22 @@ impl<'a, 'tcx> CastCheck<'tcx> {
370
435
} ;
371
436
let mut err = struct_span_err ! (
372
437
fcx. tcx. sess,
373
- self . span,
438
+ if unknown_cast_to { self . cast_span } else { self . span } ,
374
439
E0641 ,
375
440
"cannot cast {} a pointer of an unknown kind" ,
376
441
if unknown_cast_to { "to" } else { "from" }
377
442
) ;
378
- err. note (
379
- "the type information given here is insufficient to check whether \
380
- the pointer cast is valid",
381
- ) ;
382
443
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",
388
454
) ;
389
455
}
390
456
err. emit ( ) ;
@@ -438,13 +504,16 @@ impl<'a, 'tcx> CastCheck<'tcx> {
438
504
Ok ( s) => {
439
505
err. span_suggestion (
440
506
self . cast_span ,
441
- "try casting to a `Box` instead" ,
507
+ "you can cast to a `Box` instead" ,
442
508
format ! ( "Box<{}>" , s) ,
443
509
Applicability :: MachineApplicable ,
444
510
) ;
445
511
}
446
512
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
+ ) ;
448
517
}
449
518
}
450
519
}
0 commit comments