@@ -39,28 +39,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
39
39
candidate : & mut Candidate < ' pat , ' tcx > ,
40
40
) -> bool {
41
41
debug ! ( "{candidate:#?}" ) ;
42
- // `original_bindings` and `new_bindings` exist to keep the semantics in order.
43
- // Reversing the binding order for bindings after `@` changes the binding order in places
44
- // where it shouldn't be changed, for example `let (Some(a), Some(b)) = (x, y)`.
42
+ // In order to please the borrow checker, in a pattern like `x @ pat` we must lower the
43
+ // bindings in `pat` before `x`. E.g. (#69971):
45
44
//
46
- // To avoid this, the binding occurs in the following manner:
47
- // * the bindings for one iteration of the loop occurs in order (i.e. left to right)
48
- // * the bindings from the previous iteration of the loop is prepended to the bindings from
49
- // the current iteration (in the implementation this is done by mem::swap and extend)
50
- // * after all iterations, these new bindings are then appended to the bindings that were
51
- // preexisting (i.e. `candidate.binding` when the function was called).
52
- //
53
- // example:
54
- // candidate.bindings = [1, 2, 3]
55
- // binding in iter 1: [4, 5]
56
- // binding in iter 2: [6, 7]
57
- //
58
- // final binding: [1, 2, 3, 6, 7, 4, 5]
59
- //
60
- // This is because we treat refutable and irrefutable bindings differently. The binding
61
- // order should be right-to-left if there are more _irrefutable_ bindings after `@` to
62
- // please the borrow checker (#69971)
63
- // Ex
64
45
// struct NonCopyStruct {
65
46
// copy_field: u32,
66
47
// }
@@ -72,23 +53,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
72
53
// let y = x;
73
54
// }
74
55
//
75
- // If however the bindings are refutable, i.e. under a test, then we keep the bindings
76
- // left-to-right.
77
- // Ex
78
- // enum NonCopyEnum {
79
- // Variant { copy_field: u32 },
80
- // None,
81
- // }
56
+ // We can't just reverse the binding order, because we must preserve pattern-order
57
+ // otherwise, e.g. in `let (Some(a), Some(b)) = (x, y)`. Our rule then is: deepest-first,
58
+ // and bindings at the same depth stay in source order.
82
59
//
83
- // fn foo2(x: NonCopyEnum) {
84
- // let y @ NonCopyEnum::Variant { copy_field: z } = x else { return };
85
- // // turns into
86
- // let y = x;
87
- // let z = (x as Variant).copy_field;
88
- // // and raises an error
89
- // }
90
- let original_bindings = mem:: take ( & mut candidate. bindings ) ;
91
- let mut new_bindings = Vec :: new ( ) ;
60
+ // To do this, every time around the loop we prepend the newly found bindings to the
61
+ // bindings we already had.
62
+ //
63
+ // example:
64
+ // candidate.bindings = [1, 2, 3]
65
+ // bindings in iter 1: [4, 5]
66
+ // bindings in iter 2: [6, 7]
67
+ //
68
+ // final bindings: [6, 7, 4, 5, 1, 2, 3]
69
+ let mut accumulated_bindings = mem:: take ( & mut candidate. bindings ) ;
92
70
// Repeatedly simplify match pairs until fixed point is reached
93
71
loop {
94
72
let mut changed = false ;
@@ -103,9 +81,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
103
81
}
104
82
}
105
83
106
- // This does: new_bindings = candidate.bindings.take() ++ new_bindings
107
- candidate. bindings . extend_from_slice ( & new_bindings ) ;
108
- mem:: swap ( & mut candidate. bindings , & mut new_bindings ) ;
84
+ // This does: accumulated_bindings = candidate.bindings.take() ++ accumulated_bindings
85
+ candidate. bindings . extend_from_slice ( & accumulated_bindings ) ;
86
+ mem:: swap ( & mut candidate. bindings , & mut accumulated_bindings ) ;
109
87
candidate. bindings . clear ( ) ;
110
88
111
89
if !changed {
@@ -114,10 +92,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
114
92
}
115
93
}
116
94
117
- // Restore original bindings and append the new ones.
118
- // This does: candidate.bindings = new_bindings ++ original_bindings
119
- mem:: swap ( & mut candidate. bindings , & mut new_bindings) ;
120
- candidate. bindings . extend_from_slice ( & original_bindings) ;
95
+ // Store computed bindings back in `candidate`.
96
+ mem:: swap ( & mut candidate. bindings , & mut accumulated_bindings) ;
121
97
122
98
let did_expand_or =
123
99
if let [ MatchPair { pattern : Pat { kind : PatKind :: Or { pats } , .. } , place } ] =
0 commit comments