@@ -63,6 +63,22 @@ struct TopInfo<'tcx> {
6363///              found type `std::result::Result<_, _>` 
6464/// ``` 
6565span :  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