@@ -531,24 +531,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
531531 // If `deref_patterns` is enabled, peel a smart pointer from the scrutinee type. See the
532532 // examples in `tests/ui/pattern/deref_patterns/`.
533533 _ if self . tcx . features ( ) . deref_patterns ( )
534- && let AdjustMode :: Peel { kind : PeelKind :: Implicit { until_adt } } = adjust_mode
534+ && let AdjustMode :: Peel { kind : peel_kind } = adjust_mode
535535 && pat. default_binding_modes
536- // For simplicity, only apply overloaded derefs if `expected` is a known ADT.
537- // FIXME(deref_patterns): we'll get better diagnostics for users trying to
538- // implicitly deref generics if we allow them here, but primitives, tuples, and
539- // inference vars definitely should be stopped. Figure out what makes most sense.
540- && let ty:: Adt ( scrutinee_adt, _) = * expected. kind ( )
541- // Don't peel if the pattern type already matches the scrutinee. E.g., stop here if
542- // matching on a `Cow<'a, T>` scrutinee with a `Cow::Owned(_)` pattern.
543- && until_adt != Some ( scrutinee_adt. did ( ) )
544- // At this point, the pattern isn't able to match `expected` without peeling. Check
545- // that it implements `Deref` before assuming it's a smart pointer, to get a normal
546- // type error instead of a missing impl error if not. This only checks for `Deref`,
547- // not `DerefPure`: we require that too, but we want a trait error if it's missing.
548- && let Some ( deref_trait) = self . tcx . lang_items ( ) . deref_trait ( )
549- && self
550- . type_implements_trait ( deref_trait, [ expected] , self . param_env )
551- . may_apply ( ) =>
536+ && self . should_peel_smart_pointer ( peel_kind, expected) =>
552537 {
553538 debug ! ( "scrutinee ty {expected:?} is a smart pointer, inserting overloaded deref" ) ;
554539 // The scrutinee is a smart pointer; implicitly dereference it. This adds a
@@ -720,6 +705,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
720705 }
721706 }
722707
708+ /// Determine whether `expected` is a smart pointer type that should be peeled before matching.
709+ fn should_peel_smart_pointer ( & self , peel_kind : PeelKind , expected : Ty < ' tcx > ) -> bool {
710+ // Explicit `deref!(_)` patterns match against smart pointers; don't peel in that case.
711+ if let PeelKind :: Implicit { until_adt, .. } = peel_kind
712+ // For simplicity, only apply overloaded derefs if `expected` is a known ADT.
713+ // FIXME(deref_patterns): we'll get better diagnostics for users trying to
714+ // implicitly deref generics if we allow them here, but primitives, tuples, and
715+ // inference vars definitely should be stopped. Figure out what makes most sense.
716+ && let ty:: Adt ( scrutinee_adt, _) = * expected. kind ( )
717+ // Don't peel if the pattern type already matches the scrutinee. E.g., stop here if
718+ // matching on a `Cow<'a, T>` scrutinee with a `Cow::Owned(_)` pattern.
719+ && until_adt != Some ( scrutinee_adt. did ( ) )
720+ // At this point, the pattern isn't able to match `expected` without peeling. Check
721+ // that it implements `Deref` before assuming it's a smart pointer, to get a normal
722+ // type error instead of a missing impl error if not. This only checks for `Deref`,
723+ // not `DerefPure`: we require that too, but we want a trait error if it's missing.
724+ && let Some ( deref_trait) = self . tcx . lang_items ( ) . deref_trait ( )
725+ && self . type_implements_trait ( deref_trait, [ expected] , self . param_env ) . may_apply ( )
726+ {
727+ true
728+ } else {
729+ false
730+ }
731+ }
732+
723733 fn check_pat_expr_unadjusted ( & self , lt : & ' tcx hir:: PatExpr < ' tcx > ) -> Ty < ' tcx > {
724734 let ty = match & lt. kind {
725735 rustc_hir:: PatExprKind :: Lit { lit, negated } => {
0 commit comments