Skip to content

Commit 6a7753e

Browse files
authored
Rollup merge of rust-lang#78638 - vn-ki:bindigs-after-at-issue-69971, r=oli-obk
reverse binding order in matches to allow the subbinding of copyable fields in bindings after @ Fixes rust-lang#69971 ### TODO - [x] Regression tests r? `@oli-obk`
2 parents d159121 + 5827fba commit 6a7753e

22 files changed

+568
-595
lines changed

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

+44
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,36 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
4444
candidate: &mut Candidate<'pat, 'tcx>,
4545
) -> bool {
4646
// repeatedly simplify match pairs until fixed point is reached
47+
debug!(?candidate, "simplify_candidate");
48+
49+
// existing_bindings and new_bindings exists to keep the semantics in order.
50+
// Reversing the binding order for bindings after `@` changes the binding order in places
51+
// it shouldn't be changed, for example `let (Some(a), Some(b)) = (x, y)`
52+
//
53+
// To avoid this, the binding occurs in the following manner:
54+
// * the bindings for one iteration of the following loop occurs in order (i.e. left to
55+
// right)
56+
// * the bindings from the previous iteration of the loop is prepended to the bindings from
57+
// the current iteration (in the implementation this is done by mem::swap and extend)
58+
// * after all iterations, these new bindings are then appended to the bindings that were
59+
// prexisting (i.e. `candidate.binding` when the function was called).
60+
//
61+
// example:
62+
// candidate.bindings = [1, 2, 3]
63+
// binding in iter 1: [4, 5]
64+
// binding in iter 2: [6, 7]
65+
//
66+
// final binding: [1, 2, 3, 6, 7, 4, 5]
67+
let mut existing_bindings = mem::take(&mut candidate.bindings);
68+
let mut new_bindings = Vec::new();
4769
loop {
4870
let match_pairs = mem::take(&mut candidate.match_pairs);
4971

5072
if let [MatchPair { pattern: Pat { kind: box PatKind::Or { pats }, .. }, place }] =
5173
*match_pairs
5274
{
75+
existing_bindings.extend_from_slice(&new_bindings);
76+
mem::swap(&mut candidate.bindings, &mut existing_bindings);
5377
candidate.subcandidates = self.create_or_subcandidates(candidate, place, pats);
5478
return true;
5579
}
@@ -65,13 +89,33 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
6589
}
6690
}
6791
}
92+
// Avoid issue #69971: the binding order should be right to left if there are more
93+
// bindings after `@` to please the borrow checker
94+
// Ex
95+
// struct NonCopyStruct {
96+
// copy_field: u32,
97+
// }
98+
//
99+
// fn foo1(x: NonCopyStruct) {
100+
// let y @ NonCopyStruct { copy_field: z } = x;
101+
// // the above should turn into
102+
// let z = x.copy_field;
103+
// let y = x;
104+
// }
105+
candidate.bindings.extend_from_slice(&new_bindings);
106+
mem::swap(&mut candidate.bindings, &mut new_bindings);
107+
candidate.bindings.clear();
108+
68109
if !changed {
110+
existing_bindings.extend_from_slice(&new_bindings);
111+
mem::swap(&mut candidate.bindings, &mut existing_bindings);
69112
// Move or-patterns to the end, because they can result in us
70113
// creating additional candidates, so we want to test them as
71114
// late as possible.
72115
candidate
73116
.match_pairs
74117
.sort_by_key(|pair| matches!(*pair.pattern.kind, PatKind::Or { .. }));
118+
debug!(simplified = ?candidate, "simplify_candidate");
75119
return false; // if we were not able to simplify any, done.
76120
}
77121
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// run-pass
2+
3+
// Test copy
4+
5+
#![feature(bindings_after_at)]
6+
7+
struct A { a: i32, b: i32 }
8+
struct B { a: i32, b: C }
9+
struct D { a: i32, d: C }
10+
#[derive(Copy,Clone)]
11+
struct C { c: i32 }
12+
13+
pub fn main() {
14+
match (A {a: 10, b: 20}) {
15+
x@A {a, b: 20} => { assert!(x.a == 10); assert!(a == 10); }
16+
A {b: _b, ..} => { panic!(); }
17+
}
18+
19+
let mut x@B {b, ..} = B {a: 10, b: C {c: 20}};
20+
assert_eq!(x.a, 10);
21+
x.b.c = 30;
22+
assert_eq!(b.c, 20);
23+
let mut y@D {d, ..} = D {a: 10, d: C {c: 20}};
24+
assert_eq!(y.a, 10);
25+
y.d.c = 30;
26+
assert_eq!(d.c, 20);
27+
28+
let some_b = Some(B { a: 10, b: C { c: 20 } });
29+
30+
// in irrefutable pattern
31+
if let Some(x @ B { b, .. }) = some_b {
32+
assert_eq!(x.b.c, 20);
33+
assert_eq!(b.c, 20);
34+
} else {
35+
unreachable!();
36+
}
37+
38+
let some_b = Some(B { a: 10, b: C { c: 20 } });
39+
40+
if let Some(x @ B { b: mut b @ C { c }, .. }) = some_b {
41+
assert_eq!(x.b.c, 20);
42+
assert_eq!(b.c, 20);
43+
b.c = 30;
44+
assert_eq!(b.c, 30);
45+
assert_eq!(c, 20);
46+
} else {
47+
unreachable!();
48+
}
49+
}

src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,28 @@ fn main() {
1212
let x = Some(X { x: () });
1313
match x {
1414
Some(ref _y @ _z) => {} //~ ERROR cannot move out of value because it is borrowed
15+
//~| ERROR borrow of moved value
1516
None => panic!(),
1617
}
1718

1819
let x = Some(X { x: () });
1920
match x {
2021
Some(_z @ ref _y) => {}
2122
//~^ ERROR borrow of moved value
22-
//~| ERROR borrow of moved value
2323
None => panic!(),
2424
}
2525

2626
let mut x = Some(X { x: () });
2727
match x {
2828
Some(ref mut _y @ _z) => {} //~ ERROR cannot move out of value because it is borrowed
29+
//~| ERROR borrow of moved value
2930
None => panic!(),
3031
}
3132

3233
let mut x = Some(X { x: () });
3334
match x {
3435
Some(_z @ ref mut _y) => {}
3536
//~^ ERROR borrow of moved value
36-
//~| ERROR borrow of moved value
3737
None => panic!(),
3838
}
3939
}

src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr

+18-18
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ LL | Some(ref _y @ _z) => {}
88
| value borrowed, by `_y`, here
99

1010
error: borrow of moved value
11-
--> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:20:14
11+
--> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:21:14
1212
|
1313
LL | Some(_z @ ref _y) => {}
1414
| --^^^------
@@ -27,7 +27,7 @@ LL | Some(ref mut _y @ _z) => {}
2727
| value borrowed, by `_y`, here
2828

2929
error: borrow of moved value
30-
--> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:34:14
30+
--> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:35:14
3131
|
3232
LL | Some(_z @ ref mut _y) => {}
3333
| --^^^----------
@@ -37,34 +37,34 @@ LL | Some(_z @ ref mut _y) => {}
3737
| move occurs because `_z` has type `X` which does not implement the `Copy` trait
3838

3939
error[E0382]: borrow of moved value
40-
--> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:20:19
40+
--> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:14:14
4141
|
42-
LL | Some(_z @ ref _y) => {}
43-
| -----^^^^^^
44-
| | |
45-
| | value borrowed here after move
46-
| value moved here
42+
LL | Some(ref _y @ _z) => {}
43+
| ^^^^^^^^^--
44+
| | |
45+
| | value moved here
46+
| value borrowed here after move
4747
|
4848
= note: move occurs because value has type `X`, which does not implement the `Copy` trait
4949
help: borrow this field in the pattern to avoid moving `x.0`
5050
|
51-
LL | Some(ref _z @ ref _y) => {}
52-
| ^^^
51+
LL | Some(ref _y @ ref _z) => {}
52+
| ^^^
5353

5454
error[E0382]: borrow of moved value
55-
--> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:34:19
55+
--> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:28:14
5656
|
57-
LL | Some(_z @ ref mut _y) => {}
58-
| -----^^^^^^^^^^
59-
| | |
60-
| | value borrowed here after move
61-
| value moved here
57+
LL | Some(ref mut _y @ _z) => {}
58+
| ^^^^^^^^^^^^^--
59+
| | |
60+
| | value moved here
61+
| value borrowed here after move
6262
|
6363
= note: move occurs because value has type `X`, which does not implement the `Copy` trait
6464
help: borrow this field in the pattern to avoid moving `x.0`
6565
|
66-
LL | Some(ref _z @ ref mut _y) => {}
67-
| ^^^
66+
LL | Some(ref mut _y @ ref _z) => {}
67+
| ^^^
6868

6969
error: aborting due to 6 previous errors
7070

src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ fn main() {}
77
struct A(Box<u8>);
88

99
fn f(a @ A(u): A) -> Box<u8> {
10-
//~^ ERROR use of moved value
10+
//~^ ERROR use of partially moved value
1111
drop(a);
1212
u
1313
}

src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
error[E0382]: use of moved value
2-
--> $DIR/bind-by-move-no-subbindings-fun-param.rs:9:12
1+
error[E0382]: use of partially moved value
2+
--> $DIR/bind-by-move-no-subbindings-fun-param.rs:9:6
33
|
44
LL | fn f(a @ A(u): A) -> Box<u8> {
5-
| ------^-
5+
| ^^^^^^-^
66
| | |
7-
| | value used here after move
8-
| value moved here
9-
| move occurs because value has type `A`, which does not implement the `Copy` trait
7+
| | value partially moved here
8+
| value used here after partial move
9+
|
10+
= note: partial move occurs because value has type `Box<u8>`, which does not implement the `Copy` trait
1011

1112
error: aborting due to previous error
1213

src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ fn main() {
1212

1313
let a @ b = U; //~ ERROR use of moved value
1414

15-
let a @ (b, c) = (U, U); //~ ERROR use of moved value
15+
let a @ (b, c) = (U, U); //~ ERROR use of partially moved value
1616

17-
let a @ (b, c) = (u(), u()); //~ ERROR use of moved value
17+
let a @ (b, c) = (u(), u()); //~ ERROR use of partially moved value
1818

1919
match Ok(U) {
2020
a @ Ok(b) | a @ Err(b) => {} //~ ERROR use of moved value
@@ -24,10 +24,10 @@ fn main() {
2424
fn fun(a @ b: U) {} //~ ERROR use of moved value
2525

2626
match [u(), u(), u(), u()] {
27-
xs @ [a, .., b] => {} //~ ERROR use of moved value
27+
xs @ [a, .., b] => {} //~ ERROR use of partially moved value
2828
}
2929

3030
match [u(), u(), u(), u()] {
31-
xs @ [_, ys @ .., _] => {} //~ ERROR use of moved value
31+
xs @ [_, ys @ .., _] => {} //~ ERROR use of partially moved value
3232
}
3333
}

src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr

+36-32
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,33 @@
11
error[E0382]: use of moved value
2-
--> $DIR/borrowck-move-and-move.rs:13:13
2+
--> $DIR/borrowck-move-and-move.rs:13:9
33
|
44
LL | let a @ b = U;
5-
| ----^ - move occurs because value has type `U`, which does not implement the `Copy` trait
5+
| ^^^^- - move occurs because value has type `U`, which does not implement the `Copy` trait
66
| | |
7-
| | value used here after move
8-
| value moved here
7+
| | value moved here
8+
| value used here after move
99

10-
error[E0382]: use of moved value
11-
--> $DIR/borrowck-move-and-move.rs:15:17
10+
error[E0382]: use of partially moved value
11+
--> $DIR/borrowck-move-and-move.rs:15:9
1212
|
1313
LL | let a @ (b, c) = (U, U);
14-
| --------^- ------ move occurs because value has type `(U, U)`, which does not implement the `Copy` trait
14+
| ^^^^^^^^-^
1515
| | |
16-
| | value used here after move
17-
| value moved here
16+
| | value partially moved here
17+
| value used here after partial move
18+
|
19+
= note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
1820

19-
error[E0382]: use of moved value
20-
--> $DIR/borrowck-move-and-move.rs:17:17
21+
error[E0382]: use of partially moved value
22+
--> $DIR/borrowck-move-and-move.rs:17:9
2123
|
2224
LL | let a @ (b, c) = (u(), u());
23-
| --------^- ---------- move occurs because value has type `(U, U)`, which does not implement the `Copy` trait
25+
| ^^^^^^^^-^
2426
| | |
25-
| | value used here after move
26-
| value moved here
27+
| | value partially moved here
28+
| value used here after partial move
29+
|
30+
= note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
2731

2832
error[E0382]: use of moved value
2933
--> $DIR/borrowck-move-and-move.rs:20:16
@@ -47,36 +51,36 @@ LL | a @ Ok(b) | a @ Err(b) => {}
4751
| | value used here after move
4852
| value moved here
4953

50-
error[E0382]: use of moved value
51-
--> $DIR/borrowck-move-and-move.rs:27:22
54+
error[E0382]: use of partially moved value
55+
--> $DIR/borrowck-move-and-move.rs:27:9
5256
|
53-
LL | match [u(), u(), u(), u()] {
54-
| -------------------- move occurs because value has type `[U; 4]`, which does not implement the `Copy` trait
5557
LL | xs @ [a, .., b] => {}
56-
| -------------^-
58+
| ^^^^^^^^^^^^^-^
5759
| | |
58-
| | value used here after move
59-
| value moved here
60+
| | value partially moved here
61+
| value used here after partial move
62+
|
63+
= note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
6064

61-
error[E0382]: use of moved value
62-
--> $DIR/borrowck-move-and-move.rs:31:18
65+
error[E0382]: use of partially moved value
66+
--> $DIR/borrowck-move-and-move.rs:31:9
6367
|
64-
LL | match [u(), u(), u(), u()] {
65-
| -------------------- move occurs because value has type `[U; 4]`, which does not implement the `Copy` trait
6668
LL | xs @ [_, ys @ .., _] => {}
67-
| ---------^^^^^^^----
69+
| ^^^^^^^^^-------^^^^
6870
| | |
69-
| | value used here after move
70-
| value moved here
71+
| | value partially moved here
72+
| value used here after partial move
73+
|
74+
= note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
7175

7276
error[E0382]: use of moved value
73-
--> $DIR/borrowck-move-and-move.rs:24:16
77+
--> $DIR/borrowck-move-and-move.rs:24:12
7478
|
7579
LL | fn fun(a @ b: U) {}
76-
| ----^
80+
| ^^^^-
7781
| | |
78-
| | value used here after move
79-
| value moved here
82+
| | value moved here
83+
| value used here after move
8084
| move occurs because value has type `U`, which does not implement the `Copy` trait
8185

8286
error: aborting due to 8 previous errors

0 commit comments

Comments
 (0)