@@ -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.
@@ -282,7 +290,7 @@ enum ResolvedPatKind<'tcx> {
282290}
283291
284292impl < ' tcx > ResolvedPat < ' tcx > {
285- fn adjust_mode ( & self ) -> AdjustMode {
293+ fn adjust_mode ( & self ) -> AdjustMode < ' tcx > {
286294 if let ResolvedPatKind :: Path { res, .. } = self . kind
287295 && matches ! ( res, Res :: Def ( DefKind :: Const | DefKind :: AssocConst , _) )
288296 {
@@ -294,7 +302,7 @@ impl<'tcx> ResolvedPat<'tcx> {
294302 // The remaining possible resolutions for path, struct, and tuple struct patterns are
295303 // ADT constructors. As such, we may peel references freely, but we must not peel the
296304 // ADT itself from the scrutinee if it's a smart pointer.
297- AdjustMode :: Peel { kind : PeelKind :: Overloaded }
305+ AdjustMode :: peel_until_adt ( self . ty . ty_adt_def ( ) )
298306 }
299307 }
300308}
@@ -533,7 +541,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
533541 pat : & ' tcx Pat < ' tcx > ,
534542 expected : Ty < ' tcx > ,
535543 def_br : ByRef ,
536- adjust_mode : AdjustMode ,
544+ adjust_mode : AdjustMode < ' tcx > ,
537545 max_ref_mutbl : MutblCap ,
538546 ) -> ( Ty < ' tcx > , ByRef , MutblCap ) {
539547 #[ cfg( debug_assertions) ]
@@ -559,7 +567,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
559567 & self ,
560568 pat : & ' tcx Pat < ' tcx > ,
561569 opt_resolved_pat : Option < & ResolvedPat < ' tcx > > ,
562- ) -> AdjustMode {
570+ ) -> AdjustMode < ' tcx > {
563571 // When we perform destructuring assignment, we disable default match bindings, which are
564572 // unintuitive in this context.
565573 if !pat. default_binding_modes {
@@ -568,21 +576,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
568576 match & pat. kind {
569577 // Type checking these product-like types successfully always require
570578 // that the expected type be of those types and not reference types.
571- PatKind :: Struct ( ..)
572- | PatKind :: TupleStruct ( ..)
573- | PatKind :: Tuple ( ..)
579+ PatKind :: Tuple ( ..)
574580 | PatKind :: Range ( ..)
575- | PatKind :: Slice ( ..) => AdjustMode :: Peel { kind : PeelKind :: Overloaded } ,
581+ | PatKind :: Slice ( ..) => AdjustMode :: peel_all ( ) ,
576582 // When checking an explicit deref pattern, only peel reference types.
577583 // FIXME(deref_patterns): If box patterns and deref patterns need to coexist, box
578584 // patterns may want `PeelKind::Overloaded`, stopping on encountering a box.
579585 | PatKind :: Box ( _)
580586 | PatKind :: Deref ( _) => AdjustMode :: Peel { kind : PeelKind :: RefOnly } ,
581587 // A never pattern behaves somewhat like a literal or unit variant.
582- PatKind :: Never => AdjustMode :: Peel { kind : PeelKind :: Overloaded } ,
588+ PatKind :: Never => AdjustMode :: peel_all ( ) ,
583589 // For patterns with paths, how we peel the scrutinee depends on the path's resolution.
584- PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( _) , .. } ) => {
585- opt_resolved_pat. map_or ( AdjustMode :: Peel { kind : PeelKind :: Overloaded } , ResolvedPat :: adjust_mode)
590+ PatKind :: Struct ( ..)
591+ | PatKind :: TupleStruct ( ..)
592+ | PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( _) , .. } ) => {
593+ opt_resolved_pat. map_or ( AdjustMode :: peel_all ( ) , ResolvedPat :: adjust_mode)
586594 }
587595
588596 // String and byte-string literals result in types `&str` and `&[u8]` respectively.
@@ -592,7 +600,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
592600 // Call `resolve_vars_if_possible` here for inline const blocks.
593601 PatKind :: Expr ( lt) => match self . resolve_vars_if_possible ( self . check_pat_expr_unadjusted ( lt) ) . kind ( ) {
594602 ty:: Ref ( ..) => AdjustMode :: Pass ,
595- _ => AdjustMode :: Peel { kind : PeelKind :: Overloaded } ,
603+ // If an inline const pattern has a library-defined pointer-like type and
604+ // `deref_patterns` is enabled, don't implicitly add deref patterns for its ADT.
605+ // Nothing in the library that implements `DerefPure` supports structural equality,
606+ // but we don't check that until `const_to_pat` in THIR construction. By avoiding
607+ // type errors here, we can get a more meaningful error there.
608+ ty:: Adt ( adt, _) => AdjustMode :: peel_until_adt ( Some ( * adt) ) ,
609+ _ => AdjustMode :: peel_all ( )
596610 } ,
597611
598612 // Ref patterns are complicated, we handle them in `check_pat_ref`.
@@ -622,7 +636,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
622636 fn peel_off_references (
623637 & self ,
624638 pat : & ' tcx Pat < ' tcx > ,
625- peel_kind : PeelKind ,
639+ peel_kind : PeelKind < ' tcx > ,
626640 expected : Ty < ' tcx > ,
627641 mut def_br : ByRef ,
628642 mut max_ref_mutbl : MutblCap ,
@@ -656,13 +670,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
656670 } ) ;
657671 inner_ty
658672 } else if deref_patterns
659- && peel_kind == PeelKind :: Overloaded
673+ && let PeelKind :: Overloaded { until_adt } = peel_kind
660674 // For simplicity, only apply overloaded derefs if `expected` is a known ADT.
661675 // FIXME(deref_patterns): we'll get better diagnostics for users trying to
662676 // implicitly deref generics if we allow them here, but primitives, tuples, and
663677 // inference vars definitely should be stopped. Figure out what makes most sense.
664- // TODO: stop peeling if the pattern is a constructor for the scrutinee type
665- && expected. is_adt ( )
678+ && let ty:: Adt ( scrutinee_adt, _) = * expected. kind ( )
679+ // Don't peel if the pattern type already matches the scrutinee. E.g., stop here if
680+ // matching on a `Cow<'a, T>` scrutinee with a `Cow::Owned(_)` pattern.
681+ && until_adt != Some ( scrutinee_adt)
666682 {
667683 // At this point, the pattern isn't able to match `expected` without peeling. Check
668684 // that it implements `Deref` before assuming it's a smart pointer, to get a normal
0 commit comments