@@ -63,6 +63,22 @@ struct TopInfo<'tcx> {
63
63
/// found type `std::result::Result<_, _>`
64
64
/// ```
65
65
span : Option < Span > ,
66
+ /// This refers to the parent pattern. Used to provide extra diagnostic information on errors.
67
+ /// ```text
68
+ /// error[E0308]: mismatched types
69
+ /// --> $DIR/const-in-struct-pat.rs:8:17
70
+ /// |
71
+ /// L | struct f;
72
+ /// | --------- unit struct defined here
73
+ /// ...
74
+ /// L | let Thing { f } = t;
75
+ /// | ^
76
+ /// | |
77
+ /// | expected struct `std::string::String`, found struct `f`
78
+ /// | `f` is interpreted as a unit struct, not a new binding
79
+ /// | help: bind the struct field to a different name instead: `f: other_f`
80
+ /// ```
81
+ parent_pat : Option < & ' tcx Pat < ' tcx > > ,
66
82
}
67
83
68
84
impl < ' tcx > FnCtxt < ' _ , ' tcx > {
@@ -120,7 +136,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
120
136
span : Option < Span > ,
121
137
origin_expr : bool ,
122
138
) {
123
- self . check_pat ( pat, expected, INITIAL_BM , TopInfo { expected, origin_expr, span } ) ;
139
+ let info = TopInfo { expected, origin_expr, span, parent_pat : None } ;
140
+ self . check_pat ( pat, expected, INITIAL_BM , info) ;
124
141
}
125
142
126
143
/// Type check the given `pat` against the `expected` type
@@ -161,8 +178,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
161
178
self . check_pat_struct ( pat, qpath, fields, etc, expected, def_bm, ti)
162
179
}
163
180
PatKind :: Or ( pats) => {
181
+ let parent_pat = Some ( pat) ;
164
182
for pat in pats {
165
- self . check_pat ( pat, expected, def_bm, ti ) ;
183
+ self . check_pat ( pat, expected, def_bm, TopInfo { parent_pat , ..ti } ) ;
166
184
}
167
185
expected
168
186
}
@@ -501,7 +519,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
501
519
502
520
fn check_pat_ident (
503
521
& self ,
504
- pat : & Pat < ' _ > ,
522
+ pat : & ' tcx Pat < ' tcx > ,
505
523
ba : hir:: BindingAnnotation ,
506
524
var_id : HirId ,
507
525
sub : Option < & ' tcx Pat < ' tcx > > ,
@@ -546,7 +564,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
546
564
}
547
565
548
566
if let Some ( p) = sub {
549
- self . check_pat ( & p, expected, def_bm, ti ) ;
567
+ self . check_pat ( & p, expected, def_bm, TopInfo { parent_pat : Some ( & pat ) , ..ti } ) ;
550
568
}
551
569
552
570
local_ty
@@ -647,6 +665,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
647
665
variant_ty
648
666
} else {
649
667
for field in fields {
668
+ let ti = TopInfo { parent_pat : Some ( & pat) , ..ti } ;
650
669
self . check_pat ( & field. pat , self . tcx . types . err , def_bm, ti) ;
651
670
}
652
671
return self . tcx . types . err ;
@@ -656,9 +675,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
656
675
self . demand_eqtype_pat ( pat. span , expected, pat_ty, ti) ;
657
676
658
677
// Type-check subpatterns.
659
- if self
660
- . check_struct_pat_fields ( pat_ty, pat. hir_id , pat. span , variant, fields, etc, def_bm, ti)
661
- {
678
+ if self . check_struct_pat_fields ( pat_ty, & pat, variant, fields, etc, def_bm, ti) {
662
679
pat_ty
663
680
} else {
664
681
self . tcx . types . err
@@ -696,18 +713,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
696
713
}
697
714
698
715
// Type-check the path.
699
- let pat_ty = self . instantiate_value_path ( segments, opt_ty, res, pat. span , pat. hir_id ) . 0 ;
700
- if let Some ( mut err) =
716
+ let ( pat_ty, pat_res) =
717
+ self . instantiate_value_path ( segments, opt_ty, res, pat. span , pat. hir_id ) ;
718
+ if let Some ( err) =
701
719
self . demand_suptype_with_origin ( & self . pattern_cause ( ti, pat. span ) , expected, pat_ty)
702
720
{
703
- err . emit ( ) ;
721
+ self . emit_bad_pat_path ( err , pat . span , res , pat_res , segments , ti . parent_pat ) ;
704
722
}
705
723
pat_ty
706
724
}
707
725
726
+ fn emit_bad_pat_path (
727
+ & self ,
728
+ mut e : DiagnosticBuilder < ' _ > ,
729
+ pat_span : Span ,
730
+ res : Res ,
731
+ pat_res : Res ,
732
+ segments : & ' b [ hir:: PathSegment < ' b > ] ,
733
+ parent_pat : Option < & Pat < ' _ > > ,
734
+ ) {
735
+ if let Some ( span) = self . tcx . hir ( ) . res_span ( pat_res) {
736
+ e. span_label ( span, & format ! ( "{} defined here" , res. descr( ) ) ) ;
737
+ if let [ hir:: PathSegment { ident, .. } ] = & * segments {
738
+ e. span_label (
739
+ pat_span,
740
+ & format ! (
741
+ "`{}` is interpreted as {} {}, not a new binding" ,
742
+ ident,
743
+ res. article( ) ,
744
+ res. descr( ) ,
745
+ ) ,
746
+ ) ;
747
+ let ( msg, sugg) = match parent_pat {
748
+ Some ( Pat { kind : hir:: PatKind :: Struct ( ..) , .. } ) => (
749
+ "bind the struct field to a different name instead" ,
750
+ format ! ( "{}: other_{}" , ident, ident. as_str( ) . to_lowercase( ) ) ,
751
+ ) ,
752
+ _ => (
753
+ "introduce a new binding instead" ,
754
+ format ! ( "other_{}" , ident. as_str( ) . to_lowercase( ) ) ,
755
+ ) ,
756
+ } ;
757
+ e. span_suggestion ( ident. span , msg, sugg, Applicability :: HasPlaceholders ) ;
758
+ }
759
+ }
760
+ e. emit ( ) ;
761
+ }
762
+
708
763
fn check_pat_tuple_struct (
709
764
& self ,
710
- pat : & Pat < ' _ > ,
765
+ pat : & ' tcx Pat < ' tcx > ,
711
766
qpath : & hir:: QPath < ' _ > ,
712
767
subpats : & ' tcx [ & ' tcx Pat < ' tcx > ] ,
713
768
ddpos : Option < usize > ,
@@ -717,8 +772,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
717
772
) -> Ty < ' tcx > {
718
773
let tcx = self . tcx ;
719
774
let on_error = || {
775
+ let parent_pat = Some ( pat) ;
720
776
for pat in subpats {
721
- self . check_pat ( & pat, tcx. types . err , def_bm, ti ) ;
777
+ self . check_pat ( & pat, tcx. types . err , def_bm, TopInfo { parent_pat , ..ti } ) ;
722
778
}
723
779
} ;
724
780
let report_unexpected_res = |res : Res | {
@@ -793,7 +849,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
793
849
} ;
794
850
for ( i, subpat) in subpats. iter ( ) . enumerate_and_adjust ( variant. fields . len ( ) , ddpos) {
795
851
let field_ty = self . field_ty ( subpat. span , & variant. fields [ i] , substs) ;
796
- self . check_pat ( & subpat, field_ty, def_bm, ti ) ;
852
+ self . check_pat ( & subpat, field_ty, def_bm, TopInfo { parent_pat : Some ( & pat ) , ..ti } ) ;
797
853
798
854
self . tcx . check_stability ( variant. fields [ i] . did , Some ( pat. hir_id ) , subpat. span ) ;
799
855
}
@@ -938,8 +994,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
938
994
fn check_struct_pat_fields (
939
995
& self ,
940
996
adt_ty : Ty < ' tcx > ,
941
- pat_id : HirId ,
942
- span : Span ,
997
+ pat : & ' tcx Pat < ' tcx > ,
943
998
variant : & ' tcx ty:: VariantDef ,
944
999
fields : & ' tcx [ hir:: FieldPat < ' tcx > ] ,
945
1000
etc : bool ,
@@ -950,7 +1005,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
950
1005
951
1006
let ( substs, adt) = match adt_ty. kind {
952
1007
ty:: Adt ( adt, substs) => ( substs, adt) ,
953
- _ => span_bug ! ( span, "struct pattern is not an ADT" ) ,
1008
+ _ => span_bug ! ( pat . span, "struct pattern is not an ADT" ) ,
954
1009
} ;
955
1010
let kind_name = adt. variant_descr ( ) ;
956
1011
@@ -983,7 +1038,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
983
1038
. get ( & ident)
984
1039
. map ( |( i, f) | {
985
1040
self . write_field_index ( field. hir_id , * i) ;
986
- self . tcx . check_stability ( f. did , Some ( pat_id ) , span) ;
1041
+ self . tcx . check_stability ( f. did , Some ( pat . hir_id ) , span) ;
987
1042
self . field_ty ( span, f, substs)
988
1043
} )
989
1044
. unwrap_or_else ( || {
@@ -994,7 +1049,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
994
1049
}
995
1050
} ;
996
1051
997
- self . check_pat ( & field. pat , field_ty, def_bm, ti ) ;
1052
+ self . check_pat ( & field. pat , field_ty, def_bm, TopInfo { parent_pat : Some ( & pat ) , ..ti } ) ;
998
1053
}
999
1054
1000
1055
let mut unmentioned_fields = variant
@@ -1017,7 +1072,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1017
1072
if variant. is_field_list_non_exhaustive ( ) && !adt. did . is_local ( ) && !etc {
1018
1073
struct_span_err ! (
1019
1074
tcx. sess,
1020
- span,
1075
+ pat . span,
1021
1076
E0638 ,
1022
1077
"`..` required with {} marked as non-exhaustive" ,
1023
1078
kind_name
@@ -1029,14 +1084,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1029
1084
if kind_name == "union" {
1030
1085
if fields. len ( ) != 1 {
1031
1086
tcx. sess
1032
- . struct_span_err ( span, "union patterns should have exactly one field" )
1087
+ . struct_span_err ( pat . span , "union patterns should have exactly one field" )
1033
1088
. emit ( ) ;
1034
1089
}
1035
1090
if etc {
1036
- tcx. sess . struct_span_err ( span, "`..` cannot be used in union patterns" ) . emit ( ) ;
1091
+ tcx. sess . struct_span_err ( pat . span , "`..` cannot be used in union patterns" ) . emit ( ) ;
1037
1092
}
1038
1093
} else if !etc && !unmentioned_fields. is_empty ( ) {
1039
- self . error_unmentioned_fields ( span, & unmentioned_fields, variant) ;
1094
+ self . error_unmentioned_fields ( pat . span , & unmentioned_fields, variant) ;
1040
1095
}
1041
1096
no_field_errors
1042
1097
}
@@ -1196,7 +1251,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1196
1251
1197
1252
fn check_pat_ref (
1198
1253
& self ,
1199
- pat : & Pat < ' _ > ,
1254
+ pat : & ' tcx Pat < ' tcx > ,
1200
1255
inner : & ' tcx Pat < ' tcx > ,
1201
1256
mutbl : hir:: Mutability ,
1202
1257
expected : Ty < ' tcx > ,
@@ -1236,7 +1291,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1236
1291
} else {
1237
1292
( tcx. types . err , tcx. types . err )
1238
1293
} ;
1239
- self . check_pat ( & inner, inner_ty, def_bm, ti ) ;
1294
+ self . check_pat ( & inner, inner_ty, def_bm, TopInfo { parent_pat : Some ( & pat ) , ..ti } ) ;
1240
1295
rptr_ty
1241
1296
}
1242
1297
0 commit comments