Skip to content

Commit 30976fb

Browse files
authored
Rollup merge of rust-lang#121716 - Nadrieril:simple-binding-order, r=matthewjasper
match lowering: Lower bindings in a predictable order After the recent refactorings, we can now lower bindings in a truly predictable order. The order in rust-lang#120214 was an improvement but not very clear. With this PR, we lower bindings from left to right, with the special case that `x @ pat` is traversed as `pat @ x` (i.e. `x` is lowered after any bindings in `pat`). This description only applies in the absence of or-patterns. Or-patterns make everything complicated, because the binding place depends on the subpattern. Until I have a better idea I leave them to be handled in whatever weird order arises from today's code. r? `@matthewjasper`
2 parents b0ca9b5 + 00497ad commit 30976fb

11 files changed

+118
-100
lines changed

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -701,7 +701,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
701701
self.bind_pattern(
702702
self.source_info(irrefutable_pat.span),
703703
candidate,
704-
&fake_borrow_temps,
704+
fake_borrow_temps.as_slice(),
705705
irrefutable_pat.span,
706706
None,
707707
false,
@@ -1938,7 +1938,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
19381938
let post_guard_block = self.bind_pattern(
19391939
self.source_info(pat.span),
19401940
guard_candidate,
1941-
&fake_borrow_temps,
1941+
fake_borrow_temps.as_slice(),
19421942
expr_span,
19431943
None,
19441944
false,
@@ -2425,7 +2425,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
24252425
let matching = this.bind_pattern(
24262426
this.source_info(pattern.span),
24272427
candidate,
2428-
&fake_borrow_temps,
2428+
fake_borrow_temps.as_slice(),
24292429
initializer_span,
24302430
None,
24312431
true,
@@ -2434,7 +2434,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
24342434
let failure = this.bind_pattern(
24352435
this.source_info(else_block_span),
24362436
wildcard,
2437-
&fake_borrow_temps,
2437+
fake_borrow_temps.as_slice(),
24382438
initializer_span,
24392439
None,
24402440
true,

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

+20-50
Original file line numberDiff line numberDiff line change
@@ -41,60 +41,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
4141
// let y = x;
4242
// }
4343
//
44-
// We can't just reverse the binding order, because we must preserve pattern-order
45-
// otherwise, e.g. in `let (Some(a), Some(b)) = (x, y)`. Our rule then is: deepest-first,
46-
// and bindings at the same depth stay in source order.
47-
//
48-
// To do this, every time around the loop we prepend the newly found bindings to the
49-
// bindings we already had.
50-
//
51-
// example:
52-
// candidate.bindings = [1, 2, 3]
53-
// bindings in iter 1: [4, 5]
54-
// bindings in iter 2: [6, 7]
55-
//
56-
// final bindings: [6, 7, 4, 5, 1, 2, 3]
57-
let mut accumulated_bindings = mem::take(candidate_bindings);
58-
let mut simplified_match_pairs = Vec::new();
59-
// Repeatedly simplify match pairs until we're left with only unsimplifiable ones.
60-
loop {
61-
for mut match_pair in mem::take(match_pairs) {
62-
if let TestCase::Irrefutable { binding, ascription } = match_pair.test_case {
63-
if let Some(binding) = binding {
64-
candidate_bindings.push(binding);
65-
}
66-
if let Some(ascription) = ascription {
67-
candidate_ascriptions.push(ascription);
68-
}
69-
// Simplifiable pattern; we replace it with its subpairs and simplify further.
70-
match_pairs.append(&mut match_pair.subpairs);
71-
} else {
72-
// Unsimplifiable pattern; we recursively simplify its subpairs and don't
73-
// process it further.
74-
self.simplify_match_pairs(
75-
&mut match_pair.subpairs,
76-
candidate_bindings,
77-
candidate_ascriptions,
78-
);
79-
simplified_match_pairs.push(match_pair);
44+
// We therefore lower bindings from left-to-right, except we lower the `x` in `x @ pat`
45+
// after any bindings in `pat`. This doesn't work for or-patterns: the current structure of
46+
// match lowering forces us to lower bindings inside or-patterns last.
47+
for mut match_pair in mem::take(match_pairs) {
48+
self.simplify_match_pairs(
49+
&mut match_pair.subpairs,
50+
candidate_bindings,
51+
candidate_ascriptions,
52+
);
53+
if let TestCase::Irrefutable { binding, ascription } = match_pair.test_case {
54+
if let Some(binding) = binding {
55+
candidate_bindings.push(binding);
8056
}
81-
}
82-
83-
// This does: accumulated_bindings = candidate.bindings.take() ++ accumulated_bindings
84-
candidate_bindings.extend_from_slice(&accumulated_bindings);
85-
mem::swap(candidate_bindings, &mut accumulated_bindings);
86-
candidate_bindings.clear();
87-
88-
if match_pairs.is_empty() {
89-
break;
57+
if let Some(ascription) = ascription {
58+
candidate_ascriptions.push(ascription);
59+
}
60+
// Simplifiable pattern; we replace it with its already simplified subpairs.
61+
match_pairs.append(&mut match_pair.subpairs);
62+
} else {
63+
// Unsimplifiable pattern; we keep it.
64+
match_pairs.push(match_pair);
9065
}
9166
}
9267

93-
// Store computed bindings back in `candidate_bindings`.
94-
mem::swap(candidate_bindings, &mut accumulated_bindings);
95-
// Store simplified match pairs back in `match_pairs`.
96-
mem::swap(match_pairs, &mut simplified_match_pairs);
97-
9868
// Move or-patterns to the end, because they can result in us
9969
// creating additional candidates, so we want to test them as
10070
// late as possible.

tests/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff

+3-3
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,13 @@
5151
- }
5252
-
5353
- bb3: {
54-
StorageLive(_9);
55-
_9 = (((_3.1: std::option::Option<u32>) as Some).0: u32);
5654
StorageLive(_8);
5755
_8 = (((_3.0: std::option::Option<u32>) as Some).0: u32);
56+
StorageLive(_9);
57+
_9 = (((_3.1: std::option::Option<u32>) as Some).0: u32);
5858
_0 = const 0_u32;
59-
StorageDead(_8);
6059
StorageDead(_9);
60+
StorageDead(_8);
6161
- goto -> bb4;
6262
+ goto -> bb3;
6363
}

tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff

+3-3
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,13 @@
5757
- }
5858
-
5959
- bb4: {
60-
StorageLive(_10);
61-
_10 = (((_3.1: std::option::Option<u32>) as Some).0: u32);
6260
StorageLive(_9);
6361
_9 = (((_3.0: std::option::Option<u32>) as Some).0: u32);
62+
StorageLive(_10);
63+
_10 = (((_3.1: std::option::Option<u32>) as Some).0: u32);
6464
_0 = const 0_u32;
65-
StorageDead(_9);
6665
StorageDead(_10);
66+
StorageDead(_9);
6767
- goto -> bb6;
6868
+ goto -> bb4;
6969
}

tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff

+3-3
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,13 @@
5151
- }
5252
-
5353
- bb3: {
54-
StorageLive(_9);
55-
_9 = (((_3.1: std::option::Option<bool>) as Some).0: bool);
5654
StorageLive(_8);
5755
_8 = (((_3.0: std::option::Option<u32>) as Some).0: u32);
56+
StorageLive(_9);
57+
_9 = (((_3.1: std::option::Option<bool>) as Some).0: bool);
5858
_0 = const 0_u32;
59-
StorageDead(_8);
6059
StorageDead(_9);
60+
StorageDead(_8);
6161
- goto -> bb4;
6262
+ goto -> bb3;
6363
}

tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff

+6-6
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,16 @@
6969

7070
- bb4: {
7171
+ bb3: {
72-
StorageLive(_13);
73-
_13 = (((_4.2: std::option::Option<u32>) as Some).0: u32);
74-
StorageLive(_12);
75-
_12 = (((_4.1: std::option::Option<u32>) as Some).0: u32);
7672
StorageLive(_11);
7773
_11 = (((_4.0: std::option::Option<u32>) as Some).0: u32);
74+
StorageLive(_12);
75+
_12 = (((_4.1: std::option::Option<u32>) as Some).0: u32);
76+
StorageLive(_13);
77+
_13 = (((_4.2: std::option::Option<u32>) as Some).0: u32);
7878
_0 = const 0_u32;
79-
StorageDead(_11);
80-
StorageDead(_12);
8179
StorageDead(_13);
80+
StorageDead(_12);
81+
StorageDead(_11);
8282
- goto -> bb5;
8383
+ goto -> bb4;
8484
}

tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff

+24-24
Original file line numberDiff line numberDiff line change
@@ -116,12 +116,12 @@
116116
}
117117

118118
bb6: {
119-
StorageLive(_13);
120-
_39 = deref_copy (_4.1: &ViewportPercentageLength);
121-
_13 = (((*_39) as Vw).0: f32);
122119
StorageLive(_12);
123-
_40 = deref_copy (_4.0: &ViewportPercentageLength);
124-
_12 = (((*_40) as Vw).0: f32);
120+
_39 = deref_copy (_4.0: &ViewportPercentageLength);
121+
_12 = (((*_39) as Vw).0: f32);
122+
StorageLive(_13);
123+
_40 = deref_copy (_4.1: &ViewportPercentageLength);
124+
_13 = (((*_40) as Vw).0: f32);
125125
StorageLive(_14);
126126
StorageLive(_15);
127127
_15 = _12;
@@ -132,18 +132,18 @@
132132
StorageDead(_15);
133133
_3 = ViewportPercentageLength::Vw(move _14);
134134
StorageDead(_14);
135-
StorageDead(_12);
136135
StorageDead(_13);
136+
StorageDead(_12);
137137
goto -> bb10;
138138
}
139139

140140
bb7: {
141-
StorageLive(_18);
142-
_41 = deref_copy (_4.1: &ViewportPercentageLength);
143-
_18 = (((*_41) as Vh).0: f32);
144141
StorageLive(_17);
145-
_42 = deref_copy (_4.0: &ViewportPercentageLength);
146-
_17 = (((*_42) as Vh).0: f32);
142+
_41 = deref_copy (_4.0: &ViewportPercentageLength);
143+
_17 = (((*_41) as Vh).0: f32);
144+
StorageLive(_18);
145+
_42 = deref_copy (_4.1: &ViewportPercentageLength);
146+
_18 = (((*_42) as Vh).0: f32);
147147
StorageLive(_19);
148148
StorageLive(_20);
149149
_20 = _17;
@@ -154,18 +154,18 @@
154154
StorageDead(_20);
155155
_3 = ViewportPercentageLength::Vh(move _19);
156156
StorageDead(_19);
157-
StorageDead(_17);
158157
StorageDead(_18);
158+
StorageDead(_17);
159159
goto -> bb10;
160160
}
161161

162162
bb8: {
163-
StorageLive(_23);
164-
_43 = deref_copy (_4.1: &ViewportPercentageLength);
165-
_23 = (((*_43) as Vmin).0: f32);
166163
StorageLive(_22);
167-
_44 = deref_copy (_4.0: &ViewportPercentageLength);
168-
_22 = (((*_44) as Vmin).0: f32);
164+
_43 = deref_copy (_4.0: &ViewportPercentageLength);
165+
_22 = (((*_43) as Vmin).0: f32);
166+
StorageLive(_23);
167+
_44 = deref_copy (_4.1: &ViewportPercentageLength);
168+
_23 = (((*_44) as Vmin).0: f32);
169169
StorageLive(_24);
170170
StorageLive(_25);
171171
_25 = _22;
@@ -176,18 +176,18 @@
176176
StorageDead(_25);
177177
_3 = ViewportPercentageLength::Vmin(move _24);
178178
StorageDead(_24);
179-
StorageDead(_22);
180179
StorageDead(_23);
180+
StorageDead(_22);
181181
goto -> bb10;
182182
}
183183

184184
bb9: {
185-
StorageLive(_28);
186-
_45 = deref_copy (_4.1: &ViewportPercentageLength);
187-
_28 = (((*_45) as Vmax).0: f32);
188185
StorageLive(_27);
189-
_46 = deref_copy (_4.0: &ViewportPercentageLength);
190-
_27 = (((*_46) as Vmax).0: f32);
186+
_45 = deref_copy (_4.0: &ViewportPercentageLength);
187+
_27 = (((*_45) as Vmax).0: f32);
188+
StorageLive(_28);
189+
_46 = deref_copy (_4.1: &ViewportPercentageLength);
190+
_28 = (((*_46) as Vmax).0: f32);
191191
StorageLive(_29);
192192
StorageLive(_30);
193193
_30 = _27;
@@ -198,8 +198,8 @@
198198
StorageDead(_30);
199199
_3 = ViewportPercentageLength::Vmax(move _29);
200200
StorageDead(_29);
201-
StorageDead(_27);
202201
StorageDead(_28);
202+
StorageDead(_27);
203203
goto -> bb10;
204204
}
205205

tests/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff

+3-3
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,13 @@
5959
}
6060

6161
bb5: {
62-
StorageLive(_10);
63-
_10 = (((_3.1: std::option::Option<u32>) as Some).0: u32);
6462
StorageLive(_9);
6563
_9 = (((_3.0: std::option::Option<u32>) as Some).0: u32);
64+
StorageLive(_10);
65+
_10 = (((_3.1: std::option::Option<u32>) as Some).0: u32);
6666
_0 = const 0_u32;
67-
StorageDead(_9);
6867
StorageDead(_10);
68+
StorageDead(_9);
6969
goto -> bb8;
7070
}
7171

tests/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir

+4-4
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ fn match_tuple(_1: (u32, bool, Option<i32>, u32)) -> u32 {
1919

2020
bb0: {
2121
PlaceMention(_1);
22-
_2 = discriminant((_1.2: std::option::Option<i32>));
23-
switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1];
22+
switchInt((_1.0: u32)) -> [1: bb2, 4: bb2, otherwise: bb1];
2423
}
2524

2625
bb1: {
@@ -29,11 +28,12 @@ fn match_tuple(_1: (u32, bool, Option<i32>, u32)) -> u32 {
2928
}
3029

3130
bb2: {
32-
switchInt((((_1.2: std::option::Option<i32>) as Some).0: i32)) -> [1: bb3, 8: bb3, otherwise: bb1];
31+
_2 = discriminant((_1.2: std::option::Option<i32>));
32+
switchInt(move _2) -> [0: bb4, 1: bb3, otherwise: bb1];
3333
}
3434

3535
bb3: {
36-
switchInt((_1.0: u32)) -> [1: bb4, 4: bb4, otherwise: bb1];
36+
switchInt((((_1.2: std::option::Option<i32>) as Some).0: i32)) -> [1: bb4, 8: bb4, otherwise: bb1];
3737
}
3838

3939
bb4: {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//@ known-bug: unknown
2+
#![allow(unused)]
3+
4+
struct A(u32);
5+
6+
pub fn main() {
7+
// The or-pattern bindings are lowered after `x`, which triggers the error.
8+
let x @ (A(a) | A(a)) = A(10);
9+
// ERROR: use of moved value
10+
assert!(x.0 == 10);
11+
assert!(a == 10);
12+
13+
// This works.
14+
let (x @ A(a) | x @ A(a)) = A(10);
15+
assert!(x.0 == 10);
16+
assert!(a == 10);
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
error[E0382]: use of moved value
2+
--> $DIR/bind-by-copy-or-pat.rs:8:16
3+
|
4+
LL | let x @ (A(a) | A(a)) = A(10);
5+
| - ^ ----- move occurs because value has type `A`, which does not implement the `Copy` trait
6+
| | |
7+
| | value used here after move
8+
| value moved here
9+
|
10+
help: borrow this binding in the pattern to avoid moving the value
11+
|
12+
LL | let ref x @ (A(a) | A(a)) = A(10);
13+
| +++
14+
15+
error[E0382]: use of moved value
16+
--> $DIR/bind-by-copy-or-pat.rs:8:23
17+
|
18+
LL | let x @ (A(a) | A(a)) = A(10);
19+
| - ^ ----- move occurs because value has type `A`, which does not implement the `Copy` trait
20+
| | |
21+
| | value used here after move
22+
| value moved here
23+
|
24+
help: borrow this binding in the pattern to avoid moving the value
25+
|
26+
LL | let ref x @ (A(a) | A(a)) = A(10);
27+
| +++
28+
29+
error: aborting due to 2 previous errors
30+
31+
For more information about this error, try `rustc --explain E0382`.

0 commit comments

Comments
 (0)