Skip to content

Commit 2f662b1

Browse files
committed
Auto merge of #88280 - sexxi-goose:non-exhaustive, r=nikomatsakis
Handle match statements with non exhaustive variants in closures This PR ensures that the behavior for match statements with non exhaustive variants is the same inside and outside closures. If we have a non-exhaustive SingleVariant which is defined in a different crate, then we should handle the case the same way we would handle a MultiVariant: borrow the match discriminant. Closes rust-lang/project-rfc-2229#59 r? `@nikomatsakis`
2 parents ae0b03b + 33817d2 commit 2f662b1

17 files changed

+185
-2
lines changed

compiler/rustc_typeck/src/expr_use_visitor.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_index::vec::Idx;
1515
use rustc_infer::infer::InferCtxt;
1616
use rustc_middle::hir::place::ProjectionKind;
1717
use rustc_middle::mir::FakeReadCause;
18-
use rustc_middle::ty::{self, adjustment, Ty, TyCtxt};
18+
use rustc_middle::ty::{self, adjustment, AdtKind, Ty, TyCtxt};
1919
use rustc_target::abi::VariantIdx;
2020
use std::iter;
2121

@@ -845,5 +845,20 @@ fn delegate_consume<'a, 'tcx>(
845845
}
846846

847847
fn is_multivariant_adt(ty: Ty<'tcx>) -> bool {
848-
if let ty::Adt(def, _) = ty.kind() { def.variants.len() > 1 } else { false }
848+
if let ty::Adt(def, _) = ty.kind() {
849+
// Note that if a non-exhaustive SingleVariant is defined in another crate, we need
850+
// to assume that more cases will be added to the variant in the future. This mean
851+
// that we should handle non-exhaustive SingleVariant the same way we would handle
852+
// a MultiVariant.
853+
// If the variant is not local it must be defined in another crate.
854+
let is_non_exhaustive = match def.adt_kind() {
855+
AdtKind::Struct | AdtKind::Union => {
856+
def.non_enum_variant().is_field_list_non_exhaustive()
857+
}
858+
AdtKind::Enum => def.is_variant_list_non_exhaustive(),
859+
};
860+
def.variants.len() > 1 || (!def.did.is_local() && is_non_exhaustive)
861+
} else {
862+
false
863+
}
849864
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#[non_exhaustive]
2+
pub enum E1 {}
3+
4+
#[non_exhaustive]
5+
pub enum E2 { A, B }
6+
7+
#[non_exhaustive]
8+
pub enum E3 { C }
9+
10+
pub enum E4 { D }
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// edition:2021
2+
3+
enum SingleVariant {
4+
A
5+
}
6+
7+
struct TestStruct {
8+
x: i32,
9+
y: i32,
10+
z: i32,
11+
}
12+
13+
fn edge_case_if() {
14+
let sv = SingleVariant::A;
15+
let condition = true;
16+
// sv should not be captured as it is a SingleVariant
17+
let _a = || {
18+
match sv {
19+
SingleVariant::A if condition => (),
20+
_ => ()
21+
}
22+
};
23+
let mut mut_sv = sv;
24+
_a();
25+
26+
// ts should be captured
27+
let ts = TestStruct { x: 1, y: 1, z: 1 };
28+
let _b = || { match ts {
29+
TestStruct{ x: 1, .. } => (),
30+
_ => ()
31+
}};
32+
let mut mut_ts = ts;
33+
//~^ ERROR: cannot move out of `ts` because it is borrowed
34+
_b();
35+
}
36+
37+
fn main() {}

0 commit comments

Comments
 (0)