@@ -39,28 +39,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3939 candidate : & mut Candidate < ' pat , ' tcx > ,
4040 ) -> bool {
4141 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):
4544 //
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
6445 // struct NonCopyStruct {
6546 // copy_field: u32,
6647 // }
@@ -72,23 +53,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
7253 // let y = x;
7354 // }
7455 //
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.
8259 //
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 ) ;
9270 // Repeatedly simplify match pairs until fixed point is reached
9371 loop {
9472 let mut changed = false ;
@@ -103,9 +81,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
10381 }
10482 }
10583
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 ) ;
10987 candidate. bindings . clear ( ) ;
11088
11189 if !changed {
@@ -114,10 +92,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
11492 }
11593 }
11694
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) ;
12197
12298 let did_expand_or =
12399 if let [ MatchPair { pattern : Pat { kind : PatKind :: Or { pats } , .. } , place } ] =
0 commit comments