@@ -9,6 +9,7 @@ use rustc_errors::{
9
9
Applicability , Diag , ErrorGuaranteed , MultiSpan , pluralize, struct_span_code_err,
10
10
} ;
11
11
use rustc_hir:: def:: { CtorKind , DefKind , Res } ;
12
+ use rustc_hir:: def_id:: DefId ;
12
13
use rustc_hir:: pat_util:: EnumerateAndAdjustIterator ;
13
14
use rustc_hir:: {
14
15
self as hir, BindingMode , ByRef , ExprKind , HirId , LangItem , Mutability , Pat , PatExpr ,
@@ -179,8 +180,16 @@ enum PeelKind {
179
180
/// ADTs. In order to peel only as much as necessary for the pattern to match, the `until_adt`
180
181
/// field contains the ADT def that the pattern is a constructor for, if applicable, so that we
181
182
/// don't peel it. See [`ResolvedPat`] for more information.
182
- // TODO: add `ResolvedPat` and `until_adt`.
183
- Implicit ,
183
+ Implicit { until_adt : Option < DefId > } ,
184
+ }
185
+
186
+ impl AdjustMode {
187
+ const fn peel_until_adt ( opt_adt_def : Option < DefId > ) -> AdjustMode {
188
+ AdjustMode :: Peel { kind : PeelKind :: Implicit { until_adt : opt_adt_def } }
189
+ }
190
+ const fn peel_all ( ) -> AdjustMode {
191
+ AdjustMode :: peel_until_adt ( None )
192
+ }
184
193
}
185
194
186
195
/// `ref mut` bindings (explicit or match-ergonomics) are not allowed behind an `&` reference.
@@ -294,7 +303,7 @@ impl<'tcx> ResolvedPat<'tcx> {
294
303
// The remaining possible resolutions for path, struct, and tuple struct patterns are
295
304
// ADT constructors. As such, we may peel references freely, but we must not peel the
296
305
// ADT itself from the scrutinee if it's a smart pointer.
297
- AdjustMode :: Peel { kind : PeelKind :: Implicit }
306
+ AdjustMode :: peel_until_adt ( self . ty . ty_adt_def ( ) . map ( |adt| adt . did ( ) ) )
298
307
}
299
308
}
300
309
}
@@ -521,14 +530,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
521
530
// If `deref_patterns` is enabled, peel a smart pointer from the scrutinee type. See the
522
531
// examples in `tests/ui/pattern/deref_patterns/`.
523
532
_ if self . tcx . features ( ) . deref_patterns ( )
524
- && let AdjustMode :: Peel { kind : PeelKind :: Implicit } = adjust_mode
533
+ && let AdjustMode :: Peel { kind : PeelKind :: Implicit { until_adt } } = adjust_mode
525
534
&& pat. default_binding_modes
526
535
// For simplicity, only apply overloaded derefs if `expected` is a known ADT.
527
536
// FIXME(deref_patterns): we'll get better diagnostics for users trying to
528
537
// implicitly deref generics if we allow them here, but primitives, tuples, and
529
538
// 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 ( )
539
+ && let ty:: Adt ( scrutinee_adt, _) = * expected. kind ( )
540
+ // Don't peel if the pattern type already matches the scrutinee. E.g., stop here if
541
+ // matching on a `Cow<'a, T>` scrutinee with a `Cow::Owned(_)` pattern.
542
+ && until_adt != Some ( scrutinee_adt. did ( ) )
532
543
// At this point, the pattern isn't able to match `expected` without peeling. Check
533
544
// that it implements `Deref` before assuming it's a smart pointer, to get a normal
534
545
// type error instead of a missing impl error if not. This only checks for `Deref`,
@@ -637,22 +648,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
637
648
match & pat. kind {
638
649
// Type checking these product-like types successfully always require
639
650
// that the expected type be of those types and not reference types.
640
- PatKind :: Struct ( ..)
641
- | PatKind :: TupleStruct ( ..)
642
- | PatKind :: Tuple ( ..)
651
+ PatKind :: Tuple ( ..)
643
652
| PatKind :: Range ( ..)
644
- | PatKind :: Slice ( ..) => AdjustMode :: Peel { kind : PeelKind :: Implicit } ,
653
+ | PatKind :: Slice ( ..) => AdjustMode :: peel_all ( ) ,
645
654
// When checking an explicit deref pattern, only peel reference types.
646
655
// FIXME(deref_patterns): If box patterns and deref patterns need to coexist, box
647
656
// patterns may want `PeelKind::Implicit`, stopping on encountering a box.
648
657
| PatKind :: Box ( _)
649
658
| PatKind :: Deref ( _) => AdjustMode :: Peel { kind : PeelKind :: ExplicitDerefPat } ,
650
659
// A never pattern behaves somewhat like a literal or unit variant.
651
- PatKind :: Never => AdjustMode :: Peel { kind : PeelKind :: Implicit } ,
660
+ PatKind :: Never => AdjustMode :: peel_all ( ) ,
652
661
// For patterns with paths, how we peel the scrutinee depends on the path's resolution.
653
- PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( _) , .. } ) => {
662
+ PatKind :: Struct ( ..)
663
+ | PatKind :: TupleStruct ( ..)
664
+ | PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( _) , .. } ) => {
654
665
// 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 ( ) )
666
+ opt_path_res. unwrap ( ) . map_or ( AdjustMode :: peel_all ( ) , |pr| pr. adjust_mode ( ) )
656
667
}
657
668
658
669
// String and byte-string literals result in types `&str` and `&[u8]` respectively.
@@ -662,7 +673,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
662
673
// Call `resolve_vars_if_possible` here for inline const blocks.
663
674
PatKind :: Expr ( lt) => match self . resolve_vars_if_possible ( self . check_pat_expr_unadjusted ( lt) ) . kind ( ) {
664
675
ty:: Ref ( ..) => AdjustMode :: Pass ,
665
- _ => AdjustMode :: Peel { kind : PeelKind :: Implicit } ,
676
+ _ => {
677
+ // Path patterns have already been handled, and inline const blocks currently
678
+ // aren't possible to write, so any handling for them would be untested.
679
+ if cfg ! ( debug_assertions)
680
+ && self . tcx . features ( ) . deref_patterns ( )
681
+ && !matches ! ( lt. kind, PatExprKind :: Lit { .. } )
682
+ {
683
+ span_bug ! ( lt. span, "FIXME(deref_patterns): adjust mode unimplemented for {:?}" , lt. kind) ;
684
+ }
685
+ AdjustMode :: peel_all ( )
686
+ }
666
687
} ,
667
688
668
689
// Ref patterns are complicated, we handle them in `check_pat_ref`.
0 commit comments