Skip to content

Commit 0825ad3

Browse files
committed
Clarify the new binding dance
1 parent 09d4613 commit 0825ad3

File tree

1 file changed

+20
-44
lines changed

1 file changed

+20
-44
lines changed

compiler/rustc_mir_build/src/build/matches/simplify.rs

+20-44
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)