@@ -28,7 +28,7 @@ use rustc_span::hygiene::DesugaringKind;
2828use rustc_span:: source_map:: Spanned ;
2929use rustc_span:: { BytePos , DUMMY_SP , Ident , Span , kw, sym} ;
3030use rustc_trait_selection:: infer:: InferCtxtExt ;
31- use rustc_trait_selection:: traits:: { ObligationCause , ObligationCauseCode } ;
31+ use rustc_trait_selection:: traits:: { ObligationCause , ObligationCauseCode , ObligationCtxt } ;
3232use tracing:: { debug, instrument, trace} ;
3333use ty:: VariantDef ;
3434use ty:: adjustment:: { PatAdjust , PatAdjustment } ;
@@ -403,19 +403,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
403403 let ty = self . check_pat_inner ( pat, opt_path_res, adjust_mode, expected, pat_info) ;
404404 self . write_ty ( pat. hir_id , ty) ;
405405
406- // If we implicitly inserted overloaded dereferences before matching, check the pattern to
407- // see if the dereferenced types need `DerefMut` bounds.
408- if let Some ( derefed_tys) = self . typeck_results . borrow ( ) . pat_adjustments ( ) . get ( pat. hir_id )
409- && derefed_tys. iter ( ) . any ( |adjust| adjust. kind == PatAdjust :: OverloadedDeref )
410- {
411- self . register_deref_mut_bounds_if_needed (
412- pat. span ,
413- pat,
414- derefed_tys. iter ( ) . filter_map ( |adjust| match adjust. kind {
415- PatAdjust :: OverloadedDeref => Some ( adjust. source ) ,
416- PatAdjust :: BuiltinDeref | PatAdjust :: PinDeref => None ,
417- } ) ,
418- ) ;
406+ // If we implicitly inserted overloaded dereferences and pinned dereferences before matching,
407+ // check the pattern to see if the dereferenced types need `DerefMut` or `!Unpin` bounds.
408+ if let Some ( derefed_tys) = self . typeck_results . borrow ( ) . pat_adjustments ( ) . get ( pat. hir_id ) {
409+ let mut has_overloaded_deref = false ;
410+ let mut has_pin_deref = false ;
411+ derefed_tys. iter ( ) . for_each ( |adjust| match adjust. kind {
412+ PatAdjust :: BuiltinDeref => { }
413+ PatAdjust :: OverloadedDeref => has_overloaded_deref = true ,
414+ PatAdjust :: PinDeref => has_pin_deref = true ,
415+ } ) ;
416+ if has_overloaded_deref {
417+ self . register_deref_mut_bounds_if_needed (
418+ pat. span ,
419+ pat,
420+ derefed_tys. iter ( ) . filter_map ( |adjust| match adjust. kind {
421+ PatAdjust :: OverloadedDeref => Some ( adjust. source ) ,
422+ PatAdjust :: BuiltinDeref | PatAdjust :: PinDeref => None ,
423+ } ) ,
424+ ) ;
425+ }
426+ if has_pin_deref {
427+ self . register_not_unpin_bounds_if_needed (
428+ pat. span ,
429+ pat,
430+ derefed_tys. iter ( ) . filter_map ( |adjust| match adjust. kind {
431+ PatAdjust :: BuiltinDeref | PatAdjust :: OverloadedDeref => None ,
432+ PatAdjust :: PinDeref => Some ( adjust. source . peel_pin_refs ( ) ) ,
433+ } ) ,
434+ ) ;
435+ }
419436 }
420437
421438 // (note_1): In most of the cases where (note_1) is referenced
@@ -553,30 +570,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
553570 && let & ty:: Ref ( _, inner_ty, inner_mutability) = pinned_ty. kind ( ) =>
554571 {
555572 debug ! ( "scrutinee ty {expected:?} is a pinned reference, inserting pin deref" ) ;
556- // Preserve the pinned type. We'll need it later during THIR lowering.
557- self . typeck_results
558- . borrow_mut ( )
559- . pat_adjustments_mut ( )
560- . entry ( pat. hir_id )
561- . or_default ( )
562- . push ( PatAdjustment { kind : PatAdjust :: PinDeref , source : expected } ) ;
563573
564574 let binding_mode = adjust_binding_mode ( Pinnedness :: Pinned , inner_mutability) ;
565575 // If the pinnedness is `Not`, it means the pattern is unpinned
566576 // and thus requires an `Unpin` bound.
567577 if binding_mode == ByRef :: Yes ( Pinnedness :: Not , Mutability :: Mut ) {
568578 self . register_bound (
569579 inner_ty,
570- self . tcx . require_lang_item ( hir:: LangItem :: Unpin , Some ( pat. span ) ) ,
580+ self . tcx . require_lang_item ( hir:: LangItem :: Unpin , pat. span ) ,
571581 self . misc ( pat. span ) ,
572- ) ;
582+ )
573583 }
584+ // Once we've checked `pat`, we'll add a `!Unpin` bound if it contains any
585+ // `ref pin` bindings. See `Self::register_not_unpin_bounds_if_needed`.
586+
587+ debug ! ( "default binding mode is now {:?}" , binding_mode) ;
588+
574589 // Use the old pat info to keep `current_depth` to its old value.
575590 let new_pat_info = PatInfo { binding_mode, ..old_pat_info } ;
576- // Recurse with the new expected type.
577- // using `break` instead of `return` in case where any shared codes are added
578- // after the `match pat.kind {}`.
579- self . check_pat_inner ( pat, opt_path_res, adjust_mode, inner_ty, new_pat_info)
591+
592+ self . check_deref_pattern (
593+ pat,
594+ opt_path_res,
595+ adjust_mode,
596+ expected,
597+ inner_ty,
598+ PatAdjust :: PinDeref ,
599+ new_pat_info,
600+ )
580601 }
581602 // If `deref_patterns` is enabled, peel a smart pointer from the scrutinee type. See the
582603 // examples in `tests/ui/pattern/deref_patterns/`.
@@ -585,35 +606,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
585606 && pat. default_binding_modes
586607 && self . should_peel_smart_pointer ( peel_kind, expected) =>
587608 {
588- debug ! ( "scrutinee ty {expected:?} is a smart pointer, inserting overloaded deref" ) ;
609+ debug ! ( "scrutinee ty {expected:?} is a smart pointer, inserting pin deref" ) ;
610+
589611 // The scrutinee is a smart pointer; implicitly dereference it. This adds a
590612 // requirement that `expected: DerefPure`.
591- let mut inner_ty = self . deref_pat_target ( pat. span , expected) ;
613+ let inner_ty = self . deref_pat_target ( pat. span , expected) ;
592614 // Once we've checked `pat`, we'll add a `DerefMut` bound if it contains any
593615 // `ref mut` bindings. See `Self::register_deref_mut_bounds_if_needed`.
594616
595- let mut typeck_results = self . typeck_results . borrow_mut ( ) ;
596- let mut pat_adjustments_table = typeck_results. pat_adjustments_mut ( ) ;
597- let pat_adjustments = pat_adjustments_table. entry ( pat. hir_id ) . or_default ( ) ;
598- // We may reach the recursion limit if a user matches on a type `T` satisfying
599- // `T: Deref<Target = T>`; error gracefully in this case.
600- // FIXME(deref_patterns): If `deref_patterns` stabilizes, it may make sense to move
601- // this check out of this branch. Alternatively, this loop could be implemented with
602- // autoderef and this check removed. For now though, don't break code compiling on
603- // stable with lots of `&`s and a low recursion limit, if anyone's done that.
604- if self . tcx . recursion_limit ( ) . value_within_limit ( pat_adjustments. len ( ) ) {
605- // Preserve the smart pointer type for THIR lowering and closure upvar analysis.
606- pat_adjustments
607- . push ( PatAdjustment { kind : PatAdjust :: OverloadedDeref , source : expected } ) ;
608- } else {
609- let guar = report_autoderef_recursion_limit_error ( self . tcx , pat. span , expected) ;
610- inner_ty = Ty :: new_error ( self . tcx , guar) ;
611- }
612- drop ( typeck_results) ;
613-
614- // Recurse, using the old pat info to keep `current_depth` to its old value.
615- // Peeling smart pointers does not update the default binding mode.
616- self . check_pat_inner ( pat, opt_path_res, adjust_mode, inner_ty, old_pat_info)
617+ self . check_deref_pattern (
618+ pat,
619+ opt_path_res,
620+ adjust_mode,
621+ expected,
622+ inner_ty,
623+ PatAdjust :: OverloadedDeref ,
624+ old_pat_info,
625+ )
617626 }
618627 PatKind :: Missing | PatKind :: Wild | PatKind :: Err ( _) => expected,
619628 // We allow any type here; we ensure that the type is uninhabited during match checking.
@@ -684,6 +693,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
684693 }
685694 }
686695
696+ fn check_deref_pattern (
697+ & self ,
698+ pat : & ' tcx Pat < ' tcx > ,
699+ opt_path_res : Option < Result < ResolvedPat < ' tcx > , ErrorGuaranteed > > ,
700+ adjust_mode : AdjustMode ,
701+ expected : Ty < ' tcx > ,
702+ mut inner_ty : Ty < ' tcx > ,
703+ pat_adjust_kind : PatAdjust ,
704+ pat_info : PatInfo < ' tcx > ,
705+ ) -> Ty < ' tcx > {
706+ debug_assert ! (
707+ !matches!( pat_adjust_kind, PatAdjust :: BuiltinDeref ) ,
708+ "unexpected deref pattern for builtin reference type {expected:?}" ,
709+ ) ;
710+
711+ let mut typeck_results = self . typeck_results . borrow_mut ( ) ;
712+ let mut pat_adjustments_table = typeck_results. pat_adjustments_mut ( ) ;
713+ let pat_adjustments = pat_adjustments_table. entry ( pat. hir_id ) . or_default ( ) ;
714+ // We may reach the recursion limit if a user matches on a type `T` satisfying
715+ // `T: Deref<Target = T>`; error gracefully in this case.
716+ // FIXME(deref_patterns): If `deref_patterns` stabilizes, it may make sense to move
717+ // this check out of this branch. Alternatively, this loop could be implemented with
718+ // autoderef and this check removed. For now though, don't break code compiling on
719+ // stable with lots of `&`s and a low recursion limit, if anyone's done that.
720+ if self . tcx . recursion_limit ( ) . value_within_limit ( pat_adjustments. len ( ) ) {
721+ // Preserve the smart pointer type for THIR lowering and closure upvar analysis.
722+ pat_adjustments. push ( PatAdjustment { kind : pat_adjust_kind, source : expected } ) ;
723+ } else {
724+ let guar = report_autoderef_recursion_limit_error ( self . tcx , pat. span , expected) ;
725+ inner_ty = Ty :: new_error ( self . tcx , guar) ;
726+ }
727+ drop ( typeck_results) ;
728+
729+ // Recurse, using the old pat info to keep `current_depth` to its old value.
730+ // Peeling smart pointers does not update the default binding mode.
731+ self . check_pat_inner ( pat, opt_path_res, adjust_mode, inner_ty, pat_info)
732+ }
733+
687734 /// How should the binding mode and expected type be adjusted?
688735 ///
689736 /// When the pattern contains a path, `opt_path_res` must be `Some(path_res)`.
@@ -1195,7 +1242,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11951242 // Wrapping the type into `Pin` if the binding is like `ref pin const|mut x`
11961243 ByRef :: Yes ( Pinnedness :: Pinned , mutbl) => Ty :: new_adt (
11971244 self . tcx ,
1198- self . tcx . adt_def ( self . tcx . require_lang_item ( hir:: LangItem :: Pin , Some ( pat. span ) ) ) ,
1245+ self . tcx . adt_def ( self . tcx . require_lang_item ( hir:: LangItem :: Pin , pat. span ) ) ,
11991246 self . tcx . mk_args ( & [ self . new_ref_ty ( pat. span , mutbl, expected) . into ( ) ] ) ,
12001247 ) ,
12011248 // Otherwise, the type of x is the expected type `T`.
@@ -2638,6 +2685,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
26382685 }
26392686 }
26402687
2688+ /// Check if the interior of a pin pattern (either explicit or implicit) has any `ref pin`
2689+ /// bindings of non-`Unpin` types, which would require `!Unpin` to be emitted.
2690+ fn register_not_unpin_bounds_if_needed (
2691+ & self ,
2692+ span : Span ,
2693+ inner : & ' tcx Pat < ' tcx > ,
2694+ derefed_tys : impl IntoIterator < Item = Ty < ' tcx > > ,
2695+ ) {
2696+ // Check if there are subpatterns with `ref pin` binding modes of non-`Unpin` types.
2697+ let unpin = self . tcx . require_lang_item ( hir:: LangItem :: Unpin , span) ;
2698+ let cause = self . misc ( span) ;
2699+ let unpin_obligations = self . probe ( |_| {
2700+ let obligation_ctxt = ObligationCtxt :: new ( & self ) ;
2701+ self . typeck_results . borrow ( ) . pat_walk_ref_pin_binding_of_non_unpin_type ( inner, |ty| {
2702+ let ty = obligation_ctxt. normalize ( & cause, self . param_env , ty) . peel_pin_refs ( ) ;
2703+ obligation_ctxt. register_bound ( cause. clone ( ) , self . param_env , ty, unpin) ;
2704+ } ) ;
2705+ obligation_ctxt. select_all_or_error ( )
2706+ } ) ;
2707+
2708+ // If any, the current pattern type should implement `!Unpin`.
2709+ if !unpin_obligations. is_empty ( ) {
2710+ for pinned_derefed_ty in derefed_tys {
2711+ self . register_negative_bound (
2712+ pinned_derefed_ty,
2713+ self . tcx . require_lang_item ( hir:: LangItem :: Unpin , span) ,
2714+ self . misc ( span) ,
2715+ ) ;
2716+ }
2717+ }
2718+ }
2719+
26412720 // Precondition: Pat is Ref(inner)
26422721 fn check_pat_ref (
26432722 & self ,
0 commit comments