@@ -16,7 +16,7 @@ use rustc_hir::{
1616} ; 
1717use  rustc_infer:: infer; 
1818use  rustc_middle:: traits:: PatternOriginExpr ; 
19- use  rustc_middle:: ty:: { self ,  Ty ,  TypeVisitableExt } ; 
19+ use  rustc_middle:: ty:: { self ,  AdtDef ,   Ty ,  TypeVisitableExt } ; 
2020use  rustc_middle:: { bug,  span_bug} ; 
2121use  rustc_session:: lint:: builtin:: NON_EXHAUSTIVE_OMITTED_PATTERNS ; 
2222use  rustc_session:: parse:: feature_err; 
@@ -160,10 +160,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
160160
161161/// Mode for adjusting the expected type and binding mode. 
162162#[ derive( Clone ,  Copy ,  Debug ,  PartialEq ,  Eq ) ]  
163- enum  AdjustMode  { 
163+ enum  AdjustMode < ' tcx >  { 
164164    /// Peel off all immediate reference types. If the `deref_patterns` feature is enabled, this 
165165/// also peels library-defined smart pointer ADTs. 
166- Peel  {  kind :  PeelKind  } , 
166+ Peel  {  kind :  PeelKind < ' tcx >  } , 
167167    /// Reset binding mode to the initial mode. 
168168/// Used for destructuring assignment, where we don't want any match ergonomics. 
169169Reset , 
@@ -173,14 +173,22 @@ enum AdjustMode {
173173
174174/// Restrictions on what types to peel when adjusting the expected type and binding mode. 
175175#[ derive( Clone ,  Copy ,  Debug ,  PartialEq ,  Eq ) ]  
176- enum  PeelKind  { 
176+ enum  PeelKind < ' tcx >  { 
177177    /// Only peel reference types. This is used for explicit deref patterns. 
178178RefOnly , 
179179    /// If `deref_patterns` is enabled, this also peels library-defined smart pointer ADTs, except 
180180/// for `until_adt` if the pattern is a constructor. Otherwise this is the same as `RefOnly`. 
181181/// See [`ResolvedPat`] for more information. 
182- // TODO: add `ResolvedPat` and `until_adt`. 
183-     Overloaded , 
182+ Overloaded  {  until_adt :  Option < AdtDef < ' tcx > >  } , 
183+ } 
184+ 
185+ impl < ' tcx >  AdjustMode < ' tcx >  { 
186+     const  fn  peel_until_adt ( opt_adt_def :  Option < AdtDef < ' tcx > > )  -> AdjustMode < ' tcx >  { 
187+         AdjustMode :: Peel  {  kind :  PeelKind :: Overloaded  {  until_adt :  opt_adt_def }  } 
188+     } 
189+     const  fn  peel_all ( )  -> AdjustMode < ' tcx >  { 
190+         AdjustMode :: peel_until_adt ( None ) 
191+     } 
184192} 
185193
186194/// `ref mut` bindings (explicit or match-ergonomics) are not allowed behind an `&` reference. 
@@ -266,11 +274,12 @@ enum InheritedRefMatchRule {
266274/// 
267275/// `ResolvedPat` contains the information from resolution needed to determine match ergonomics 
268276/// adjustments, plus a callback to finish checking the pattern once we know its adjusted type. 
269- // TODO: add an `adt_def: Option<DefId>` field to handle the `Cow` case above. 
270- struct  ResolvedPat < F :  ?Sized >  { 
277+ struct  ResolvedPat < ' tcx ,  F :  ?Sized >  { 
271278    /// For path patterns, this must be `Some(res)`, where `res` is the resolution of the pattern's 
272279/// `QPath`. Otherwise, this is `None`. 
273280path_res :  Option < Res > , 
281+     /// If applicable, identifies the ADT that the pattern matches against. 
282+ pat_adt_def :  Option < AdtDef < ' tcx > > , 
274283    /// Given the expected type of the scrutinee and the [`PatInfo`] after applying match ergonomics 
275284/// adjustments, finish checking the pattern. 
276285check :  F , 
@@ -356,7 +365,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
356365
357366        // For patterns containing paths, we need the path's resolution to determine whether to 
358367        // implicitly dereference the scrutinee before matching. 
359-         let  resolved_pat:  Option < & ResolvedPat < dyn  Fn ( Ty < ' tcx > ,  PatInfo < ' tcx > )  -> Ty < ' tcx > > >  =
368+         let  resolved_pat:  Option < & ResolvedPat < ' tcx ,   dyn  Fn ( Ty < ' tcx > ,  PatInfo < ' tcx > )  -> Ty < ' tcx > > >  =
360369            match  pat. kind  { 
361370                PatKind :: Expr ( PatExpr  {  kind :  PatExprKind :: Path ( qpath) ,  hir_id,  span } )  => { 
362371                    Some  {  0 :  & self . check_pat_path ( * hir_id,  pat. hir_id ,  * span,  qpath,  & ti)  } 
@@ -369,7 +378,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
369378                } 
370379                _ => None , 
371380            } ; 
372-         let  adjust_mode = self . calc_adjust_mode ( pat,  resolved_pat. and_then ( |r| r. path_res ) ) ; 
381+         let  adjust_mode = self . calc_adjust_mode ( 
382+             pat, 
383+             resolved_pat. and_then ( |r| r. path_res ) , 
384+             resolved_pat. and_then ( |r| r. pat_adt_def ) , 
385+         ) ; 
373386        let  ( expected,  binding_mode,  max_ref_mutbl)  =
374387            self . calc_default_binding_mode ( pat,  expected,  binding_mode,  adjust_mode,  max_ref_mutbl) ; 
375388        let  pat_info = PatInfo  { 
@@ -484,7 +497,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
484497        pat :  & ' tcx  Pat < ' tcx > , 
485498        expected :  Ty < ' tcx > , 
486499        def_br :  ByRef , 
487-         adjust_mode :  AdjustMode , 
500+         adjust_mode :  AdjustMode < ' tcx > , 
488501        max_ref_mutbl :  MutblCap , 
489502    )  -> ( Ty < ' tcx > ,  ByRef ,  MutblCap )  { 
490503        #[ cfg( debug_assertions) ]  
@@ -506,7 +519,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
506519    /// How should the binding mode and expected type be adjusted? 
507520/// 
508521/// When the pattern is a path pattern, `opt_path_res` must be `Some(res)`. 
509- fn  calc_adjust_mode ( & self ,  pat :  & ' tcx  Pat < ' tcx > ,  opt_path_res :  Option < Res > )  -> AdjustMode  { 
522+ /// When the pattern contains a path (such as a struct pattern or tuple struct pattern), 
523+ /// `pat_adt_def` should be `Some(adt)` if the path resolved to an ADT constructor. 
524+ fn  calc_adjust_mode ( 
525+         & self , 
526+         pat :  & ' tcx  Pat < ' tcx > , 
527+         opt_path_res :  Option < Res > , 
528+         pat_adt_def :  Option < AdtDef < ' tcx > > , 
529+     )  -> AdjustMode < ' tcx >  { 
510530        // When we perform destructuring assignment, we disable default match bindings, which are 
511531        // unintuitive in this context. 
512532        if  !pat. default_binding_modes  { 
@@ -519,14 +539,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
519539            | PatKind :: TupleStruct ( ..) 
520540            | PatKind :: Tuple ( ..) 
521541            | PatKind :: Range ( ..) 
522-             | PatKind :: Slice ( ..)  => AdjustMode :: Peel   {   kind :   PeelKind :: Overloaded   } , 
542+             | PatKind :: Slice ( ..)  => AdjustMode :: peel_until_adt ( pat_adt_def ) , 
523543            // When checking an explicit deref pattern, only peel reference types. 
524544            // FIXME(deref_patterns): If box patterns and deref patterns need to coexist, box 
525545            // patterns may want `PeelKind::Overloaded`, stopping on encountering a box. 
526546            | PatKind :: Box ( _) 
527547            | PatKind :: Deref ( _)  => AdjustMode :: Peel  {  kind :  PeelKind :: RefOnly  } , 
528548            // A never pattern behaves somewhat like a literal or unit variant. 
529-             PatKind :: Never  => AdjustMode :: Peel   {   kind :   PeelKind :: Overloaded   } , 
549+             PatKind :: Never  => AdjustMode :: peel_all ( ) , 
530550            PatKind :: Expr ( PatExpr  {  kind :  PatExprKind :: Path ( _) ,  .. } )  => match  opt_path_res. unwrap ( )  { 
531551                // These constants can be of a reference type, e.g. `const X: &u8 = &0;`. 
532552                // Peeling the reference types too early will cause type checking failures. 
@@ -536,7 +556,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
536556                // could successfully compile. The former being `Self` requires a unit struct. 
537557                // In either case, and unlike constants, the pattern itself cannot be 
538558                // a reference type wherefore peeling doesn't give up any expressiveness. 
539-                 _ => AdjustMode :: Peel   {   kind :   PeelKind :: Overloaded   } , 
559+                 _ => AdjustMode :: peel_until_adt ( pat_adt_def ) , 
540560            } , 
541561
542562            // String and byte-string literals result in types `&str` and `&[u8]` respectively. 
@@ -546,7 +566,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
546566            // Call `resolve_vars_if_possible` here for inline const blocks. 
547567            PatKind :: Expr ( lt)  => match  self . resolve_vars_if_possible ( self . check_pat_expr_unadjusted ( lt) ) . kind ( )  { 
548568                ty:: Ref ( ..)  => AdjustMode :: Pass , 
549-                 _ => AdjustMode :: Peel  {  kind :  PeelKind :: Overloaded  } , 
569+                 // If an inline const pattern has a library-defined pointer-like type and 
570+                 // `deref_patterns` is enabled, don't implicitly add deref patterns for its ADT. 
571+                 // Nothing in the library that implements `DerefPure` supports structural equality, 
572+                 // but we don't check that until `const_to_pat` in THIR construction. By avoiding 
573+                 // type errors here, we can get a more meaningful error there. 
574+                 ty:: Adt ( adt,  _)  => AdjustMode :: peel_until_adt ( Some ( * adt) ) , 
575+                 _ => AdjustMode :: peel_all ( ) 
550576            } , 
551577
552578            // Ref patterns are complicated, we handle them in `check_pat_ref`. 
@@ -576,7 +602,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
576602fn  peel_off_references ( 
577603        & self , 
578604        pat :  & ' tcx  Pat < ' tcx > , 
579-         peel_kind :  PeelKind , 
605+         peel_kind :  PeelKind < ' tcx > , 
580606        expected :  Ty < ' tcx > , 
581607        mut  def_br :  ByRef , 
582608        mut  max_ref_mutbl :  MutblCap , 
@@ -610,13 +636,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
610636                } ) ; 
611637                inner_ty
612638            }  else  if  deref_patterns
613-                 && peel_kind ==  PeelKind :: Overloaded 
639+                 && let   PeelKind :: Overloaded   {  until_adt  }  = peel_kind 
614640                // For simplicity, only apply overloaded derefs if `expected` is a known ADT. 
615641                // FIXME(deref_patterns): we'll get better diagnostics for users trying to 
616642                // implicitly deref generics if we allow them here, but primitives, tuples, and 
617643                // inference vars definitely should be stopped. Figure out what makes most sense. 
618-                 // TODO: stop peeling if the pattern is a constructor for the scrutinee type 
619-                 && expected. is_adt ( ) 
644+                 && let  ty:: Adt ( scrutinee_adt,  _)  = * expected. kind ( ) 
645+                 // Don't peel if the pattern type already matches the scrutinee. E.g., stop here if 
646+                 // matching on a `Cow<'a, T>` scrutinee with a `Cow::Owned(_)` pattern. 
647+                 && until_adt != Some ( scrutinee_adt) 
620648            { 
621649                // At this point, the pattern isn't able to match `expected` without peeling. Check 
622650                // that it implements `Deref` before assuming it's a smart pointer, to get a normal 
@@ -1231,9 +1259,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12311259        qpath :  & hir:: QPath < ' tcx > , 
12321260        fields :  & ' tcx  [ hir:: PatField < ' tcx > ] , 
12331261        has_rest_pat :  bool , 
1234-     )  -> ResolvedPat < impl  Fn ( Ty < ' tcx > ,  PatInfo < ' tcx > )  -> Ty < ' tcx > >  { 
1262+     )  -> ResolvedPat < ' tcx ,   impl  Fn ( Ty < ' tcx > ,  PatInfo < ' tcx > )  -> Ty < ' tcx > >  { 
12351263        // Resolve the path and check the definition for errors. 
12361264        let  variant_and_pat_ty = self . check_struct_path ( qpath,  pat. hir_id ) ; 
1265+         let  pat_adt_def = variant_and_pat_ty. ok ( ) . and_then ( |( _,  pat_ty) | pat_ty. ty_adt_def ( ) ) ; 
12371266
12381267        let  check = move  |expected :  Ty < ' tcx > ,  pat_info :  PatInfo < ' tcx > | -> Ty < ' tcx >  { 
12391268            let  ( variant,  pat_ty)  = match  variant_and_pat_ty { 
@@ -1258,7 +1287,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12581287            } 
12591288        } ; 
12601289
1261-         ResolvedPat  {  path_res :  None ,  check } 
1290+         ResolvedPat  {  path_res :  None ,  pat_adt_def ,   check } 
12621291    } 
12631292
12641293    fn  check_pat_path ( 
@@ -1268,7 +1297,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12681297        span :  Span , 
12691298        qpath :  & ' tcx  hir:: QPath < ' tcx > , 
12701299        ti :  & TopInfo < ' tcx > , 
1271-     )  -> ResolvedPat < impl  Fn ( Ty < ' tcx > ,  PatInfo < ' tcx > )  -> Ty < ' tcx > >  { 
1300+     )  -> ResolvedPat < ' tcx ,   impl  Fn ( Ty < ' tcx > ,  PatInfo < ' tcx > )  -> Ty < ' tcx > >  { 
12721301        let  tcx = self . tcx ; 
12731302
12741303        let  ( res,  opt_ty,  segments)  =
@@ -1317,6 +1346,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13171346        // Type-check the path. 
13181347        let  pat_ty_and_res =
13191348            res_ok. map ( |_| self . instantiate_value_path ( segments,  opt_ty,  res,  span,  span,  path_id) ) ; 
1349+         let  pat_adt_def = pat_ty_and_res. ok ( ) . and_then ( |( pat_ty,  _) | pat_ty. ty_adt_def ( ) ) ; 
13201350
13211351        let  check = move  |expected,  _pat_info| -> Ty < ' tcx >  { 
13221352            let  ( pat_ty,  pat_res)  = match  pat_ty_and_res { 
@@ -1331,7 +1361,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13311361            } 
13321362            pat_ty
13331363        } ; 
1334-         ResolvedPat  {  path_res :  Some ( res) ,  check } 
1364+         ResolvedPat  {  path_res :  Some ( res) ,  pat_adt_def ,   check } 
13351365    } 
13361366
13371367    fn  maybe_suggest_range_literal ( 
@@ -1447,14 +1477,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14471477        qpath :  & ' tcx  hir:: QPath < ' tcx > , 
14481478        subpats :  & ' tcx  [ Pat < ' tcx > ] , 
14491479        ddpos :  hir:: DotDotPos , 
1450-     )  -> ResolvedPat < impl  Fn ( Ty < ' tcx > ,  PatInfo < ' tcx > )  -> Ty < ' tcx > >  { 
1480+     )  -> ResolvedPat < ' tcx ,   impl  Fn ( Ty < ' tcx > ,  PatInfo < ' tcx > )  -> Ty < ' tcx > >  { 
14511481        let  tcx = self . tcx ; 
14521482        let  report_unexpected_res = |res :  Res | { 
14531483            let  expected = "tuple struct or tuple variant" ; 
14541484            report_unexpected_variant_res ( tcx,  res,  None ,  qpath,  pat. span ,  E0164 ,  expected) 
14551485        } ; 
14561486
1457-         let  pat_ty_and_res_and_variant = try { 
1487+         let  pat_ty_and_res_and_variant:   Result < ( Ty < ' _ > ,   Res ,   & VariantDef ) ,   ErrorGuaranteed >  = try { 
14581488            // Resolve the path and check the definition for errors. 
14591489            let  ( res,  opt_ty,  segments)  =
14601490                self . resolve_ty_and_res_fully_qualified_call ( qpath,  pat. hir_id ,  pat. span ) ; 
@@ -1488,6 +1518,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14881518
14891519            ( pat_ty,  res,  variant) 
14901520        } ; 
1521+         let  pat_adt_def = pat_ty_and_res_and_variant. ok ( ) . and_then ( |( ty,  ..) | ty. ty_adt_def ( ) ) ; 
14911522
14921523        let  check = move  |expected :  Ty < ' tcx > ,  pat_info :  PatInfo < ' tcx > | -> Ty < ' tcx >  { 
14931524            let  on_error = |e| { 
@@ -1547,7 +1578,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15471578            pat_ty
15481579        } ; 
15491580
1550-         ResolvedPat  {  path_res :  None ,  check } 
1581+         ResolvedPat  {  path_res :  None ,  pat_adt_def ,   check } 
15511582    } 
15521583
15531584    fn  emit_err_pat_wrong_number_of_fields ( 
0 commit comments