@@ -48,8 +48,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
48
48
pub fn check_pat_walk (
49
49
& self ,
50
50
pat : & ' tcx hir:: Pat ,
51
- mut expected : Ty < ' tcx > ,
52
- mut def_bm : ty:: BindingMode ,
51
+ expected : Ty < ' tcx > ,
52
+ def_bm : ty:: BindingMode ,
53
53
discrim_span : Option < Span > ,
54
54
) {
55
55
let tcx = self . tcx ;
@@ -62,53 +62,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
62
62
} ;
63
63
64
64
let is_non_ref_pat = self . is_non_ref_pat ( pat, path_resolution. map ( |( res, ..) | res) ) ;
65
- if is_non_ref_pat {
65
+ let ( expected , def_bm ) = if is_non_ref_pat {
66
66
debug ! ( "pattern is non reference pattern" ) ;
67
- let mut exp_ty = self . resolve_type_vars_with_obligations ( & expected) ;
68
-
69
- // Peel off as many `&` or `&mut` from the discriminant as possible. For example,
70
- // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
71
- // the `Some(5)` which is not of type Ref.
72
- //
73
- // For each ampersand peeled off, update the binding mode and push the original
74
- // type into the adjustments vector.
75
- //
76
- // See the examples in `ui/match-defbm*.rs`.
77
- let mut pat_adjustments = vec ! [ ] ;
78
- while let ty:: Ref ( _, inner_ty, inner_mutability) = exp_ty. sty {
79
- debug ! ( "inspecting {:?}" , exp_ty) ;
80
-
81
- debug ! ( "current discriminant is Ref, inserting implicit deref" ) ;
82
- // Preserve the reference type. We'll need it later during HAIR lowering.
83
- pat_adjustments. push ( exp_ty) ;
84
-
85
- exp_ty = inner_ty;
86
- def_bm = match def_bm {
87
- // If default binding mode is by value, make it `ref` or `ref mut`
88
- // (depending on whether we observe `&` or `&mut`).
89
- ty:: BindByValue ( _) =>
90
- ty:: BindByReference ( inner_mutability) ,
91
-
92
- // Once a `ref`, always a `ref`. This is because a `& &mut` can't mutate
93
- // the underlying value.
94
- ty:: BindByReference ( hir:: Mutability :: MutImmutable ) =>
95
- ty:: BindByReference ( hir:: Mutability :: MutImmutable ) ,
96
-
97
- // When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref`
98
- // (on `&`).
99
- ty:: BindByReference ( hir:: Mutability :: MutMutable ) =>
100
- ty:: BindByReference ( inner_mutability) ,
101
- } ;
102
- }
103
- expected = exp_ty;
104
-
105
- if pat_adjustments. len ( ) > 0 {
106
- debug ! ( "default binding mode is now {:?}" , def_bm) ;
107
- self . inh . tables . borrow_mut ( )
108
- . pat_adjustments_mut ( )
109
- . insert ( pat. hir_id , pat_adjustments) ;
110
- }
111
- } else if let PatKind :: Ref ( ..) = pat. node {
67
+ self . peel_off_references ( pat, expected, def_bm)
68
+ } else {
112
69
// When you encounter a `&pat` pattern, reset to "by
113
70
// value". This is so that `x` and `y` here are by value,
114
71
// as they appear to be:
@@ -120,12 +77,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
120
77
// ```
121
78
//
122
79
// See issue #46688.
123
- def_bm = ty :: BindByValue ( hir :: MutImmutable ) ;
124
- }
125
-
126
- // Lose mutability now that we know binding mode and discriminant type.
127
- let def_bm = def_bm;
128
- let expected = expected ;
80
+ let def_bm = match pat . node {
81
+ PatKind :: Ref ( .. ) => ty :: BindByValue ( hir :: MutImmutable ) ,
82
+ _ => def_bm ,
83
+ } ;
84
+ ( expected , def_bm)
85
+ } ;
129
86
130
87
let ty = match pat. node {
131
88
PatKind :: Wild => {
@@ -568,6 +525,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
568
525
}
569
526
}
570
527
528
+ /// Peel off as many immediately nested `& mut?` from the expected type as possible
529
+ /// and return the new expected type and binding default binding mode.
530
+ /// The adjustments vector, if non-empty is stored in a table.
531
+ fn peel_off_references (
532
+ & self ,
533
+ pat : & ' tcx hir:: Pat ,
534
+ expected : Ty < ' tcx > ,
535
+ mut def_bm : ty:: BindingMode ,
536
+ ) -> ( Ty < ' tcx > , ty:: BindingMode ) {
537
+ let mut expected = self . resolve_type_vars_with_obligations ( & expected) ;
538
+
539
+ // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
540
+ // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
541
+ // the `Some(5)` which is not of type Ref.
542
+ //
543
+ // For each ampersand peeled off, update the binding mode and push the original
544
+ // type into the adjustments vector.
545
+ //
546
+ // See the examples in `ui/match-defbm*.rs`.
547
+ let mut pat_adjustments = vec ! [ ] ;
548
+ while let ty:: Ref ( _, inner_ty, inner_mutability) = expected. sty {
549
+ debug ! ( "inspecting {:?}" , expected) ;
550
+
551
+ debug ! ( "current discriminant is Ref, inserting implicit deref" ) ;
552
+ // Preserve the reference type. We'll need it later during HAIR lowering.
553
+ pat_adjustments. push ( expected) ;
554
+
555
+ expected = inner_ty;
556
+ def_bm = match def_bm {
557
+ // If default binding mode is by value, make it `ref` or `ref mut`
558
+ // (depending on whether we observe `&` or `&mut`).
559
+ ty:: BindByValue ( _) =>
560
+ ty:: BindByReference ( inner_mutability) ,
561
+
562
+ // Once a `ref`, always a `ref`. This is because a `& &mut` can't mutate
563
+ // the underlying value.
564
+ ty:: BindByReference ( hir:: Mutability :: MutImmutable ) =>
565
+ ty:: BindByReference ( hir:: Mutability :: MutImmutable ) ,
566
+
567
+ // When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref`
568
+ // (on `&`).
569
+ ty:: BindByReference ( hir:: Mutability :: MutMutable ) =>
570
+ ty:: BindByReference ( inner_mutability) ,
571
+ } ;
572
+ }
573
+
574
+ if pat_adjustments. len ( ) > 0 {
575
+ debug ! ( "default binding mode is now {:?}" , def_bm) ;
576
+ self . inh . tables . borrow_mut ( )
577
+ . pat_adjustments_mut ( )
578
+ . insert ( pat. hir_id , pat_adjustments) ;
579
+ }
580
+
581
+ ( expected, def_bm)
582
+ }
583
+
571
584
fn borrow_pat_suggestion (
572
585
& self ,
573
586
err : & mut DiagnosticBuilder < ' _ > ,
0 commit comments