@@ -63,6 +63,22 @@ struct TopInfo<'tcx> {
6363 /// found type `std::result::Result<_, _>`
6464 /// ```
6565 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 > > ,
6682}
6783
6884impl < ' tcx > FnCtxt < ' _ , ' tcx > {
@@ -120,7 +136,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
120136 span : Option < Span > ,
121137 origin_expr : bool ,
122138 ) {
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) ;
124141 }
125142
126143 /// Type check the given `pat` against the `expected` type
@@ -161,8 +178,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
161178 self . check_pat_struct ( pat, qpath, fields, etc, expected, def_bm, ti)
162179 }
163180 PatKind :: Or ( pats) => {
181+ let parent_pat = Some ( pat) ;
164182 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 } ) ;
166184 }
167185 expected
168186 }
@@ -501,7 +519,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
501519
502520 fn check_pat_ident (
503521 & self ,
504- pat : & Pat < ' _ > ,
522+ pat : & ' tcx Pat < ' tcx > ,
505523 ba : hir:: BindingAnnotation ,
506524 var_id : HirId ,
507525 sub : Option < & ' tcx Pat < ' tcx > > ,
@@ -546,7 +564,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
546564 }
547565
548566 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 } ) ;
550568 }
551569
552570 local_ty
@@ -647,6 +665,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
647665 variant_ty
648666 } else {
649667 for field in fields {
668+ let ti = TopInfo { parent_pat : Some ( & pat) , ..ti } ;
650669 self . check_pat ( & field. pat , self . tcx . types . err , def_bm, ti) ;
651670 }
652671 return self . tcx . types . err ;
@@ -656,9 +675,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
656675 self . demand_eqtype_pat ( pat. span , expected, pat_ty, ti) ;
657676
658677 // 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) {
662679 pat_ty
663680 } else {
664681 self . tcx . types . err
@@ -696,18 +713,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
696713 }
697714
698715 // 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) =
701719 self . demand_suptype_with_origin ( & self . pattern_cause ( ti, pat. span ) , expected, pat_ty)
702720 {
703- err . emit ( ) ;
721+ self . emit_bad_pat_path ( err , pat . span , res , pat_res , segments , ti . parent_pat ) ;
704722 }
705723 pat_ty
706724 }
707725
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+
708763 fn check_pat_tuple_struct (
709764 & self ,
710- pat : & Pat < ' _ > ,
765+ pat : & ' tcx Pat < ' tcx > ,
711766 qpath : & hir:: QPath < ' _ > ,
712767 subpats : & ' tcx [ & ' tcx Pat < ' tcx > ] ,
713768 ddpos : Option < usize > ,
@@ -717,8 +772,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
717772 ) -> Ty < ' tcx > {
718773 let tcx = self . tcx ;
719774 let on_error = || {
775+ let parent_pat = Some ( pat) ;
720776 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 } ) ;
722778 }
723779 } ;
724780 let report_unexpected_res = |res : Res | {
@@ -793,7 +849,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
793849 } ;
794850 for ( i, subpat) in subpats. iter ( ) . enumerate_and_adjust ( variant. fields . len ( ) , ddpos) {
795851 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 } ) ;
797853
798854 self . tcx . check_stability ( variant. fields [ i] . did , Some ( pat. hir_id ) , subpat. span ) ;
799855 }
@@ -938,8 +994,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
938994 fn check_struct_pat_fields (
939995 & self ,
940996 adt_ty : Ty < ' tcx > ,
941- pat_id : HirId ,
942- span : Span ,
997+ pat : & ' tcx Pat < ' tcx > ,
943998 variant : & ' tcx ty:: VariantDef ,
944999 fields : & ' tcx [ hir:: FieldPat < ' tcx > ] ,
9451000 etc : bool ,
@@ -950,7 +1005,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
9501005
9511006 let ( substs, adt) = match adt_ty. kind {
9521007 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" ) ,
9541009 } ;
9551010 let kind_name = adt. variant_descr ( ) ;
9561011
@@ -983,7 +1038,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
9831038 . get ( & ident)
9841039 . map ( |( i, f) | {
9851040 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) ;
9871042 self . field_ty ( span, f, substs)
9881043 } )
9891044 . unwrap_or_else ( || {
@@ -994,7 +1049,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
9941049 }
9951050 } ;
9961051
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 } ) ;
9981053 }
9991054
10001055 let mut unmentioned_fields = variant
@@ -1017,7 +1072,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10171072 if variant. is_field_list_non_exhaustive ( ) && !adt. did . is_local ( ) && !etc {
10181073 struct_span_err ! (
10191074 tcx. sess,
1020- span,
1075+ pat . span,
10211076 E0638 ,
10221077 "`..` required with {} marked as non-exhaustive" ,
10231078 kind_name
@@ -1029,14 +1084,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10291084 if kind_name == "union" {
10301085 if fields. len ( ) != 1 {
10311086 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" )
10331088 . emit ( ) ;
10341089 }
10351090 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 ( ) ;
10371092 }
10381093 } 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) ;
10401095 }
10411096 no_field_errors
10421097 }
@@ -1196,7 +1251,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11961251
11971252 fn check_pat_ref (
11981253 & self ,
1199- pat : & Pat < ' _ > ,
1254+ pat : & ' tcx Pat < ' tcx > ,
12001255 inner : & ' tcx Pat < ' tcx > ,
12011256 mutbl : hir:: Mutability ,
12021257 expected : Ty < ' tcx > ,
@@ -1236,7 +1291,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12361291 } else {
12371292 ( tcx. types . err , tcx. types . err )
12381293 } ;
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 } ) ;
12401295 rptr_ty
12411296 }
12421297
0 commit comments