@@ -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;
@@ -161,26 +161,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
161161
162162/// Mode for adjusting the expected type and binding mode.
163163#[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
164- enum AdjustMode {
164+ enum AdjustMode < ' tcx > {
165165 /// Peel off all immediate reference types. If the `deref_patterns` feature is enabled, this
166166 /// also peels smart pointer ADTs.
167- Peel { kind : PeelKind } ,
167+ Peel { kind : PeelKind < ' tcx > } ,
168168 /// Pass on the input binding mode and expected type.
169169 Pass ,
170170}
171171
172172/// Restrictions on what types to peel when adjusting the expected type and binding mode.
173173#[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
174- enum PeelKind {
174+ enum PeelKind < ' tcx > {
175175 /// Only peel reference types. This is used for explicit `deref!(_)` patterns, which dereference
176176 /// any number of `&`/`&mut` references, plus a single smart pointer.
177177 ExplicitDerefPat ,
178178 /// Implicitly peel any number of references, and if `deref_patterns` is enabled, smart pointer
179179 /// ADTs. In order to peel only as much as necessary for the pattern to match, the `until_adt`
180180 /// field contains the ADT def that the pattern is a constructor for, if applicable, so that we
181181 /// don't peel it. See [`ResolvedPat`] for more information.
182- // TODO: add `ResolvedPat` and `until_adt`.
183- Implicit ,
182+ Implicit { 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 :: Implicit { 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 :: Implicit }
305+ AdjustMode :: peel_until_adt ( self . ty . ty_adt_def ( ) )
298306 }
299307 }
300308}
@@ -452,7 +460,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
452460 & self ,
453461 pat : & ' tcx Pat < ' tcx > ,
454462 opt_path_res : Option < Result < ResolvedPat < ' tcx > , ErrorGuaranteed > > ,
455- adjust_mode : AdjustMode ,
463+ adjust_mode : AdjustMode < ' tcx > ,
456464 expected : Ty < ' tcx > ,
457465 pat_info : PatInfo < ' tcx > ,
458466 ) -> Ty < ' tcx > {
@@ -521,14 +529,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
521529 // If `deref_patterns` is enabled, peel a smart pointer from the scrutinee type. See the
522530 // examples in `tests/ui/pattern/deref_patterns/`.
523531 _ if self . tcx . features ( ) . deref_patterns ( )
524- && let AdjustMode :: Peel { kind : PeelKind :: Implicit } = adjust_mode
532+ && let AdjustMode :: Peel { kind : PeelKind :: Implicit { until_adt } } = adjust_mode
525533 && pat. default_binding_modes
526534 // For simplicity, only apply overloaded derefs if `expected` is a known ADT.
527535 // FIXME(deref_patterns): we'll get better diagnostics for users trying to
528536 // implicitly deref generics if we allow them here, but primitives, tuples, and
529537 // inference vars definitely should be stopped. Figure out what makes most sense.
530- // TODO: stop peeling if the pattern is a constructor for the scrutinee type
531- && expected. is_adt ( )
538+ && let ty:: Adt ( scrutinee_adt, _) = * expected. kind ( )
539+ // Don't peel if the pattern type already matches the scrutinee. E.g., stop here if
540+ // matching on a `Cow<'a, T>` scrutinee with a `Cow::Owned(_)` pattern.
541+ && until_adt != Some ( scrutinee_adt)
532542 // At this point, the pattern isn't able to match `expected` without peeling. Check
533543 // that it implements `Deref` before assuming it's a smart pointer, to get a normal
534544 // type error instead of a missing impl error if not. This only checks for `Deref`,
@@ -633,26 +643,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
633643 & self ,
634644 pat : & ' tcx Pat < ' tcx > ,
635645 opt_path_res : Option < Result < ResolvedPat < ' tcx > , ErrorGuaranteed > > ,
636- ) -> AdjustMode {
646+ ) -> AdjustMode < ' tcx > {
637647 match & pat. kind {
638648 // Type checking these product-like types successfully always require
639649 // that the expected type be of those types and not reference types.
640- PatKind :: Struct ( ..)
641- | PatKind :: TupleStruct ( ..)
642- | PatKind :: Tuple ( ..)
650+ PatKind :: Tuple ( ..)
643651 | PatKind :: Range ( ..)
644- | PatKind :: Slice ( ..) => AdjustMode :: Peel { kind : PeelKind :: Implicit } ,
652+ | PatKind :: Slice ( ..) => AdjustMode :: peel_all ( ) ,
645653 // When checking an explicit deref pattern, only peel reference types.
646654 // FIXME(deref_patterns): If box patterns and deref patterns need to coexist, box
647655 // patterns may want `PeelKind::Implicit`, stopping on encountering a box.
648656 | PatKind :: Box ( _)
649657 | PatKind :: Deref ( _) => AdjustMode :: Peel { kind : PeelKind :: ExplicitDerefPat } ,
650658 // A never pattern behaves somewhat like a literal or unit variant.
651- PatKind :: Never => AdjustMode :: Peel { kind : PeelKind :: Implicit } ,
659+ PatKind :: Never => AdjustMode :: peel_all ( ) ,
652660 // For patterns with paths, how we peel the scrutinee depends on the path's resolution.
653- PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( _) , .. } ) => {
661+ PatKind :: Struct ( ..)
662+ | PatKind :: TupleStruct ( ..)
663+ | PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( _) , .. } ) => {
654664 // If there was an error resolving the path, default to peeling everything.
655- opt_path_res. unwrap ( ) . map_or ( AdjustMode :: Peel { kind : PeelKind :: Implicit } , |pr| pr. adjust_mode ( ) )
665+ opt_path_res. unwrap ( ) . map_or ( AdjustMode :: peel_all ( ) , |pr| pr. adjust_mode ( ) )
656666 }
657667
658668 // String and byte-string literals result in types `&str` and `&[u8]` respectively.
@@ -662,7 +672,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
662672 // Call `resolve_vars_if_possible` here for inline const blocks.
663673 PatKind :: Expr ( lt) => match self . resolve_vars_if_possible ( self . check_pat_expr_unadjusted ( lt) ) . kind ( ) {
664674 ty:: Ref ( ..) => AdjustMode :: Pass ,
665- _ => AdjustMode :: Peel { kind : PeelKind :: Implicit } ,
675+ // If an inline const pattern has a library-defined pointer-like type and
676+ // `deref_patterns` is enabled, don't implicitly add deref patterns for its ADT.
677+ // Nothing in the library that implements `DerefPure` supports structural equality,
678+ // but we don't check that until `const_to_pat` in THIR construction. By avoiding
679+ // type errors here, we can get a more meaningful error there.
680+ ty:: Adt ( adt, _) => AdjustMode :: peel_until_adt ( Some ( * adt) ) ,
681+ _ => AdjustMode :: peel_all ( )
666682 } ,
667683
668684 // Ref patterns are complicated, we handle them in `check_pat_ref`.
0 commit comments