@@ -27,7 +27,7 @@ use rustc_span::edition::Edition;
2727use rustc_span:: source_map:: Spanned ;
2828use rustc_span:: { BytePos , DUMMY_SP , Ident , Span , kw, sym} ;
2929use rustc_trait_selection:: infer:: InferCtxtExt ;
30- use rustc_trait_selection:: traits:: { ObligationCause , ObligationCauseCode } ;
30+ use rustc_trait_selection:: traits:: { ObligationCause , ObligationCauseCode , ObligationCtxt } ;
3131use tracing:: { debug, instrument, trace} ;
3232use ty:: VariantDef ;
3333use ty:: adjustment:: { PatAdjust , PatAdjustment } ;
@@ -402,19 +402,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
402402 let ty = self . check_pat_inner ( pat, opt_path_res, adjust_mode, expected, pat_info) ;
403403 self . write_ty ( pat. hir_id , ty) ;
404404
405- // If we implicitly inserted overloaded dereferences before matching, check the pattern to
406- // see if the dereferenced types need `DerefMut` bounds.
407- if let Some ( derefed_tys) = self . typeck_results . borrow ( ) . pat_adjustments ( ) . get ( pat. hir_id )
408- && derefed_tys. iter ( ) . any ( |adjust| adjust. kind == PatAdjust :: OverloadedDeref )
409- {
410- self . register_deref_mut_bounds_if_needed (
411- pat. span ,
412- pat,
413- derefed_tys. iter ( ) . filter_map ( |adjust| match adjust. kind {
414- PatAdjust :: OverloadedDeref => Some ( adjust. source ) ,
415- PatAdjust :: BuiltinDeref | PatAdjust :: PinDeref => None ,
416- } ) ,
417- ) ;
405+ // If we implicitly inserted overloaded dereferences and pinned dereferences before matching,
406+ // check the pattern to see if the dereferenced types need `DerefMut` or `!Unpin` bounds.
407+ if let Some ( derefed_tys) = self . typeck_results . borrow ( ) . pat_adjustments ( ) . get ( pat. hir_id ) {
408+ let mut has_overloaded_deref = false ;
409+ let mut has_pin_deref = false ;
410+ derefed_tys. iter ( ) . for_each ( |adjust| match adjust. kind {
411+ PatAdjust :: BuiltinDeref => { }
412+ PatAdjust :: OverloadedDeref => has_overloaded_deref = true ,
413+ PatAdjust :: PinDeref => has_pin_deref = true ,
414+ } ) ;
415+ if has_overloaded_deref {
416+ self . register_deref_mut_bounds_if_needed (
417+ pat. span ,
418+ pat,
419+ derefed_tys. iter ( ) . filter_map ( |adjust| match adjust. kind {
420+ PatAdjust :: OverloadedDeref => Some ( adjust. source ) ,
421+ PatAdjust :: BuiltinDeref | PatAdjust :: PinDeref => None ,
422+ } ) ,
423+ ) ;
424+ }
425+ if has_pin_deref {
426+ self . register_not_unpin_bounds_if_needed (
427+ pat. span ,
428+ pat,
429+ derefed_tys. iter ( ) . filter_map ( |adjust| match adjust. kind {
430+ PatAdjust :: BuiltinDeref | PatAdjust :: OverloadedDeref => None ,
431+ PatAdjust :: PinDeref => {
432+ Some ( adjust. source . pinned_ref ( ) . expect ( "expected pinned reference" ) . 0 )
433+ }
434+ } ) ,
435+ ) ;
436+ }
418437 }
419438
420439 // (note_1): In most of the cases where (note_1) is referenced
@@ -552,30 +571,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
552571 && let & ty:: Ref ( _, inner_ty, inner_mutability) = pinned_ty. kind ( ) =>
553572 {
554573 debug ! ( "scrutinee ty {expected:?} is a pinned reference, inserting pin deref" ) ;
555- // Preserve the pinned type. We'll need it later during THIR lowering.
556- self . typeck_results
557- . borrow_mut ( )
558- . pat_adjustments_mut ( )
559- . entry ( pat. hir_id )
560- . or_default ( )
561- . push ( PatAdjustment { kind : PatAdjust :: PinDeref , source : expected } ) ;
562574
563575 let binding_mode = adjust_binding_mode ( Pinnedness :: Pinned , inner_mutability) ;
564576 // If the pinnedness is `Not`, it means the pattern is unpinned
565577 // and thus requires an `Unpin` bound.
566578 if binding_mode == ByRef :: Yes ( Pinnedness :: Not , Mutability :: Mut ) {
567579 self . register_bound (
568580 inner_ty,
569- self . tcx . require_lang_item ( hir:: LangItem :: Unpin , Some ( pat. span ) ) ,
581+ self . tcx . require_lang_item ( hir:: LangItem :: Unpin , pat. span ) ,
570582 self . misc ( pat. span ) ,
571- ) ;
583+ )
572584 }
585+ // Once we've checked `pat`, we'll add a `!Unpin` bound if it contains any
586+ // `ref pin` bindings. See `Self::register_not_unpin_bounds_if_needed`.
587+
588+ debug ! ( "default binding mode is now {:?}" , binding_mode) ;
589+
573590 // Use the old pat info to keep `current_depth` to its old value.
574591 let new_pat_info = PatInfo { binding_mode, ..old_pat_info } ;
575- // Recurse with the new expected type.
576- // using `break` instead of `return` in case where any shared codes are added
577- // after the `match pat.kind {}`.
578- self . check_pat_inner ( pat, opt_path_res, adjust_mode, inner_ty, new_pat_info)
592+
593+ self . check_deref_pattern (
594+ pat,
595+ opt_path_res,
596+ adjust_mode,
597+ expected,
598+ inner_ty,
599+ PatAdjust :: PinDeref ,
600+ new_pat_info,
601+ )
579602 }
580603 // If `deref_patterns` is enabled, peel a smart pointer from the scrutinee type. See the
581604 // examples in `tests/ui/pattern/deref_patterns/`.
@@ -584,35 +607,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
584607 && pat. default_binding_modes
585608 && self . should_peel_smart_pointer ( peel_kind, expected) =>
586609 {
587- debug ! ( "scrutinee ty {expected:?} is a smart pointer, inserting overloaded deref" ) ;
610+ debug ! ( "scrutinee ty {expected:?} is a smart pointer, inserting pin deref" ) ;
611+
588612 // The scrutinee is a smart pointer; implicitly dereference it. This adds a
589613 // requirement that `expected: DerefPure`.
590- let mut inner_ty = self . deref_pat_target ( pat. span , expected) ;
614+ let inner_ty = self . deref_pat_target ( pat. span , expected) ;
591615 // Once we've checked `pat`, we'll add a `DerefMut` bound if it contains any
592616 // `ref mut` bindings. See `Self::register_deref_mut_bounds_if_needed`.
593617
594- let mut typeck_results = self . typeck_results . borrow_mut ( ) ;
595- let mut pat_adjustments_table = typeck_results. pat_adjustments_mut ( ) ;
596- let pat_adjustments = pat_adjustments_table. entry ( pat. hir_id ) . or_default ( ) ;
597- // We may reach the recursion limit if a user matches on a type `T` satisfying
598- // `T: Deref<Target = T>`; error gracefully in this case.
599- // FIXME(deref_patterns): If `deref_patterns` stabilizes, it may make sense to move
600- // this check out of this branch. Alternatively, this loop could be implemented with
601- // autoderef and this check removed. For now though, don't break code compiling on
602- // stable with lots of `&`s and a low recursion limit, if anyone's done that.
603- if self . tcx . recursion_limit ( ) . value_within_limit ( pat_adjustments. len ( ) ) {
604- // Preserve the smart pointer type for THIR lowering and closure upvar analysis.
605- pat_adjustments
606- . push ( PatAdjustment { kind : PatAdjust :: OverloadedDeref , source : expected } ) ;
607- } else {
608- let guar = report_autoderef_recursion_limit_error ( self . tcx , pat. span , expected) ;
609- inner_ty = Ty :: new_error ( self . tcx , guar) ;
610- }
611- drop ( typeck_results) ;
612-
613- // Recurse, using the old pat info to keep `current_depth` to its old value.
614- // Peeling smart pointers does not update the default binding mode.
615- self . check_pat_inner ( pat, opt_path_res, adjust_mode, inner_ty, old_pat_info)
618+ self . check_deref_pattern (
619+ pat,
620+ opt_path_res,
621+ adjust_mode,
622+ expected,
623+ inner_ty,
624+ PatAdjust :: OverloadedDeref ,
625+ old_pat_info,
626+ )
616627 }
617628 PatKind :: Missing | PatKind :: Wild | PatKind :: Err ( _) => expected,
618629 // We allow any type here; we ensure that the type is uninhabited during match checking.
@@ -683,6 +694,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
683694 }
684695 }
685696
697+ fn check_deref_pattern (
698+ & self ,
699+ pat : & ' tcx Pat < ' tcx > ,
700+ opt_path_res : Option < Result < ResolvedPat < ' tcx > , ErrorGuaranteed > > ,
701+ adjust_mode : AdjustMode ,
702+ expected : Ty < ' tcx > ,
703+ mut inner_ty : Ty < ' tcx > ,
704+ pat_adjust_kind : PatAdjust ,
705+ pat_info : PatInfo < ' tcx > ,
706+ ) -> Ty < ' tcx > {
707+ debug_assert ! (
708+ !matches!( pat_adjust_kind, PatAdjust :: BuiltinDeref ) ,
709+ "unexpected deref pattern for builtin reference type {expected:?}" ,
710+ ) ;
711+
712+ let mut typeck_results = self . typeck_results . borrow_mut ( ) ;
713+ let mut pat_adjustments_table = typeck_results. pat_adjustments_mut ( ) ;
714+ let pat_adjustments = pat_adjustments_table. entry ( pat. hir_id ) . or_default ( ) ;
715+ // We may reach the recursion limit if a user matches on a type `T` satisfying
716+ // `T: Deref<Target = T>`; error gracefully in this case.
717+ // FIXME(deref_patterns): If `deref_patterns` stabilizes, it may make sense to move
718+ // this check out of this branch. Alternatively, this loop could be implemented with
719+ // autoderef and this check removed. For now though, don't break code compiling on
720+ // stable with lots of `&`s and a low recursion limit, if anyone's done that.
721+ if self . tcx . recursion_limit ( ) . value_within_limit ( pat_adjustments. len ( ) ) {
722+ // Preserve the smart pointer type for THIR lowering and closure upvar analysis.
723+ pat_adjustments. push ( PatAdjustment { kind : pat_adjust_kind, source : expected } ) ;
724+ } else {
725+ let guar = report_autoderef_recursion_limit_error ( self . tcx , pat. span , expected) ;
726+ inner_ty = Ty :: new_error ( self . tcx , guar) ;
727+ }
728+ drop ( typeck_results) ;
729+
730+ // Recurse, using the old pat info to keep `current_depth` to its old value.
731+ // Peeling smart pointers does not update the default binding mode.
732+ self . check_pat_inner ( pat, opt_path_res, adjust_mode, inner_ty, pat_info)
733+ }
734+
686735 /// How should the binding mode and expected type be adjusted?
687736 ///
688737 /// When the pattern contains a path, `opt_path_res` must be `Some(path_res)`.
@@ -1185,7 +1234,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11851234 // Wrapping the type into `Pin` if the binding is like `ref pin const|mut x`
11861235 ByRef :: Yes ( Pinnedness :: Pinned , mutbl) => Ty :: new_adt (
11871236 self . tcx ,
1188- self . tcx . adt_def ( self . tcx . require_lang_item ( hir:: LangItem :: Pin , Some ( pat. span ) ) ) ,
1237+ self . tcx . adt_def ( self . tcx . require_lang_item ( hir:: LangItem :: Pin , pat. span ) ) ,
11891238 self . tcx . mk_args ( & [ self . new_ref_ty ( pat. span , mutbl, expected) . into ( ) ] ) ,
11901239 ) ,
11911240 // Otherwise, the type of x is the expected type `T`.
@@ -2628,6 +2677,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
26282677 }
26292678 }
26302679
2680+ /// Check if the interior of a pin pattern (either explicit or implicit) has any `ref pin`
2681+ /// bindings of non-`Unpin` types, which would require `!Unpin` to be emitted.
2682+ fn register_not_unpin_bounds_if_needed (
2683+ & self ,
2684+ span : Span ,
2685+ inner : & ' tcx Pat < ' tcx > ,
2686+ derefed_tys : impl IntoIterator < Item = Ty < ' tcx > > ,
2687+ ) {
2688+ // Check if there are subpatterns with `ref pin` binding modes of non-`Unpin` types.
2689+ let unpin = self . tcx . require_lang_item ( hir:: LangItem :: Unpin , span) ;
2690+ let cause = self . misc ( span) ;
2691+ let unpin_obligations = self . probe ( |_| {
2692+ let ocx = ObligationCtxt :: new ( & self ) ;
2693+ self . typeck_results . borrow ( ) . pat_walk_ref_pin_binding_of_non_unpin_type ( inner, |ty| {
2694+ let ty = ocx
2695+ . normalize ( & cause, self . param_env , ty)
2696+ . pinned_ref ( )
2697+ . expect ( "expect pinned reference" )
2698+ . 0 ;
2699+ debug ! ( "check if `Unpin` is implemented for `{ty:?}`" ) ;
2700+ ocx. register_bound ( cause. clone ( ) , self . param_env , ty, unpin) ;
2701+ } ) ;
2702+ ocx. select_all_or_error ( )
2703+ } ) ;
2704+
2705+ // If any, the current pattern type should implement `!Unpin`.
2706+ if !unpin_obligations. is_empty ( ) {
2707+ for pinned_derefed_ty in derefed_tys {
2708+ debug ! ( "register `!Unpin` for `{pinned_derefed_ty:?}`" ) ;
2709+ self . register_negative_bound (
2710+ pinned_derefed_ty,
2711+ self . tcx . require_lang_item ( hir:: LangItem :: Unpin , span) ,
2712+ self . misc ( span) ,
2713+ ) ;
2714+ }
2715+ }
2716+ }
2717+
26312718 // Precondition: Pat is Ref(inner)
26322719 fn check_pat_ref (
26332720 & self ,
@@ -2654,7 +2741,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
26542741 expected = self . try_structurally_resolve_type ( pat. span , expected) ;
26552742 // Determine whether we're consuming an inherited reference and resetting the default
26562743 // binding mode, based on edition and enabled experimental features.
2657- if let ByRef :: Yes ( _, inh_mut) = pat_info. binding_mode {
2744+ // FIXME(pin_ergonomics): since `&pin` pattern is supported, the condition here
2745+ // should be adjusted to `pat_pin == inh_pin`
2746+ if let ByRef :: Yes ( Pinnedness :: Not , inh_mut) = pat_info. binding_mode {
26582747 match self . ref_pat_matches_inherited_ref ( pat. span . edition ( ) ) {
26592748 InheritedRefMatchRule :: EatOuter => {
26602749 // ref pattern attempts to consume inherited reference
@@ -2673,9 +2762,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
26732762 return expected;
26742763 }
26752764 InheritedRefMatchRule :: EatInner => {
2676- if let ty:: Ref ( _, _, r_mutbl) = * expected. kind ( )
2677- && pat_mutbl <= r_mutbl
2678- {
2765+ let expected_ref_or_pinned_ref = || {
2766+ if self . tcx . features ( ) . pin_ergonomics ( )
2767+ && let Some ( ty:: Ref ( _, _, r_mutbl) ) =
2768+ expected. pinned_ty ( ) . map ( |ty| * ty. kind ( ) )
2769+ && pat_mutbl <= r_mutbl
2770+ {
2771+ return Some ( ( Pinnedness :: Pinned , r_mutbl) ) ;
2772+ }
2773+ if let ty:: Ref ( _, _, r_mutbl) = * expected. kind ( )
2774+ && pat_mutbl <= r_mutbl
2775+ {
2776+ return Some ( ( Pinnedness :: Not , r_mutbl) ) ;
2777+ }
2778+ None
2779+ } ;
2780+ if let Some ( ( _, r_mutbl) ) = expected_ref_or_pinned_ref ( ) {
26792781 // Match against the reference type; don't consume the inherited ref.
26802782 // NB: The check for compatible pattern and ref type mutability assumes that
26812783 // `&` patterns can match against mutable references (RFC 3627, Rule 5). If
0 commit comments