1
- use crate :: check:: coercion:: Coerce ;
2
1
use crate :: check:: FnCtxt ;
3
2
use rustc_infer:: infer:: InferOk ;
4
3
use rustc_trait_selection:: infer:: InferCtxtExt as _;
@@ -9,7 +8,6 @@ use rustc_ast::util::parser::PREC_POSTFIX;
9
8
use rustc_errors:: { Applicability , DiagnosticBuilder } ;
10
9
use rustc_hir as hir;
11
10
use rustc_hir:: { is_range_literal, Node } ;
12
- use rustc_middle:: traits:: ObligationCauseCode ;
13
11
use rustc_middle:: ty:: adjustment:: AllowTwoPhase ;
14
12
use rustc_middle:: ty:: { self , AssocItem , Ty , TypeAndMut } ;
15
13
use rustc_span:: symbol:: sym;
@@ -376,7 +374,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
376
374
expr : & hir:: Expr < ' _ > ,
377
375
checked_ty : Ty < ' tcx > ,
378
376
expected : Ty < ' tcx > ,
379
- ) -> Option < ( Span , & ' static str , String ) > {
377
+ ) -> Option < ( Span , & ' static str , String , Applicability ) > {
380
378
let sm = self . sess ( ) . source_map ( ) ;
381
379
let sp = expr. span ;
382
380
if sm. is_imported ( sp) {
@@ -395,16 +393,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
395
393
// `ExprKind::DropTemps` is semantically irrelevant for these suggestions.
396
394
let expr = expr. peel_drop_temps ( ) ;
397
395
396
+ let remove_prefix = |s : String , prefix : & str | {
397
+ if s. starts_with ( prefix) { Some ( s[ prefix. len ( ) ..] . to_string ( ) ) } else { None }
398
+ } ;
399
+
398
400
match ( & expr. kind , & expected. kind , & checked_ty. kind ) {
399
401
( _, & ty:: Ref ( _, exp, _) , & ty:: Ref ( _, check, _) ) => match ( & exp. kind , & check. kind ) {
400
402
( & ty:: Str , & ty:: Array ( arr, _) | & ty:: Slice ( arr) ) if arr == self . tcx . types . u8 => {
401
403
if let hir:: ExprKind :: Lit ( _) = expr. kind {
402
404
if let Ok ( src) = sm. span_to_snippet ( sp) {
403
- if src. starts_with ( "b\" " ) {
405
+ if let Some ( src) = remove_prefix ( src , "b\" " ) {
404
406
return Some ( (
405
407
sp,
406
408
"consider removing the leading `b`" ,
407
- src[ 1 ..] . to_string ( ) ,
409
+ format ! ( "\" {}" , src) ,
410
+ Applicability :: MachineApplicable ,
408
411
) ) ;
409
412
}
410
413
}
@@ -413,11 +416,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
413
416
( & ty:: Array ( arr, _) | & ty:: Slice ( arr) , & ty:: Str ) if arr == self . tcx . types . u8 => {
414
417
if let hir:: ExprKind :: Lit ( _) = expr. kind {
415
418
if let Ok ( src) = sm. span_to_snippet ( sp) {
416
- if src. starts_with ( '"' ) {
419
+ if let Some ( src) = remove_prefix ( src , " \" " ) {
417
420
return Some ( (
418
421
sp,
419
422
"consider adding a leading `b`" ,
420
- format ! ( "b{}" , src) ,
423
+ format ! ( "b\" {}" , src) ,
424
+ Applicability :: MachineApplicable ,
421
425
) ) ;
422
426
}
423
427
}
@@ -470,7 +474,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
470
474
let sugg_expr = if needs_parens { format ! ( "({})" , src) } else { src } ;
471
475
472
476
if let Some ( sugg) = self . can_use_as_ref ( expr) {
473
- return Some ( sugg) ;
477
+ return Some ( (
478
+ sugg. 0 ,
479
+ sugg. 1 ,
480
+ sugg. 2 ,
481
+ Applicability :: MachineApplicable ,
482
+ ) ) ;
474
483
}
475
484
let field_name = if is_struct_pat_shorthand_field {
476
485
format ! ( "{}: " , sugg_expr)
@@ -495,6 +504,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
495
504
"consider dereferencing here to assign to the mutable \
496
505
borrowed piece of memory",
497
506
format ! ( "*{}" , src) ,
507
+ Applicability :: MachineApplicable ,
498
508
) ) ;
499
509
}
500
510
}
@@ -505,11 +515,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
505
515
sp,
506
516
"consider mutably borrowing here" ,
507
517
format ! ( "{}&mut {}" , field_name, sugg_expr) ,
518
+ Applicability :: MachineApplicable ,
508
519
) ,
509
520
hir:: Mutability :: Not => (
510
521
sp,
511
522
"consider borrowing here" ,
512
523
format ! ( "{}&{}" , field_name, sugg_expr) ,
524
+ Applicability :: MachineApplicable ,
513
525
) ,
514
526
} ) ;
515
527
}
@@ -526,51 +538,84 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
526
538
// We have `&T`, check if what was expected was `T`. If so,
527
539
// we may want to suggest removing a `&`.
528
540
if sm. is_imported ( expr. span ) {
529
- if let Ok ( code ) = sm. span_to_snippet ( sp) {
530
- if code . starts_with ( '&' ) {
541
+ if let Ok ( src ) = sm. span_to_snippet ( sp) {
542
+ if let Some ( src ) = remove_prefix ( src , "&" ) {
531
543
return Some ( (
532
544
sp,
533
545
"consider removing the borrow" ,
534
- code[ 1 ..] . to_string ( ) ,
546
+ src,
547
+ Applicability :: MachineApplicable ,
535
548
) ) ;
536
549
}
537
550
}
538
551
return None ;
539
552
}
540
553
if let Ok ( code) = sm. span_to_snippet ( expr. span ) {
541
- return Some ( ( sp, "consider removing the borrow" , code) ) ;
554
+ return Some ( (
555
+ sp,
556
+ "consider removing the borrow" ,
557
+ code,
558
+ Applicability :: MachineApplicable ,
559
+ ) ) ;
542
560
}
543
561
}
544
562
(
545
563
_,
546
- & ty:: RawPtr ( TypeAndMut { ty : _ , mutbl : hir :: Mutability :: Not } ) ,
547
- & ty:: Ref ( _, _ , hir :: Mutability :: Not ) ,
564
+ & ty:: RawPtr ( TypeAndMut { ty : ty_b , mutbl : mutbl_b } ) ,
565
+ & ty:: Ref ( _, ty_a , mutbl_a ) ,
548
566
) => {
549
- let cause = self . cause ( rustc_span:: DUMMY_SP , ObligationCauseCode :: ExprAssignable ) ;
550
- // We don't ever need two-phase here since we throw out the result of the coercion
551
- let coerce = Coerce :: new ( self , cause, AllowTwoPhase :: No ) ;
552
-
553
- if let Some ( steps) =
554
- coerce. autoderef ( sp, checked_ty) . skip ( 1 ) . find_map ( |( referent_ty, steps) | {
555
- coerce
556
- . unify (
557
- coerce. tcx . mk_ptr ( ty:: TypeAndMut {
558
- mutbl : hir:: Mutability :: Not ,
559
- ty : referent_ty,
560
- } ) ,
561
- expected,
562
- )
563
- . ok ( )
564
- . map ( |_| steps)
565
- } )
566
- {
567
- // The pointer type implements `Copy` trait so the suggestion is always valid.
568
- if let Ok ( code) = sm. span_to_snippet ( sp) {
569
- if code. starts_with ( '&' ) {
570
- let derefs = "*" . repeat ( steps - 1 ) ;
571
- let message = "consider dereferencing the reference" ;
572
- let suggestion = format ! ( "&{}{}" , derefs, code[ 1 ..] . to_string( ) ) ;
573
- return Some ( ( sp, message, suggestion) ) ;
567
+ if let Some ( steps) = self . deref_steps ( ty_a, ty_b) {
568
+ // Only suggest valid if dereferencing needed.
569
+ if steps > 0 {
570
+ // The pointer type implements `Copy` trait so the suggestion is always valid.
571
+ if let Ok ( src) = sm. span_to_snippet ( sp) {
572
+ let derefs = "*" . repeat ( steps) ;
573
+ match mutbl_b {
574
+ hir:: Mutability :: Mut => match mutbl_a {
575
+ hir:: Mutability :: Mut => {
576
+ if let Some ( src) = remove_prefix ( src, "&mut " ) {
577
+ return Some ( (
578
+ sp,
579
+ "consider dereferencing" ,
580
+ format ! ( "&mut {}{}" , derefs, src) ,
581
+ Applicability :: MachineApplicable ,
582
+ ) ) ;
583
+ }
584
+ }
585
+ hir:: Mutability :: Not => {
586
+ if let Some ( src) = remove_prefix ( src, "&" ) {
587
+ return Some ( (
588
+ sp,
589
+ "consider dereferencing" ,
590
+ format ! ( "&mut {}{}" , derefs, src) ,
591
+ Applicability :: Unspecified ,
592
+ ) ) ;
593
+ }
594
+ }
595
+ } ,
596
+ hir:: Mutability :: Not => match mutbl_a {
597
+ hir:: Mutability :: Mut => {
598
+ if let Some ( src) = remove_prefix ( src, "&mut " ) {
599
+ return Some ( (
600
+ sp,
601
+ "consider dereferencing" ,
602
+ format ! ( "&{}{}" , derefs, src) ,
603
+ Applicability :: MachineApplicable ,
604
+ ) ) ;
605
+ }
606
+ }
607
+ hir:: Mutability :: Not => {
608
+ if let Some ( src) = remove_prefix ( src, "&" ) {
609
+ return Some ( (
610
+ sp,
611
+ "consider dereferencing" ,
612
+ format ! ( "&{}{}" , derefs, src) ,
613
+ Applicability :: MachineApplicable ,
614
+ ) ) ;
615
+ }
616
+ }
617
+ } ,
618
+ }
574
619
}
575
620
}
576
621
}
@@ -616,7 +661,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
616
661
} else {
617
662
format ! ( "*{}" , code)
618
663
} ;
619
- return Some ( ( sp, message, suggestion) ) ;
664
+ return Some ( ( sp, message, suggestion, Applicability :: MachineApplicable ) ) ;
620
665
}
621
666
}
622
667
}
0 commit comments