From 3ea464f36aa8e5bcc0367891e4a77ce5d643ea3a Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 21 Jan 2024 23:58:40 +0100 Subject: [PATCH 1/5] Add tests --- .../pattern/bindings-after-at/bind-by-copy.rs | 47 ++++++++++++++++--- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/tests/ui/pattern/bindings-after-at/bind-by-copy.rs b/tests/ui/pattern/bindings-after-at/bind-by-copy.rs index 2b349f0ed5f99..08e1d55f77335 100644 --- a/tests/ui/pattern/bindings-after-at/bind-by-copy.rs +++ b/tests/ui/pattern/bindings-after-at/bind-by-copy.rs @@ -1,13 +1,29 @@ -// run-pass +#![allow(unused)] // Test copy -struct A { a: i32, b: i32 } -struct B { a: i32, b: C } -struct D { a: i32, d: C } -#[derive(Copy,Clone)] -struct C { c: i32 } +struct A { + a: i32, + b: i32, +} +struct B { + a: i32, + b: C, +} +struct D { + a: i32, + d: C, +} +#[derive(Copy, Clone)] +struct C { + c: i32, +} +enum E { + E { a: i32, e: C }, + NotE, +} +#[rustfmt::skip] pub fn main() { match (A {a: 10, b: 20}) { x@A {a, b: 20} => { assert!(x.a == 10); assert!(a == 10); } @@ -23,6 +39,25 @@ pub fn main() { y.d.c = 30; assert_eq!(d.c, 20); + match (E::E { a: 10, e: C { c: 20 } }) { + x @ E::E{ a, e: C { c } } => { + //~^ ERROR use of moved value + assert!(matches!(x, E::E { a: 10, e: C { c: 20 } })); + assert!(a == 10); + assert!(c == 20); + } + _ => panic!(), + } + match (E::E { a: 10, e: C { c: 20 } }) { + mut x @ E::E{ a, e: C { mut c } } => { + //~^ ERROR use of moved value + x = E::NotE; + c += 30; + assert_eq!(c, 50); + } + _ => panic!(), + } + let some_b = Some(B { a: 10, b: C { c: 20 } }); // in irrefutable pattern From 96ff1a4538646b1a431914a285de43f744b3489d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 21 Jan 2024 21:52:58 +0100 Subject: [PATCH 2/5] Move `Or` test out of the loop --- .../src/build/matches/simplify.rs | 48 ++++++++++--------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index a7f6f4873e383..c2e44a06321da 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -62,19 +62,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut existing_bindings = mem::take(&mut candidate.bindings); let mut new_bindings = Vec::new(); loop { - let match_pairs = mem::take(&mut candidate.match_pairs); - - if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place }] = - &*match_pairs - { - existing_bindings.extend_from_slice(&new_bindings); - mem::swap(&mut candidate.bindings, &mut existing_bindings); - candidate.subcandidates = self.create_or_subcandidates(candidate, place, pats); - return true; - } - let mut changed = false; - for match_pair in match_pairs { + for match_pair in mem::take(&mut candidate.match_pairs) { match self.simplify_match_pair(match_pair, candidate) { Ok(()) => { changed = true; @@ -84,6 +73,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } } + // Avoid issue #69971: the binding order should be right to left if there are more // bindings after `@` to please the borrow checker // Ex @@ -102,18 +92,32 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidate.bindings.clear(); if !changed { - existing_bindings.extend_from_slice(&new_bindings); - mem::swap(&mut candidate.bindings, &mut existing_bindings); - // Move or-patterns to the end, because they can result in us - // creating additional candidates, so we want to test them as - // late as possible. - candidate - .match_pairs - .sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. })); - debug!(simplified = ?candidate, "simplify_candidate"); - return false; // if we were not able to simplify any, done. + // If we were not able to simplify anymore, done. + break; } } + + existing_bindings.extend_from_slice(&new_bindings); + mem::swap(&mut candidate.bindings, &mut existing_bindings); + + let did_expand_or = + if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place }] = + &*candidate.match_pairs + { + candidate.subcandidates = self.create_or_subcandidates(candidate, place, pats); + candidate.match_pairs.clear(); + true + } else { + false + }; + + // Move or-patterns to the end, because they can result in us + // creating additional candidates, so we want to test them as + // late as possible. + candidate.match_pairs.sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. })); + debug!(simplified = ?candidate, "simplify_candidate"); + + did_expand_or } /// Given `candidate` that has a single or-pattern for its match-pairs, From e9028789084b2d9ebb6fbadf54527daf78598510 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 21 Jan 2024 22:06:13 +0100 Subject: [PATCH 3/5] Clarify the binding dance --- .../src/build/matches/simplify.rs | 63 ++++++++++++------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index c2e44a06321da..8563c2d6dfbb7 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -38,16 +38,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, candidate: &mut Candidate<'pat, 'tcx>, ) -> bool { - // repeatedly simplify match pairs until fixed point is reached debug!("{candidate:#?}"); - - // existing_bindings and new_bindings exists to keep the semantics in order. + // `original_bindings` and `new_bindings` exist to keep the semantics in order. // Reversing the binding order for bindings after `@` changes the binding order in places - // it shouldn't be changed, for example `let (Some(a), Some(b)) = (x, y)` + // where it shouldn't be changed, for example `let (Some(a), Some(b)) = (x, y)`. // // To avoid this, the binding occurs in the following manner: - // * the bindings for one iteration of the following loop occurs in order (i.e. left to - // right) + // * the bindings for one iteration of the loop occurs in order (i.e. left to right) // * the bindings from the previous iteration of the loop is prepended to the bindings from // the current iteration (in the implementation this is done by mem::swap and extend) // * after all iterations, these new bindings are then appended to the bindings that were @@ -59,8 +56,40 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // binding in iter 2: [6, 7] // // final binding: [1, 2, 3, 6, 7, 4, 5] - let mut existing_bindings = mem::take(&mut candidate.bindings); + // + // This is because we treat refutable and irrefutable bindings differently. The binding + // order should be right-to-left if there are more _irrefutable_ bindings after `@` to + // please the borrow checker (#69971) + // Ex + // struct NonCopyStruct { + // copy_field: u32, + // } + // + // fn foo1(x: NonCopyStruct) { + // let y @ NonCopyStruct { copy_field: z } = x; + // // the above should turn into + // let z = x.copy_field; + // let y = x; + // } + // + // If however the bindings are refutable, i.e. under a test, then we keep the bindings + // left-to-right. + // Ex + // enum NonCopyEnum { + // Variant { copy_field: u32 }, + // None, + // } + // + // fn foo2(x: NonCopyEnum) { + // let y @ NonCopyEnum::Variant { copy_field: z } = x else { return }; + // // turns into + // let y = x; + // let z = (x as Variant).copy_field; + // // and raises an error + // } + let mut original_bindings = mem::take(&mut candidate.bindings); let mut new_bindings = Vec::new(); + // Repeatedly simplify match pairs until fixed point is reached loop { let mut changed = false; for match_pair in mem::take(&mut candidate.match_pairs) { @@ -74,19 +103,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - // Avoid issue #69971: the binding order should be right to left if there are more - // bindings after `@` to please the borrow checker - // Ex - // struct NonCopyStruct { - // copy_field: u32, - // } - // - // fn foo1(x: NonCopyStruct) { - // let y @ NonCopyStruct { copy_field: z } = x; - // // the above should turn into - // let z = x.copy_field; - // let y = x; - // } + // This does: new_bindings = candidate.bindings.take() ++ new_bindings candidate.bindings.extend_from_slice(&new_bindings); mem::swap(&mut candidate.bindings, &mut new_bindings); candidate.bindings.clear(); @@ -97,8 +114,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - existing_bindings.extend_from_slice(&new_bindings); - mem::swap(&mut candidate.bindings, &mut existing_bindings); + // Restore original bindings and append the new ones. + // This does: candidate.bindings = original_bindings ++ new_bindings + mem::swap(&mut candidate.bindings, &mut original_bindings); + candidate.bindings.extend_from_slice(&new_bindings); let did_expand_or = if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place }] = From 09d4613f20a6052bb8af7119b90cf64e288deda0 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 21 Jan 2024 23:36:33 +0100 Subject: [PATCH 4/5] Put new bindings first in refutable cases too --- .../src/build/matches/simplify.rs | 8 +- ...wise_branch.opt1.EarlyOtherwiseBranch.diff | 6 +- ...wise_branch.opt2.EarlyOtherwiseBranch.diff | 6 +- ...wise_branch.opt3.EarlyOtherwiseBranch.diff | 6 +- ...ement_tuple.opt1.EarlyOtherwiseBranch.diff | 12 +-- ...ch_68867.try_sum.EarlyOtherwiseBranch.diff | 48 ++++----- ...nch_noopt.noopt1.EarlyOtherwiseBranch.diff | 6 +- .../pattern/bindings-after-at/bind-by-copy.rs | 3 +- .../borrowck-move-and-move.rs | 4 +- .../borrowck-move-and-move.stderr | 30 +++--- .../borrowck-pat-by-move-and-ref-inverse.rs | 7 +- ...orrowck-pat-by-move-and-ref-inverse.stderr | 75 ++++--------- .../borrowck-pat-by-move-and-ref.rs | 3 + .../borrowck-pat-by-move-and-ref.stderr | 58 ++++++++-- .../borrowck-pat-ref-mut-and-ref.rs | 10 +- .../borrowck-pat-ref-mut-and-ref.stderr | 102 ++++++++++++------ .../borrowck-pat-ref-mut-twice.rs | 6 +- .../borrowck-pat-ref-mut-twice.stderr | 48 +++------ 18 files changed, 229 insertions(+), 209 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 8563c2d6dfbb7..9fab61803e887 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -87,7 +87,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // let z = (x as Variant).copy_field; // // and raises an error // } - let mut original_bindings = mem::take(&mut candidate.bindings); + let original_bindings = mem::take(&mut candidate.bindings); let mut new_bindings = Vec::new(); // Repeatedly simplify match pairs until fixed point is reached loop { @@ -115,9 +115,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } // Restore original bindings and append the new ones. - // This does: candidate.bindings = original_bindings ++ new_bindings - mem::swap(&mut candidate.bindings, &mut original_bindings); - candidate.bindings.extend_from_slice(&new_bindings); + // This does: candidate.bindings = new_bindings ++ original_bindings + mem::swap(&mut candidate.bindings, &mut new_bindings); + candidate.bindings.extend_from_slice(&original_bindings); let did_expand_or = if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place }] = diff --git a/tests/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff index 7a374c5675ab9..8b427cff67780 100644 --- a/tests/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff @@ -51,13 +51,13 @@ - } - - bb3: { - StorageLive(_8); - _8 = (((_3.0: std::option::Option) as Some).0: u32); StorageLive(_9); _9 = (((_3.1: std::option::Option) as Some).0: u32); + StorageLive(_8); + _8 = (((_3.0: std::option::Option) as Some).0: u32); _0 = const 0_u32; - StorageDead(_9); StorageDead(_8); + StorageDead(_9); - goto -> bb4; + goto -> bb3; } diff --git a/tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff index 21f58a14a2b3f..b91a469225cd2 100644 --- a/tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff @@ -58,13 +58,13 @@ - - bb4: { + bb2: { - StorageLive(_9); - _9 = (((_3.0: std::option::Option) as Some).0: u32); StorageLive(_10); _10 = (((_3.1: std::option::Option) as Some).0: u32); + StorageLive(_9); + _9 = (((_3.0: std::option::Option) as Some).0: u32); _0 = const 0_u32; - StorageDead(_10); StorageDead(_9); + StorageDead(_10); - goto -> bb6; + goto -> bb4; } diff --git a/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff index e058c409cb596..cc16af721ca69 100644 --- a/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff @@ -51,13 +51,13 @@ - } - - bb3: { - StorageLive(_8); - _8 = (((_3.0: std::option::Option) as Some).0: u32); StorageLive(_9); _9 = (((_3.1: std::option::Option) as Some).0: bool); + StorageLive(_8); + _8 = (((_3.0: std::option::Option) as Some).0: u32); _0 = const 0_u32; - StorageDead(_9); StorageDead(_8); + StorageDead(_9); - goto -> bb4; + goto -> bb3; } diff --git a/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff index f98d68e6ffce3..eb8926d27ee87 100644 --- a/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff @@ -69,16 +69,16 @@ - bb4: { + bb3: { - StorageLive(_11); - _11 = (((_4.0: std::option::Option) as Some).0: u32); - StorageLive(_12); - _12 = (((_4.1: std::option::Option) as Some).0: u32); StorageLive(_13); _13 = (((_4.2: std::option::Option) as Some).0: u32); + StorageLive(_12); + _12 = (((_4.1: std::option::Option) as Some).0: u32); + StorageLive(_11); + _11 = (((_4.0: std::option::Option) as Some).0: u32); _0 = const 0_u32; - StorageDead(_13); - StorageDead(_12); StorageDead(_11); + StorageDead(_12); + StorageDead(_13); - goto -> bb5; + goto -> bb4; } diff --git a/tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff index 0c94794fa3ffe..79cf1c0e34ad5 100644 --- a/tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff @@ -116,12 +116,12 @@ } bb6: { - StorageLive(_12); - _39 = deref_copy (_4.0: &ViewportPercentageLength); - _12 = (((*_39) as Vw).0: f32); StorageLive(_13); - _40 = deref_copy (_4.1: &ViewportPercentageLength); - _13 = (((*_40) as Vw).0: f32); + _39 = deref_copy (_4.1: &ViewportPercentageLength); + _13 = (((*_39) as Vw).0: f32); + StorageLive(_12); + _40 = deref_copy (_4.0: &ViewportPercentageLength); + _12 = (((*_40) as Vw).0: f32); StorageLive(_14); StorageLive(_15); _15 = _12; @@ -132,18 +132,18 @@ StorageDead(_15); _3 = ViewportPercentageLength::Vw(move _14); StorageDead(_14); - StorageDead(_13); StorageDead(_12); + StorageDead(_13); goto -> bb10; } bb7: { - StorageLive(_17); - _41 = deref_copy (_4.0: &ViewportPercentageLength); - _17 = (((*_41) as Vh).0: f32); StorageLive(_18); - _42 = deref_copy (_4.1: &ViewportPercentageLength); - _18 = (((*_42) as Vh).0: f32); + _41 = deref_copy (_4.1: &ViewportPercentageLength); + _18 = (((*_41) as Vh).0: f32); + StorageLive(_17); + _42 = deref_copy (_4.0: &ViewportPercentageLength); + _17 = (((*_42) as Vh).0: f32); StorageLive(_19); StorageLive(_20); _20 = _17; @@ -154,18 +154,18 @@ StorageDead(_20); _3 = ViewportPercentageLength::Vh(move _19); StorageDead(_19); - StorageDead(_18); StorageDead(_17); + StorageDead(_18); goto -> bb10; } bb8: { - StorageLive(_22); - _43 = deref_copy (_4.0: &ViewportPercentageLength); - _22 = (((*_43) as Vmin).0: f32); StorageLive(_23); - _44 = deref_copy (_4.1: &ViewportPercentageLength); - _23 = (((*_44) as Vmin).0: f32); + _43 = deref_copy (_4.1: &ViewportPercentageLength); + _23 = (((*_43) as Vmin).0: f32); + StorageLive(_22); + _44 = deref_copy (_4.0: &ViewportPercentageLength); + _22 = (((*_44) as Vmin).0: f32); StorageLive(_24); StorageLive(_25); _25 = _22; @@ -176,18 +176,18 @@ StorageDead(_25); _3 = ViewportPercentageLength::Vmin(move _24); StorageDead(_24); - StorageDead(_23); StorageDead(_22); + StorageDead(_23); goto -> bb10; } bb9: { - StorageLive(_27); - _45 = deref_copy (_4.0: &ViewportPercentageLength); - _27 = (((*_45) as Vmax).0: f32); StorageLive(_28); - _46 = deref_copy (_4.1: &ViewportPercentageLength); - _28 = (((*_46) as Vmax).0: f32); + _45 = deref_copy (_4.1: &ViewportPercentageLength); + _28 = (((*_45) as Vmax).0: f32); + StorageLive(_27); + _46 = deref_copy (_4.0: &ViewportPercentageLength); + _27 = (((*_46) as Vmax).0: f32); StorageLive(_29); StorageLive(_30); _30 = _27; @@ -198,8 +198,8 @@ StorageDead(_30); _3 = ViewportPercentageLength::Vmax(move _29); StorageDead(_29); - StorageDead(_28); StorageDead(_27); + StorageDead(_28); goto -> bb10; } diff --git a/tests/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff index 09cdce718572e..af0337d0a7e71 100644 --- a/tests/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff @@ -59,13 +59,13 @@ } bb5: { - StorageLive(_9); - _9 = (((_3.0: std::option::Option) as Some).0: u32); StorageLive(_10); _10 = (((_3.1: std::option::Option) as Some).0: u32); + StorageLive(_9); + _9 = (((_3.0: std::option::Option) as Some).0: u32); _0 = const 0_u32; - StorageDead(_10); StorageDead(_9); + StorageDead(_10); goto -> bb8; } diff --git a/tests/ui/pattern/bindings-after-at/bind-by-copy.rs b/tests/ui/pattern/bindings-after-at/bind-by-copy.rs index 08e1d55f77335..253b2d8890100 100644 --- a/tests/ui/pattern/bindings-after-at/bind-by-copy.rs +++ b/tests/ui/pattern/bindings-after-at/bind-by-copy.rs @@ -1,3 +1,4 @@ +// run-pass #![allow(unused)] // Test copy @@ -41,7 +42,6 @@ pub fn main() { match (E::E { a: 10, e: C { c: 20 } }) { x @ E::E{ a, e: C { c } } => { - //~^ ERROR use of moved value assert!(matches!(x, E::E { a: 10, e: C { c: 20 } })); assert!(a == 10); assert!(c == 20); @@ -50,7 +50,6 @@ pub fn main() { } match (E::E { a: 10, e: C { c: 20 } }) { mut x @ E::E{ a, e: C { mut c } } => { - //~^ ERROR use of moved value x = E::NotE; c += 30; assert_eq!(c, 50); diff --git a/tests/ui/pattern/bindings-after-at/borrowck-move-and-move.rs b/tests/ui/pattern/bindings-after-at/borrowck-move-and-move.rs index a61d682152407..bfb3c3b20d63c 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-move-and-move.rs +++ b/tests/ui/pattern/bindings-after-at/borrowck-move-and-move.rs @@ -15,8 +15,8 @@ fn main() { let a @ (b, c) = (u(), u()); //~ ERROR use of partially moved value match Ok(U) { - a @ Ok(b) | a @ Err(b) => {} //~ ERROR use of moved value - //~^ ERROR use of moved value + a @ Ok(b) | a @ Err(b) => {} //~ ERROR use of partially moved value + //~^ ERROR use of partially moved value } fn fun(a @ b: U) {} //~ ERROR use of moved value diff --git a/tests/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr b/tests/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr index 324897151124c..ba0622090bb7d 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr +++ b/tests/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr @@ -40,35 +40,33 @@ help: borrow this binding in the pattern to avoid moving the value LL | let ref a @ (b, ref c) = (u(), u()); | +++ +++ -error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:18:16 +error[E0382]: use of partially moved value + --> $DIR/borrowck-move-and-move.rs:18:9 | -LL | match Ok(U) { - | ----- move occurs because value has type `Result`, which does not implement the `Copy` trait LL | a @ Ok(b) | a @ Err(b) => {} - | - ^ value used here after move + | ^ - value partially moved here | | - | value moved here + | value used here after partial move | + = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait help: borrow this binding in the pattern to avoid moving the value | -LL | ref a @ Ok(b) | a @ Err(b) => {} - | +++ +LL | ref a @ Ok(ref b) | a @ Err(b) => {} + | +++ +++ -error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:18:29 +error[E0382]: use of partially moved value + --> $DIR/borrowck-move-and-move.rs:18:21 | -LL | match Ok(U) { - | ----- move occurs because value has type `Result`, which does not implement the `Copy` trait LL | a @ Ok(b) | a @ Err(b) => {} - | - ^ value used here after move + | ^ - value partially moved here | | - | value moved here + | value used here after partial move | + = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait help: borrow this binding in the pattern to avoid moving the value | -LL | a @ Ok(b) | ref a @ Err(b) => {} - | +++ +LL | a @ Ok(b) | ref a @ Err(ref b) => {} + | +++ +++ error[E0382]: use of partially moved value --> $DIR/borrowck-move-and-move.rs:25:9 diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs index 06dc6e1c4da1f..ac57838f0298f 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs @@ -48,19 +48,17 @@ fn main() { //~^ ERROR borrow of moved value //~| ERROR borrow of moved value //~| ERROR borrow of moved value - //~| ERROR use of moved value + //~| ERROR use of partially moved value None => {} } match Some([U, U]) { mut a @ Some([ref b, ref mut c]) => {} //~^ ERROR borrow of moved value - //~| ERROR borrow of moved value None => {} } match Some(u()) { a @ Some(ref b) => {} //~^ ERROR borrow of moved value - //~| ERROR borrow of moved value None => {} } match Some((u(), u())) { @@ -68,13 +66,12 @@ fn main() { //~^ ERROR borrow of moved value //~| ERROR borrow of moved value //~| ERROR borrow of moved value - //~| ERROR use of moved value + //~| ERROR use of partially moved value None => {} } match Some([u(), u()]) { mut a @ Some([ref b, ref mut c]) => {} //~^ ERROR borrow of moved value - //~| ERROR borrow of moved value None => {} } } diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr index 1ed019f0a6927..fd7a51388bc10 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr @@ -215,7 +215,7 @@ LL | ref mut a @ Some([ref b, ref mut c]) => {} | +++ error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:9 | LL | a @ Some(ref b) => {} | ^ ----- value borrowed here after move @@ -229,7 +229,7 @@ LL | ref a @ Some(ref b) => {} | +++ error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:65:9 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | ^ --------- ----- value borrowed here after move @@ -244,7 +244,7 @@ LL | ref a @ Some((mut b @ ref mut c, d @ ref e)) => {} | +++ error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:19 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:65:19 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | ^^^^^ --------- value borrowed here after move @@ -258,7 +258,7 @@ LL | a @ Some((ref mut b @ ref mut c, d @ ref e)) => {} | +++ error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:38 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:65:38 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | ^ ----- value borrowed here after move @@ -272,7 +272,7 @@ LL | a @ Some((mut b @ ref mut c, ref d @ ref e)) => {} | +++ error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:75:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:73:9 | LL | mut a @ Some([ref b, ref mut c]) => {} | ^^^^^ ----- --------- value borrowed here after move @@ -314,66 +314,33 @@ help: borrow this binding in the pattern to avoid moving the value LL | let ref a @ (mut b @ ref mut c, ref d @ ref e) = (u(), u()); | +++ +++ -error[E0382]: use of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:38 +error[E0382]: use of partially moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:9 | -LL | match Some((U, U)) { - | ------------ move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} - | - value moved here ^ value used here after move - | -help: borrow this binding in the pattern to avoid moving the value - | -LL | ref a @ Some((mut b @ ref mut c, d @ ref e)) => {} - | +++ - -error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:30 - | -LL | match Some([U, U]) { - | ------------ move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait -LL | mut a @ Some([ref b, ref mut c]) => {} - | ----- ^^^^^^^^^ value borrowed here after move - | | - | value moved here - -error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:18 - | -LL | match Some(u()) { - | --------- move occurs because value has type `Option`, which does not implement the `Copy` trait -LL | a @ Some(ref b) => {} - | - ^^^^^ value borrowed here after move + | ^ - value partially moved here | | - | value moved here + | value used here after partial move | + = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait help: borrow this binding in the pattern to avoid moving the value | -LL | ref a @ Some(ref b) => {} - | +++ +LL | ref a @ Some((mut b @ ref mut c, ref d @ ref e)) => {} + | +++ +++ -error[E0382]: use of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:38 +error[E0382]: use of partially moved value + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:65:9 | -LL | match Some((u(), u())) { - | ---------------- move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} - | - value moved here ^ value used here after move + | ^ - value partially moved here + | | + | value used here after partial move | + = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait help: borrow this binding in the pattern to avoid moving the value | -LL | ref a @ Some((mut b @ ref mut c, d @ ref e)) => {} - | +++ - -error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:75:30 - | -LL | match Some([u(), u()]) { - | ---------------- move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait -LL | mut a @ Some([ref b, ref mut c]) => {} - | ----- ^^^^^^^^^ value borrowed here after move - | | - | value moved here +LL | ref a @ Some((mut b @ ref mut c, ref d @ ref e)) => {} + | +++ +++ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:11:11 @@ -457,6 +424,6 @@ help: borrow this binding in the pattern to avoid moving the value LL | fn f3(ref a @ [ref mut b, ref c]: [U; 2]) {} | +++ -error: aborting due to 33 previous errors +error: aborting due to 30 previous errors For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs index 0b0a7801049fe..095c871e8d205 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs @@ -58,11 +58,13 @@ fn main() { match Some([U, U]) { ref mut a @ Some([b, mut c]) => {} //~^ ERROR cannot move out of value because it is borrowed + //~| ERROR borrow of partially moved value None => {} } match Some(u()) { ref a @ Some(b) => {} //~^ ERROR cannot move out of value because it is borrowed + //~| ERROR borrow of partially moved value None => {} } match Some((u(), u())) { @@ -77,6 +79,7 @@ fn main() { match Some([u(), u()]) { ref mut a @ Some([b, mut c]) => {} //~^ ERROR cannot move out of value because it is borrowed + //~| ERROR borrow of partially moved value None => {} } } diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr index c8c4d9b8fdb13..45ada8fd51606 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr @@ -125,7 +125,7 @@ LL | ref mut a @ Some([b, mut c]) => {} | value is mutably borrowed by `a` here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:64:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:65:9 | LL | ref a @ Some(b) => {} | ^^^^^ - value is moved into `b` here @@ -133,7 +133,7 @@ LL | ref a @ Some(b) => {} | value is borrowed by `a` here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:69:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:71:9 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | ^^^^^ ----- - value is moved into `e` here @@ -142,7 +142,7 @@ LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | value is borrowed by `a` here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:69:23 + --> $DIR/borrowck-pat-by-move-and-ref.rs:71:23 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | ^^^^^ ----- value is moved into `c` here @@ -150,7 +150,7 @@ LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | value is borrowed by `b` here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:69:38 + --> $DIR/borrowck-pat-by-move-and-ref.rs:71:38 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | ^^^^^ - value is moved into `e` here @@ -158,7 +158,7 @@ LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | value is borrowed by `d` here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:78:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:80:9 | LL | ref mut a @ Some([b, mut c]) => {} | ^^^^^^^^^ - ----- value is moved into `c` here @@ -236,8 +236,36 @@ help: borrow this binding in the pattern to avoid moving the value LL | let ref mut a @ [b, ref mut c] = [u(), u()]; | +++ +error[E0382]: borrow of partially moved value + --> $DIR/borrowck-pat-by-move-and-ref.rs:59:9 + | +LL | ref mut a @ Some([b, mut c]) => {} + | ^^^^^^^^^ ----- value partially moved here + | | + | value borrowed here after partial move + | + = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref mut a @ Some([b, ref mut c]) => {} + | +++ + +error[E0382]: borrow of partially moved value + --> $DIR/borrowck-pat-by-move-and-ref.rs:65:9 + | +LL | ref a @ Some(b) => {} + | ^^^^^ - value partially moved here + | | + | value borrowed here after partial move + | + = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref a @ Some(ref b) => {} + | +++ + error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref.rs:69:23 + --> $DIR/borrowck-pat-by-move-and-ref.rs:71:23 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | ^^^^^ ----- value moved here @@ -251,7 +279,7 @@ LL | ref a @ Some((ref b @ ref mut c, ref d @ e)) => {} | +++ error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref.rs:69:38 + --> $DIR/borrowck-pat-by-move-and-ref.rs:71:38 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | ^^^^^ - value moved here @@ -264,6 +292,20 @@ help: borrow this binding in the pattern to avoid moving the value LL | ref a @ Some((ref b @ mut c, ref d @ ref e)) => {} | +++ +error[E0382]: borrow of partially moved value + --> $DIR/borrowck-pat-by-move-and-ref.rs:80:9 + | +LL | ref mut a @ Some([b, mut c]) => {} + | ^^^^^^^^^ ----- value partially moved here + | | + | value borrowed here after partial move + | + = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref mut a @ Some([b, ref mut c]) => {} + | +++ + error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:11:11 | @@ -345,6 +387,6 @@ LL | fn f3(ref mut a @ [b, mut c]: [U; 2]) {} | = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait -error: aborting due to 36 previous errors +error: aborting due to 39 previous errors For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs index 6bc0d346c111a..98f316dd74bdd 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs @@ -7,7 +7,7 @@ fn main() { match &mut Some(1) { ref mut z @ &mut Some(ref a) => { //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable - //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable + //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable **z = None; println!("{}", *a); } @@ -76,8 +76,8 @@ fn main() { ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable - //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable - //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable + //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable + //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable *b = U; drop(a); } @@ -87,6 +87,8 @@ fn main() { ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {} //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable + //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable + //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable //~| ERROR cannot assign to `*b`, as it is immutable for the pattern guard _ => {} } @@ -101,6 +103,8 @@ fn main() { ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable + //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable + //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable //~| ERROR cannot move out of `b` in pattern guard //~| ERROR cannot move out of `b` in pattern guard _ => {} diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr index 0b432487615b2..9359244c6ebc1 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr @@ -138,7 +138,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } | value is borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:96:9 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {} | ^^^^^^^^^ ----- value is borrowed by `b` here @@ -146,7 +146,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); fa | value is mutably borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:33 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:96:33 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {} | ^^^^^^^^^ ----- value is borrowed by `b` here @@ -154,7 +154,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); fa | value is mutably borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:9 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} | ^^^^^ --------- value is mutably borrowed by `b` here @@ -162,7 +162,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false | value is borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:33 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:33 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} | ^^^^^ --------- value is mutably borrowed by `b` here @@ -170,7 +170,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false | value is borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:113:9 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} | ^^^^^^^^^ ----- value is borrowed by `b` here @@ -178,7 +178,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false | value is mutably borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:33 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:113:33 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} | ^^^^^^^^^ ----- value is borrowed by `b` here @@ -186,7 +186,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false | value is mutably borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:117:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:121:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | ^^^^^ --------- --------- value is mutably borrowed by `c` here @@ -195,7 +195,7 @@ LL | let ref a @ (ref mut b, ref mut c) = (U, U); | value is borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:127:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | ^^^^^ --------- --------- value is mutably borrowed by `c` here @@ -204,7 +204,7 @@ LL | let ref a @ (ref mut b, ref mut c) = (U, U); | value is borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:129:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:133:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | ^^^^^ --------- --------- value is mutably borrowed by `c` here @@ -213,7 +213,7 @@ LL | let ref a @ (ref mut b, ref mut c) = (U, U); | value is borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:134:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:138:9 | LL | let ref mut a @ (ref b, ref c) = (U, U); | ^^^^^^^^^ ----- ----- value is borrowed by `c` here @@ -221,16 +221,16 @@ LL | let ref mut a @ (ref b, ref c) = (U, U); | | value is borrowed by `b` here | value is mutably borrowed by `a` here -error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:8:31 +error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:8:9 | LL | ref mut z @ &mut Some(ref a) => { - | --------- ^^^^^ immutable borrow occurs here + | ^^^^^^^^^ ----- immutable borrow occurs here | | | mutable borrow occurs here ... -LL | **z = None; - | ---------- mutable borrow later used here +LL | println!("{}", *a); + | -- immutable borrow later used here error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:46:9 @@ -254,27 +254,44 @@ LL | let ref a @ ref mut b = u(); LL | *b = u(); | -------- mutable borrow later used here -error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:20 +error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:9 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { - | ----- ^^^^^^^^^ mutable borrow occurs here + | ^^^^^ --------- mutable borrow occurs here | | | immutable borrow occurs here ... -LL | drop(a); - | - immutable borrow later used here +LL | *b = U; + | ------ mutable borrow later used here -error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:45 +error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:33 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { - | ----- ^^^^^^^^^ mutable borrow occurs here + | ^^^^^ --------- mutable borrow occurs here | | | immutable borrow occurs here ... -LL | drop(a); - | - immutable borrow later used here +LL | *b = U; + | ------ mutable borrow later used here + +error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:9 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {} + | ^^^^^ --------- mutable borrow occurs here ------ mutable borrow later used here + | | + | immutable borrow occurs here + +error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:33 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {} + | ^^^^^ --------- ------ mutable borrow later used here + | | | + | | mutable borrow occurs here + | immutable borrow occurs here error[E0594]: cannot assign to `*b`, as it is immutable for the pattern guard --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:61 @@ -285,15 +302,32 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } = note: variables bound in patterns are immutable until the end of the pattern guard error[E0594]: cannot assign to `*a`, as it is immutable for the pattern guard - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:61 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:96:61 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {} | ^^^^^^^^^^^ cannot assign | = note: variables bound in patterns are immutable until the end of the pattern guard +error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:9 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} + | ^^^^^ --------- mutable borrow occurs here - mutable borrow later used here + | | + | immutable borrow occurs here + +error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:33 + | +LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} + | ^^^^^ --------- - mutable borrow later used here + | | | + | | mutable borrow occurs here + | immutable borrow occurs here + error[E0507]: cannot move out of `b` in pattern guard - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:66 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:66 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} | ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait @@ -301,7 +335,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false = note: variables bound in patterns cannot be moved from until after the end of the pattern guard error[E0507]: cannot move out of `b` in pattern guard - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:66 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:66 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} | ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait @@ -310,7 +344,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0507]: cannot move out of `a` in pattern guard - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:66 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:113:66 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} | ^ move occurs because `a` has type `&mut Result`, which does not implement the `Copy` trait @@ -318,7 +352,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false = note: variables bound in patterns cannot be moved from until after the end of the pattern guard error[E0507]: cannot move out of `a` in pattern guard - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:66 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:113:66 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} | ^ move occurs because `a` has type `&mut Result`, which does not implement the `Copy` trait @@ -327,7 +361,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:117:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:121:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | ^^^^^ --------- mutable borrow occurs here @@ -338,7 +372,7 @@ LL | *b = U; | ------ mutable borrow later used here error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:127:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | ^^^^^ --------- mutable borrow occurs here @@ -349,7 +383,7 @@ LL | *b = U; | ------ mutable borrow later used here error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:129:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:133:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | ^^^^^ --------- mutable borrow occurs here @@ -409,7 +443,7 @@ LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {} | | value borrowed here after move | move occurs because value has type `U`, which does not implement the `Copy` trait -error: aborting due to 47 previous errors +error: aborting due to 51 previous errors Some errors have detailed explanations: E0382, E0502, E0507, E0594. For more information about an error, try `rustc --explain E0382`. diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs index 99739c7bce041..5f86a6a0ca919 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs @@ -82,6 +82,8 @@ fn main() { ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { //~^ ERROR cannot borrow value as mutable more than once at a time //~| ERROR cannot borrow value as mutable more than once at a time + //~| ERROR cannot borrow value as mutable more than once at a time + //~| ERROR cannot borrow value as mutable more than once at a time *b = U; } } @@ -89,8 +91,6 @@ fn main() { ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { //~^ ERROR cannot borrow value as mutable more than once at a time //~| ERROR cannot borrow value as mutable more than once at a time - //~| ERROR cannot borrow value as mutable more than once at a time - //~| ERROR cannot borrow value as mutable more than once at a time *a = Err(U); // FIXME: The binding name value used above makes for problematic diagnostics. @@ -101,8 +101,6 @@ fn main() { ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { //~^ ERROR cannot borrow value as mutable more than once at a time //~| ERROR cannot borrow value as mutable more than once at a time - //~| ERROR cannot borrow value as mutable more than once at a time - //~| ERROR cannot borrow value as mutable more than once at a time drop(a); } } diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr index c634ea470c5d5..3446148d2b15b 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr @@ -163,7 +163,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:89:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:91:9 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ^^^^^^^^^ --------- value is mutably borrowed by `b` here @@ -171,7 +171,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:89:37 + --> $DIR/borrowck-pat-ref-mut-twice.rs:91:37 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ^^^^^^^^^ --------- value is mutably borrowed by `b` here @@ -217,48 +217,26 @@ LL | *b = U; | ------ first borrow later used here error[E0499]: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:89:24 - | -LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { - | --------- ^^^^^^^^^ second mutable borrow occurs here - | | - | first mutable borrow occurs here -... -LL | *a = Err(U); - | ----------- first borrow later used here - -error[E0499]: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:89:53 - | -LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { - | --------- ^^^^^^^^^ second mutable borrow occurs here - | | - | first mutable borrow occurs here -... -LL | *a = Err(U); - | ----------- first borrow later used here - -error[E0499]: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:101:24 + --> $DIR/borrowck-pat-ref-mut-twice.rs:82:9 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { - | --------- ^^^^^^^^^ second mutable borrow occurs here + | ^^^^^^^^^ --------- first mutable borrow occurs here | | - | first mutable borrow occurs here + | second mutable borrow occurs here ... -LL | drop(a); - | - first borrow later used here +LL | *b = U; + | ------ first borrow later used here error[E0499]: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:101:53 + --> $DIR/borrowck-pat-ref-mut-twice.rs:82:37 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { - | --------- ^^^^^^^^^ second mutable borrow occurs here + | ^^^^^^^^^ --------- first mutable borrow occurs here | | - | first mutable borrow occurs here + | second mutable borrow occurs here ... -LL | drop(a); - | - first borrow later used here +LL | *b = U; + | ------ first borrow later used here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:8:11 @@ -313,7 +291,7 @@ LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {} | | value borrowed here after move | move occurs because value has type `U`, which does not implement the `Copy` trait -error: aborting due to 31 previous errors +error: aborting due to 29 previous errors Some errors have detailed explanations: E0382, E0499. For more information about an error, try `rustc --explain E0382`. From 0825ad3fb0488cbca375d6eb8d0af4dadbed5a91 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 21 Jan 2024 23:41:13 +0100 Subject: [PATCH 5/5] Clarify the new binding dance --- .../src/build/matches/simplify.rs | 64 ++++++------------- 1 file changed, 20 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 9fab61803e887..3eb39d68d749b 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -39,28 +39,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidate: &mut Candidate<'pat, 'tcx>, ) -> bool { debug!("{candidate:#?}"); - // `original_bindings` and `new_bindings` exist to keep the semantics in order. - // Reversing the binding order for bindings after `@` changes the binding order in places - // where it shouldn't be changed, for example `let (Some(a), Some(b)) = (x, y)`. + // In order to please the borrow checker, in a pattern like `x @ pat` we must lower the + // bindings in `pat` before `x`. E.g. (#69971): // - // To avoid this, the binding occurs in the following manner: - // * the bindings for one iteration of the loop occurs in order (i.e. left to right) - // * the bindings from the previous iteration of the loop is prepended to the bindings from - // the current iteration (in the implementation this is done by mem::swap and extend) - // * after all iterations, these new bindings are then appended to the bindings that were - // preexisting (i.e. `candidate.binding` when the function was called). - // - // example: - // candidate.bindings = [1, 2, 3] - // binding in iter 1: [4, 5] - // binding in iter 2: [6, 7] - // - // final binding: [1, 2, 3, 6, 7, 4, 5] - // - // This is because we treat refutable and irrefutable bindings differently. The binding - // order should be right-to-left if there are more _irrefutable_ bindings after `@` to - // please the borrow checker (#69971) - // Ex // struct NonCopyStruct { // copy_field: u32, // } @@ -72,23 +53,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // let y = x; // } // - // If however the bindings are refutable, i.e. under a test, then we keep the bindings - // left-to-right. - // Ex - // enum NonCopyEnum { - // Variant { copy_field: u32 }, - // None, - // } + // We can't just reverse the binding order, because we must preserve pattern-order + // otherwise, e.g. in `let (Some(a), Some(b)) = (x, y)`. Our rule then is: deepest-first, + // and bindings at the same depth stay in source order. // - // fn foo2(x: NonCopyEnum) { - // let y @ NonCopyEnum::Variant { copy_field: z } = x else { return }; - // // turns into - // let y = x; - // let z = (x as Variant).copy_field; - // // and raises an error - // } - let original_bindings = mem::take(&mut candidate.bindings); - let mut new_bindings = Vec::new(); + // To do this, every time around the loop we prepend the newly found bindings to the + // bindings we already had. + // + // example: + // candidate.bindings = [1, 2, 3] + // bindings in iter 1: [4, 5] + // bindings in iter 2: [6, 7] + // + // final bindings: [6, 7, 4, 5, 1, 2, 3] + let mut accumulated_bindings = mem::take(&mut candidate.bindings); // Repeatedly simplify match pairs until fixed point is reached loop { let mut changed = false; @@ -103,9 +81,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - // This does: new_bindings = candidate.bindings.take() ++ new_bindings - candidate.bindings.extend_from_slice(&new_bindings); - mem::swap(&mut candidate.bindings, &mut new_bindings); + // This does: accumulated_bindings = candidate.bindings.take() ++ accumulated_bindings + candidate.bindings.extend_from_slice(&accumulated_bindings); + mem::swap(&mut candidate.bindings, &mut accumulated_bindings); candidate.bindings.clear(); if !changed { @@ -114,10 +92,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - // Restore original bindings and append the new ones. - // This does: candidate.bindings = new_bindings ++ original_bindings - mem::swap(&mut candidate.bindings, &mut new_bindings); - candidate.bindings.extend_from_slice(&original_bindings); + // Store computed bindings back in `candidate`. + mem::swap(&mut candidate.bindings, &mut accumulated_bindings); let did_expand_or = if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place }] =