@@ -88,6 +88,7 @@ struct TopInfo<'tcx> {
8888
8989#[ derive( Copy , Clone ) ]
9090struct PatInfo < ' tcx > {
91+ pinnedness : ast:: Pinnedness ,
9192 binding_mode : ByRef ,
9293 max_ref_mutbl : MutblCap ,
9394 top_info : TopInfo < ' tcx > ,
@@ -302,6 +303,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
302303 ) {
303304 let top_info = TopInfo { expected, origin_expr, span, hir_id : pat. hir_id } ;
304305 let pat_info = PatInfo {
306+ pinnedness : ast:: Pinnedness :: Not ,
305307 binding_mode : ByRef :: No ,
306308 max_ref_mutbl : MutblCap :: Mut ,
307309 top_info,
@@ -400,11 +402,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
400402 let pat_info = PatInfo { current_depth : old_pat_info. current_depth + 1 , ..old_pat_info } ;
401403
402404 match pat. kind {
403- // Peel off a `&` or `&mut` from the scrutinee type. See the examples in
404- // `tests/ui/rfcs/rfc-2005-default-binding-mode`.
405+ // Peel off a `&`, `&mut`, `&pin const` or `&pin mut` from the scrutinee type.
406+ // See the examples in `tests/ui/rfcs/rfc-2005-default-binding-mode`
407+ // and `tests/ui/async-await/pin-ergonomics/project-pattern-match`.
405408 _ if let AdjustMode :: Peel = adjust_mode
406409 && pat. default_binding_modes
407- && let ty:: Ref ( _, inner_ty, inner_mutability) = * expected. kind ( ) =>
410+ && let Some ( ( _, pinnedness, inner_ty, inner_mutability) ) =
411+ expected. is_ref_or_pin_ref ( self . tcx ) =>
408412 {
409413 debug ! ( "inspecting {:?}" , expected) ;
410414
@@ -428,6 +432,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
428432 ByRef :: Yes ( Mutability :: Not ) => Mutability :: Not ,
429433 } ) ;
430434
435+ let pinnedness = pinnedness. max ( pat_info. pinnedness ) ;
436+
431437 let mut max_ref_mutbl = pat_info. max_ref_mutbl ;
432438 if self . downgrade_mut_inside_shared ( ) {
433439 binding_mode = binding_mode. cap_ref_mutability ( max_ref_mutbl. as_mutbl ( ) ) ;
@@ -438,7 +444,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
438444 debug ! ( "default binding mode is now {:?}" , binding_mode) ;
439445
440446 // Use the old pat info to keep `current_depth` to its old value.
441- let new_pat_info = PatInfo { binding_mode, max_ref_mutbl, ..old_pat_info } ;
447+ let new_pat_info =
448+ PatInfo { pinnedness, binding_mode, max_ref_mutbl, ..old_pat_info } ;
442449 // Recurse with the new expected type.
443450 self . check_pat_inner ( pat, opt_path_res, adjust_mode, inner_ty, new_pat_info)
444451 }
@@ -790,7 +797,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
790797 expected : Ty < ' tcx > ,
791798 pat_info : PatInfo < ' tcx > ,
792799 ) -> Ty < ' tcx > {
793- let PatInfo { binding_mode : def_br, top_info : ti, .. } = pat_info;
800+ let PatInfo { pinnedness , binding_mode : def_br, top_info : ti, .. } = pat_info;
794801
795802 // Determine the binding mode...
796803 let bm = match user_bind_annot {
@@ -883,6 +890,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
883890 ByRef :: No => expected, // As above, `T <: typeof(x)` is required, but we use equality, see (note_1).
884891 } ;
885892
893+ // Wrapping the type into `Pin` if the pattern is pinned
894+ let eq_ty = if pinnedness == ast:: Pinnedness :: Pinned {
895+ Ty :: new_adt (
896+ self . tcx ,
897+ self . tcx . adt_def ( self . tcx . require_lang_item ( hir:: LangItem :: Pin , Some ( pat. span ) ) ) ,
898+ self . tcx . mk_args ( & [ eq_ty. into ( ) ] ) ,
899+ )
900+ } else {
901+ eq_ty
902+ } ;
903+
886904 // We have a concrete type for the local, so we do not need to taint it and hide follow up errors *using* the local.
887905 let _ = self . demand_eqtype_pat ( pat. span , eq_ty, local_ty, & ti) ;
888906
@@ -1386,6 +1404,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13861404 for ( i, subpat) in subpats. iter ( ) . enumerate_and_adjust ( variant. fields . len ( ) , ddpos) {
13871405 let field = & variant. fields [ FieldIdx :: from_usize ( i) ] ;
13881406 let field_ty = self . field_ty ( subpat. span , field, args) ;
1407+ // If the field is not marked as `#[pin]`, then remove the
1408+ // pinnedness in `pat_info`.
1409+ let pinnedness = pat_info. pinnedness . min ( field. pinnedness ) ;
1410+ let pat_info = PatInfo { pinnedness, ..pat_info } ;
13891411 self . check_pat ( subpat, field_ty, pat_info) ;
13901412
13911413 self . tcx . check_stability (
@@ -1642,11 +1664,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16421664 for field in fields {
16431665 let span = field. span ;
16441666 let ident = tcx. adjust_ident ( field. ident , variant. def_id ) ;
1645- let field_ty = match used_fields. entry ( ident) {
1667+ let ( field_ty, pinnedness ) = match used_fields. entry ( ident) {
16461668 Occupied ( occupied) => {
16471669 let guar = self . error_field_already_bound ( span, field. ident , * occupied. get ( ) ) ;
16481670 result = Err ( guar) ;
1649- Ty :: new_error ( tcx, guar)
1671+ ( Ty :: new_error ( tcx, guar) , ast :: Pinnedness :: Not )
16501672 }
16511673 Vacant ( vacant) => {
16521674 vacant. insert ( span) ;
@@ -1655,15 +1677,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16551677 . map ( |( i, f) | {
16561678 self . write_field_index ( field. hir_id , * i) ;
16571679 self . tcx . check_stability ( f. did , Some ( field. hir_id ) , span, None ) ;
1658- self . field_ty ( span, f, args)
1680+ ( self . field_ty ( span, f, args) , f . pinnedness )
16591681 } )
16601682 . unwrap_or_else ( || {
16611683 inexistent_fields. push ( field) ;
1662- Ty :: new_misc_error ( tcx)
1684+ ( Ty :: new_misc_error ( tcx) , ast :: Pinnedness :: Not )
16631685 } )
16641686 }
16651687 } ;
16661688
1689+ // If the field is not marked as `#[pin]`, then remove the
1690+ // pinnedness in `pat_info`.
1691+ let pinnedness = pat_info. pinnedness . min ( pinnedness) ;
1692+ let pat_info = PatInfo { pinnedness, ..pat_info } ;
16671693 self . check_pat ( field. pat , field_ty, pat_info) ;
16681694 }
16691695
0 commit comments