@@ -13,7 +13,7 @@ use rustc_middle::ty::adjustment::AllowTwoPhase;
13
13
use rustc_middle:: ty:: error:: { ExpectedFound , TypeError } ;
14
14
use rustc_middle:: ty:: print:: with_no_trimmed_paths;
15
15
use rustc_middle:: ty:: { self , AssocItem , Ty , TypeAndMut } ;
16
- use rustc_span:: symbol:: sym;
16
+ use rustc_span:: symbol:: { sym, Symbol } ;
17
17
use rustc_span:: { BytePos , Span } ;
18
18
19
19
use super :: method:: probe;
@@ -24,7 +24,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24
24
pub fn emit_coerce_suggestions (
25
25
& self ,
26
26
err : & mut DiagnosticBuilder < ' _ > ,
27
- expr : & hir:: Expr < ' _ > ,
27
+ expr : & hir:: Expr < ' tcx > ,
28
28
expr_ty : Ty < ' tcx > ,
29
29
expected : Ty < ' tcx > ,
30
30
expected_ty_expr : Option < & ' tcx hir:: Expr < ' tcx > > ,
@@ -109,7 +109,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
109
109
110
110
pub fn demand_coerce (
111
111
& self ,
112
- expr : & hir:: Expr < ' _ > ,
112
+ expr : & hir:: Expr < ' tcx > ,
113
113
checked_ty : Ty < ' tcx > ,
114
114
expected : Ty < ' tcx > ,
115
115
expected_ty_expr : Option < & ' tcx hir:: Expr < ' tcx > > ,
@@ -129,7 +129,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
129
129
/// will be permitted if the diverges flag is currently "always".
130
130
pub fn demand_coerce_diag (
131
131
& self ,
132
- expr : & hir:: Expr < ' _ > ,
132
+ expr : & hir:: Expr < ' tcx > ,
133
133
checked_ty : Ty < ' tcx > ,
134
134
expected : Ty < ' tcx > ,
135
135
expected_ty_expr : Option < & ' tcx hir:: Expr < ' tcx > > ,
@@ -338,31 +338,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
338
338
} )
339
339
. collect ( ) ;
340
340
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) ,
359
352
vec ! [
360
- ( expr. span. shrink_to_lo( ) , format!( "{}(" , variant) ) ,
353
+ ( expr. span. shrink_to_lo( ) , format!( "{}{}(" , prefix , variant) ) ,
361
354
( 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
+ }
366
375
}
367
376
}
368
377
}
@@ -483,33 +492,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
483
492
}
484
493
}
485
494
486
- crate fn is_hir_id_from_struct_pattern_shorthand_field (
495
+ crate fn maybe_get_struct_pattern_shorthand_field (
487
496
& 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 ) ;
502
521
}
503
522
}
504
523
}
524
+ _ => { }
505
525
}
506
- false
526
+
527
+ None
507
528
}
508
529
509
530
/// 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 ,
513
534
_ => None ,
514
535
}
515
536
}
@@ -547,7 +568,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
547
568
/// `&mut`!".
548
569
pub fn check_ref (
549
570
& self ,
550
- expr : & hir:: Expr < ' _ > ,
571
+ expr : & hir:: Expr < ' tcx > ,
551
572
checked_ty : Ty < ' tcx > ,
552
573
expected : Ty < ' tcx > ,
553
574
) -> Option < ( Span , & ' static str , String , Applicability , bool /* verbose */ ) > {
@@ -565,9 +586,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
565
586
s. strip_prefix ( old) . map ( |stripped| new. to_string ( ) + stripped)
566
587
} ;
567
588
568
- let is_struct_pat_shorthand_field =
569
- self . is_hir_id_from_struct_pattern_shorthand_field ( expr. hir_id , sp) ;
570
-
571
589
// `ExprKind::DropTemps` is semantically irrelevant for these suggestions.
572
590
let expr = expr. peel_drop_temps ( ) ;
573
591
@@ -661,11 +679,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
661
679
false ,
662
680
) ) ;
663
681
}
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 ! ( "" ) ,
668
686
} ;
687
+
669
688
if let Some ( hir:: Node :: Expr ( hir:: Expr {
670
689
kind : hir:: ExprKind :: Assign ( left_expr, ..) ,
671
690
..
@@ -695,14 +714,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
695
714
hir:: Mutability :: Mut => (
696
715
sp,
697
716
"consider mutably borrowing here" ,
698
- format ! ( "{}&mut {}" , field_name , sugg_expr) ,
717
+ format ! ( "{}&mut {}" , prefix , sugg_expr) ,
699
718
Applicability :: MachineApplicable ,
700
719
false ,
701
720
) ,
702
721
hir:: Mutability :: Not => (
703
722
sp,
704
723
"consider borrowing here" ,
705
- format ! ( "{}&{}" , field_name , sugg_expr) ,
724
+ format ! ( "{}&{}" , prefix , sugg_expr) ,
706
725
Applicability :: MachineApplicable ,
707
726
false ,
708
727
) ,
@@ -846,32 +865,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
846
865
if self . infcx . type_is_copy_modulo_regions ( self . param_env , expected, sp)
847
866
|| checked_ty. is_box ( )
848
867
{
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
+ ) ) ;
875
895
}
876
896
}
877
897
}
0 commit comments