@@ -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.
169169 Reset ,
@@ -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.
178178 RefOnly ,
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`.
273280 path_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.
276285 check : 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> {
576602 fn 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