1- use crate :: check:: coercion:: Coerce ;
21use crate :: check:: FnCtxt ;
32use rustc_infer:: infer:: InferOk ;
43use rustc_trait_selection:: infer:: InferCtxtExt as _;
@@ -9,7 +8,6 @@ use rustc_ast::util::parser::PREC_POSTFIX;
98use rustc_errors:: { Applicability , DiagnosticBuilder } ;
109use rustc_hir as hir;
1110use rustc_hir:: { is_range_literal, Node } ;
12- use rustc_middle:: traits:: ObligationCauseCode ;
1311use rustc_middle:: ty:: adjustment:: AllowTwoPhase ;
1412use rustc_middle:: ty:: { self , AssocItem , Ty , TypeAndMut } ;
1513use rustc_span:: symbol:: sym;
@@ -376,7 +374,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
376374 expr : & hir:: Expr < ' _ > ,
377375 checked_ty : Ty < ' tcx > ,
378376 expected : Ty < ' tcx > ,
379- ) -> Option < ( Span , & ' static str , String ) > {
377+ ) -> Option < ( Span , & ' static str , String , Applicability ) > {
380378 let sm = self . sess ( ) . source_map ( ) ;
381379 let sp = expr. span ;
382380 if sm. is_imported ( sp) {
@@ -395,16 +393,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
395393 // `ExprKind::DropTemps` is semantically irrelevant for these suggestions.
396394 let expr = expr. peel_drop_temps ( ) ;
397395
396+ let remove_prefix = |s : String , prefix : & str | {
397+ if s. starts_with ( prefix) { Some ( s[ prefix. len ( ) ..] . to_string ( ) ) } else { None }
398+ } ;
399+
398400 match ( & expr. kind , & expected. kind , & checked_ty. kind ) {
399401 ( _, & ty:: Ref ( _, exp, _) , & ty:: Ref ( _, check, _) ) => match ( & exp. kind , & check. kind ) {
400402 ( & ty:: Str , & ty:: Array ( arr, _) | & ty:: Slice ( arr) ) if arr == self . tcx . types . u8 => {
401403 if let hir:: ExprKind :: Lit ( _) = expr. kind {
402404 if let Ok ( src) = sm. span_to_snippet ( sp) {
403- if src. starts_with ( "b\" " ) {
405+ if let Some ( src) = remove_prefix ( src , "b\" " ) {
404406 return Some ( (
405407 sp,
406408 "consider removing the leading `b`" ,
407- src[ 1 ..] . to_string ( ) ,
409+ format ! ( "\" {}" , src) ,
410+ Applicability :: MachineApplicable ,
408411 ) ) ;
409412 }
410413 }
@@ -413,11 +416,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
413416 ( & ty:: Array ( arr, _) | & ty:: Slice ( arr) , & ty:: Str ) if arr == self . tcx . types . u8 => {
414417 if let hir:: ExprKind :: Lit ( _) = expr. kind {
415418 if let Ok ( src) = sm. span_to_snippet ( sp) {
416- if src. starts_with ( '"' ) {
419+ if let Some ( src) = remove_prefix ( src , " \" " ) {
417420 return Some ( (
418421 sp,
419422 "consider adding a leading `b`" ,
420- format ! ( "b{}" , src) ,
423+ format ! ( "b\" {}" , src) ,
424+ Applicability :: MachineApplicable ,
421425 ) ) ;
422426 }
423427 }
@@ -470,7 +474,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
470474 let sugg_expr = if needs_parens { format ! ( "({})" , src) } else { src } ;
471475
472476 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+ ) ) ;
474483 }
475484 let field_name = if is_struct_pat_shorthand_field {
476485 format ! ( "{}: " , sugg_expr)
@@ -495,6 +504,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
495504 "consider dereferencing here to assign to the mutable \
496505 borrowed piece of memory",
497506 format ! ( "*{}" , src) ,
507+ Applicability :: MachineApplicable ,
498508 ) ) ;
499509 }
500510 }
@@ -505,11 +515,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
505515 sp,
506516 "consider mutably borrowing here" ,
507517 format ! ( "{}&mut {}" , field_name, sugg_expr) ,
518+ Applicability :: MachineApplicable ,
508519 ) ,
509520 hir:: Mutability :: Not => (
510521 sp,
511522 "consider borrowing here" ,
512523 format ! ( "{}&{}" , field_name, sugg_expr) ,
524+ Applicability :: MachineApplicable ,
513525 ) ,
514526 } ) ;
515527 }
@@ -526,51 +538,84 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
526538 // We have `&T`, check if what was expected was `T`. If so,
527539 // we may want to suggest removing a `&`.
528540 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 , "&" ) {
531543 return Some ( (
532544 sp,
533545 "consider removing the borrow" ,
534- code[ 1 ..] . to_string ( ) ,
546+ src,
547+ Applicability :: MachineApplicable ,
535548 ) ) ;
536549 }
537550 }
538551 return None ;
539552 }
540553 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+ ) ) ;
542560 }
543561 }
544562 (
545563 _,
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 ) ,
548566 ) => {
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+ }
574619 }
575620 }
576621 }
@@ -616,7 +661,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
616661 } else {
617662 format ! ( "*{}" , code)
618663 } ;
619- return Some ( ( sp, message, suggestion) ) ;
664+ return Some ( ( sp, message, suggestion, Applicability :: MachineApplicable ) ) ;
620665 }
621666 }
622667 }
0 commit comments