@@ -13,7 +13,7 @@ use rustc_middle::ty::adjustment::AllowTwoPhase;
1313use rustc_middle:: ty:: error:: { ExpectedFound , TypeError } ;
1414use rustc_middle:: ty:: print:: with_no_trimmed_paths;
1515use rustc_middle:: ty:: { self , AssocItem , Ty , TypeAndMut } ;
16- use rustc_span:: symbol:: sym;
16+ use rustc_span:: symbol:: { sym, Symbol } ;
1717use rustc_span:: { BytePos , Span } ;
1818
1919use super :: method:: probe;
@@ -24,7 +24,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2424 pub fn emit_coerce_suggestions (
2525 & self ,
2626 err : & mut DiagnosticBuilder < ' _ > ,
27- expr : & hir:: Expr < ' _ > ,
27+ expr : & hir:: Expr < ' tcx > ,
2828 expr_ty : Ty < ' tcx > ,
2929 expected : Ty < ' tcx > ,
3030 expected_ty_expr : Option < & ' tcx hir:: Expr < ' tcx > > ,
@@ -109,7 +109,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
109109
110110 pub fn demand_coerce (
111111 & self ,
112- expr : & hir:: Expr < ' _ > ,
112+ expr : & hir:: Expr < ' tcx > ,
113113 checked_ty : Ty < ' tcx > ,
114114 expected : Ty < ' tcx > ,
115115 expected_ty_expr : Option < & ' tcx hir:: Expr < ' tcx > > ,
@@ -129,7 +129,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
129129 /// will be permitted if the diverges flag is currently "always".
130130 pub fn demand_coerce_diag (
131131 & self ,
132- expr : & hir:: Expr < ' _ > ,
132+ expr : & hir:: Expr < ' tcx > ,
133133 checked_ty : Ty < ' tcx > ,
134134 expected : Ty < ' tcx > ,
135135 expected_ty_expr : Option < & ' tcx hir:: Expr < ' tcx > > ,
@@ -338,31 +338,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
338338 } )
339339 . collect ( ) ;
340340
341- if let [ variant] = & compatible_variants[ ..] {
342- // Just a single matching variant.
343- err. multipart_suggestion (
344- & format ! ( "try wrapping the expression in `{}`" , variant) ,
345- vec ! [
346- ( expr. span. shrink_to_lo( ) , format!( "{}(" , variant) ) ,
347- ( expr. span. shrink_to_hi( ) , ")" . to_string( ) ) ,
348- ] ,
349- Applicability :: MaybeIncorrect ,
350- ) ;
351- } else if compatible_variants. len ( ) > 1 {
352- // More than one matching variant.
353- err. multipart_suggestions (
354- & format ! (
355- "try wrapping the expression in a variant of `{}`" ,
356- self . tcx. def_path_str( expected_adt. did)
357- ) ,
358- compatible_variants. into_iter ( ) . map ( |variant| {
341+ let prefix = match self . maybe_get_struct_pattern_shorthand_field ( expr) {
342+ Some ( ident) => format ! ( "{}: " , ident) ,
343+ None => format ! ( "" ) ,
344+ } ;
345+
346+ match & compatible_variants[ ..] {
347+ [ ] => { /* No variants to format */ }
348+ [ variant] => {
349+ // Just a single matching variant.
350+ err. multipart_suggestion_verbose (
351+ & format ! ( "try wrapping the expression in `{}`" , variant) ,
359352 vec ! [
360- ( expr. span. shrink_to_lo( ) , format!( "{}(" , variant) ) ,
353+ ( expr. span. shrink_to_lo( ) , format!( "{}{}(" , prefix , variant) ) ,
361354 ( expr. span. shrink_to_hi( ) , ")" . to_string( ) ) ,
362- ]
363- } ) ,
364- Applicability :: MaybeIncorrect ,
365- ) ;
355+ ] ,
356+ Applicability :: MaybeIncorrect ,
357+ ) ;
358+ }
359+ _ => {
360+ // More than one matching variant.
361+ err. multipart_suggestions (
362+ & format ! (
363+ "try wrapping the expression in a variant of `{}`" ,
364+ self . tcx. def_path_str( expected_adt. did)
365+ ) ,
366+ compatible_variants. into_iter ( ) . map ( |variant| {
367+ vec ! [
368+ ( expr. span. shrink_to_lo( ) , format!( "{}{}(" , prefix, variant) ) ,
369+ ( expr. span. shrink_to_hi( ) , ")" . to_string( ) ) ,
370+ ]
371+ } ) ,
372+ Applicability :: MaybeIncorrect ,
373+ ) ;
374+ }
366375 }
367376 }
368377 }
@@ -483,33 +492,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
483492 }
484493 }
485494
486- crate fn is_hir_id_from_struct_pattern_shorthand_field (
495+ crate fn maybe_get_struct_pattern_shorthand_field (
487496 & self ,
488- hir_id : hir:: HirId ,
489- sp : Span ,
490- ) -> bool {
491- let sm = self . sess ( ) . source_map ( ) ;
492- let parent_id = self . tcx . hir ( ) . get_parent_node ( hir_id) ;
493- if let Some ( parent) = self . tcx . hir ( ) . find ( parent_id) {
494- // Account for fields
495- if let Node :: Expr ( hir:: Expr { kind : hir:: ExprKind :: Struct ( _, fields, ..) , .. } ) = parent
496- {
497- if let Ok ( src) = sm. span_to_snippet ( sp) {
498- for field in * fields {
499- if field. ident . as_str ( ) == src && field. is_shorthand {
500- return true ;
501- }
497+ expr : & hir:: Expr < ' _ > ,
498+ ) -> Option < Symbol > {
499+ let hir = self . tcx . hir ( ) ;
500+ let local = match expr {
501+ hir:: Expr {
502+ kind :
503+ hir:: ExprKind :: Path ( hir:: QPath :: Resolved (
504+ None ,
505+ hir:: Path {
506+ res : hir:: def:: Res :: Local ( _) ,
507+ segments : [ hir:: PathSegment { ident, .. } ] ,
508+ ..
509+ } ,
510+ ) ) ,
511+ ..
512+ } => Some ( ident) ,
513+ _ => None ,
514+ } ?;
515+
516+ match hir. find ( hir. get_parent_node ( expr. hir_id ) ) ? {
517+ Node :: Expr ( hir:: Expr { kind : hir:: ExprKind :: Struct ( _, fields, ..) , .. } ) => {
518+ for field in * fields {
519+ if field. ident . name == local. name && field. is_shorthand {
520+ return Some ( local. name ) ;
502521 }
503522 }
504523 }
524+ _ => { }
505525 }
506- false
526+
527+ None
507528 }
508529
509530 /// If the given `HirId` corresponds to a block with a trailing expression, return that expression
510- crate fn maybe_get_block_expr ( & self , hir_id : hir:: HirId ) -> Option < & ' tcx hir:: Expr < ' tcx > > {
511- match self . tcx . hir ( ) . find ( hir_id ) ? {
512- Node :: Expr ( hir:: Expr { kind : hir:: ExprKind :: Block ( block, ..) , .. } ) => block. expr ,
531+ crate fn maybe_get_block_expr ( & self , expr : & hir:: Expr < ' tcx > ) -> Option < & ' tcx hir:: Expr < ' tcx > > {
532+ match expr {
533+ hir:: Expr { kind : hir:: ExprKind :: Block ( block, ..) , .. } => block. expr ,
513534 _ => None ,
514535 }
515536 }
@@ -547,7 +568,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
547568 /// `&mut`!".
548569 pub fn check_ref (
549570 & self ,
550- expr : & hir:: Expr < ' _ > ,
571+ expr : & hir:: Expr < ' tcx > ,
551572 checked_ty : Ty < ' tcx > ,
552573 expected : Ty < ' tcx > ,
553574 ) -> Option < ( Span , & ' static str , String , Applicability , bool /* verbose */ ) > {
@@ -565,9 +586,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
565586 s. strip_prefix ( old) . map ( |stripped| new. to_string ( ) + stripped)
566587 } ;
567588
568- let is_struct_pat_shorthand_field =
569- self . is_hir_id_from_struct_pattern_shorthand_field ( expr. hir_id , sp) ;
570-
571589 // `ExprKind::DropTemps` is semantically irrelevant for these suggestions.
572590 let expr = expr. peel_drop_temps ( ) ;
573591
@@ -661,11 +679,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
661679 false ,
662680 ) ) ;
663681 }
664- let field_name = if is_struct_pat_shorthand_field {
665- format ! ( "{}: " , sugg_expr )
666- } else {
667- String :: new ( )
682+
683+ let prefix = match self . maybe_get_struct_pattern_shorthand_field ( expr ) {
684+ Some ( ident ) => format ! ( "{}: " , ident ) ,
685+ None => format ! ( "" ) ,
668686 } ;
687+
669688 if let Some ( hir:: Node :: Expr ( hir:: Expr {
670689 kind : hir:: ExprKind :: Assign ( left_expr, ..) ,
671690 ..
@@ -695,14 +714,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
695714 hir:: Mutability :: Mut => (
696715 sp,
697716 "consider mutably borrowing here" ,
698- format ! ( "{}&mut {}" , field_name , sugg_expr) ,
717+ format ! ( "{}&mut {}" , prefix , sugg_expr) ,
699718 Applicability :: MachineApplicable ,
700719 false ,
701720 ) ,
702721 hir:: Mutability :: Not => (
703722 sp,
704723 "consider borrowing here" ,
705- format ! ( "{}&{}" , field_name , sugg_expr) ,
724+ format ! ( "{}&{}" , prefix , sugg_expr) ,
706725 Applicability :: MachineApplicable ,
707726 false ,
708727 ) ,
@@ -846,32 +865,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
846865 if self . infcx . type_is_copy_modulo_regions ( self . param_env , expected, sp)
847866 || checked_ty. is_box ( )
848867 {
849- if let Ok ( code) = sm. span_to_snippet ( expr. span ) {
850- let message = if checked_ty. is_box ( ) {
851- "consider unboxing the value"
852- } else if checked_ty. is_region_ptr ( ) {
853- "consider dereferencing the borrow"
854- } else {
855- "consider dereferencing the type"
856- } ;
857- let ( span, suggestion) = if is_struct_pat_shorthand_field {
858- ( expr. span , format ! ( "{}: *{}" , code, code) )
859- } else if self . is_else_if_block ( expr) {
860- // Don't suggest nonsense like `else *if`
861- return None ;
862- } else if let Some ( expr) = self . maybe_get_block_expr ( expr. hir_id ) {
863- ( expr. span . shrink_to_lo ( ) , "*" . to_string ( ) )
864- } else {
865- ( expr. span . shrink_to_lo ( ) , "*" . to_string ( ) )
866- } ;
867- return Some ( (
868- span,
869- message,
870- suggestion,
871- Applicability :: MachineApplicable ,
872- true ,
873- ) ) ;
874- }
868+ let message = if checked_ty. is_box ( ) {
869+ "consider unboxing the value"
870+ } else if checked_ty. is_region_ptr ( ) {
871+ "consider dereferencing the borrow"
872+ } else {
873+ "consider dereferencing the type"
874+ } ;
875+ let prefix = match self . maybe_get_struct_pattern_shorthand_field ( expr) {
876+ Some ( ident) => format ! ( "{}: " , ident) ,
877+ None => format ! ( "" ) ,
878+ } ;
879+ let ( span, suggestion) = if self . is_else_if_block ( expr) {
880+ // Don't suggest nonsense like `else *if`
881+ return None ;
882+ } else if let Some ( expr) = self . maybe_get_block_expr ( expr) {
883+ // prefix should be empty here..
884+ ( expr. span . shrink_to_lo ( ) , "*" . to_string ( ) )
885+ } else {
886+ ( expr. span . shrink_to_lo ( ) , format ! ( "{}*" , prefix) )
887+ } ;
888+ return Some ( (
889+ span,
890+ message,
891+ suggestion,
892+ Applicability :: MachineApplicable ,
893+ true ,
894+ ) ) ;
875895 }
876896 }
877897 }
0 commit comments