Skip to content

Commit

Permalink
[compiler-v2] Fix enum match not exhaustive (#15970)
Browse files Browse the repository at this point in the history
  • Loading branch information
vineethk authored Feb 19, 2025
1 parent 6c35318 commit e035f86
Show file tree
Hide file tree
Showing 7 changed files with 238 additions and 78 deletions.
22 changes: 14 additions & 8 deletions third_party/move/move-compiler-v2/src/bytecode_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2213,7 +2213,7 @@ impl ValueShape {
let mut values = BTreeSet::new();
for (_, shape) in &pattern_shapes {
for partial_value in shape.possible_values(env) {
Self::join_value_shape(&mut values, partial_value)
values = Self::join_value_shape(values, partial_value);
}
}
// Now go over all patterns in sequence and incrementally remove matched
Expand Down Expand Up @@ -2329,6 +2329,7 @@ impl ValueShape {
for (s1, s2) in shapes1.iter().zip(shapes2) {
if let Some(s) = s1.try_join(s2) {
result.push(s);
} else {
break;
}
}
Expand All @@ -2353,16 +2354,21 @@ impl ValueShape {

/// Given a list of value shapes, join a new one. This attempts specializing existing shapes
/// via the join operator in order to keep the list minimal.
fn join_value_shape(set: &mut BTreeSet<ValueShape>, value: ValueShape) {
for v in set.iter() {
fn join_value_shape(set: BTreeSet<ValueShape>, value: ValueShape) -> BTreeSet<ValueShape> {
let mut new_set = BTreeSet::new();
let mut joined = false;
for v in set.into_iter() {
if let Some(unified) = v.try_join(&value) {
let v = v.clone(); // to free set
set.remove(&v);
set.insert(unified);
return;
new_set.insert(unified);
joined = true;
} else {
new_set.insert(v);
}
}
set.insert(value);
if !joined {
new_set.insert(value);
}
new_set
}

/// Checks whether one shape is instance of another. It holds that
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,6 @@ error: match not exhaustive
│ ^^^^^^
= missing `(_,Inner::Inner1{..})`
= missing `(Inner::Inner2{..},_)`

error: unreachable pattern
┌─ tests/bytecode-generator/matching_coverage_err.move:78:14
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -468,11 +468,3 @@ error: match not exhaustive
│ ^
= missing `E1::C{..}`

error: match not exhaustive
┌─ tests/checking/dotdot/dotdot_valid.move:153:16
153 │ match (x) {
│ ^
= missing `E1::C{..}`
Original file line number Diff line number Diff line change
@@ -1,58 +1,13 @@
processed 5 tasks

task 0 'publish'. lines 1-51:
Error: compilation errors:
error: match not exhaustive
┌─ TEMPFILE:22:16
22 │ match (x) {
│ ^
= missing `E::V1{..}`
= missing `E::V2{..}`



task 1 'run'. lines 53-53:
Error: Function execution failed with VMError: {
message: Linker Error: Module 0000000000000000000000000000000000000000000000000000000000000042::test doesn't exist,
major_status: LINKER_ERROR,
sub_status: None,
location: undefined,
indices: [],
offsets: [],
exec_state: None,
}
return values: 42

task 2 'run'. lines 55-55:
Error: Function execution failed with VMError: {
message: Linker Error: Module 0000000000000000000000000000000000000000000000000000000000000042::test doesn't exist,
major_status: LINKER_ERROR,
sub_status: None,
location: undefined,
indices: [],
offsets: [],
exec_state: None,
}
return values: 42

task 3 'run'. lines 57-57:
Error: Function execution failed with VMError: {
message: Linker Error: Module 0000000000000000000000000000000000000000000000000000000000000042::test doesn't exist,
major_status: LINKER_ERROR,
sub_status: None,
location: undefined,
indices: [],
offsets: [],
exec_state: None,
}
return values: 43

task 4 'run'. lines 59-59:
Error: Function execution failed with VMError: {
message: Linker Error: Module 0000000000000000000000000000000000000000000000000000000000000042::test doesn't exist,
major_status: LINKER_ERROR,
sub_status: None,
location: undefined,
indices: [],
offsets: [],
exec_state: None,
}
return values: 43
Original file line number Diff line number Diff line change
@@ -1,13 +1 @@
processed 1 task

task 0 'publish'. lines 1-24:
Error: compilation errors:
error: match not exhaustive
┌─ TEMPFILE:16:16
16 │ match (y) {
│ ^
= missing `E::V1{..}`


Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
processed 4 tasks

task 3 'publish'. lines 147-197:
Error: compilation errors:
error: unreachable pattern
┌─ TEMPFILE3:168:13
168 │ E::V1 {..} => {}
│ ^^^^^^^^^^

error: unreachable pattern
┌─ TEMPFILE3:178:13
178 │ E::V1 {b: G::G2{ a: H::H2 {b: _}}, a: F::F1} => {},
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: unreachable pattern
┌─ TEMPFILE3:187:13
187 │ E::V1 {..} => {}
│ ^^^^^^^^^^


Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
//# publish
module 0xc0ffee::m {
enum A has drop {
V1 { a: Q, b: R},
}

enum Q has drop {
Q1,
Q2,
}

enum R has drop {
R1,
R2,
}

public fun test1(a: A) {
match (a) {
A::V1 { a: Q::Q1, b: _ } => {},
A::V1 { a: _, b: R::R1 } => {},
A::V1 {a: Q::Q2, b: R::R2} => {},
}
}

public fun test2(a: A) {
match (a) {
A::V1 { a: Q::Q1, b: _ } => {},
A::V1 { a: _, b: R::R1 } => {},
A::V1 {..} => {},
}
}

public fun test3(a: A) {
match (a) {
A::V1 { a: Q::Q1, b: _ } => {},
A::V1 { a: _, b: R::R1 } => {},
_ => {},
}
}

public fun test4(a: A) {
match (a) {
A::V1 { a: Q::Q1, b: _ } => {},
A::V1 {..} => {},
}
}

public fun test5(a: A) {
match (a) {
A::V1 { a: Q::Q1, b: _ } => {},
A::V1 { a: Q::Q2, b: _ } => {},
}
}

public fun test6(a: A) {
match (a) {
A::V1 { a: Q::Q1, b: _ } => {},
A::V1 { a: Q::Q2, b: _ } if true => {},
_ => {},
}
}
}


//# publish
module 0xc0ffee::n {
enum A has drop {
V1 { a: P, b: Q, c: R},
}

enum P has drop {
P1,
P2,
}

enum Q has drop {
Q1,
Q2,
}

enum R has drop {
R1,
R2,
}

public fun test(a: A) {
match (a) {
A::V1 { a: P::P1, b: _, c: _ } => {},
A::V1 { a: _, b: Q::Q1, c: _ } => {},
A::V1 { a: _, b: _, c: R::R1 } => {},
A::V1 { a: P::P2, b: Q::Q2, c: R::R2 } => {},
}
}
}


//# publish
module 0xc0ffee::o {
enum E has drop {
V1 { a: F, b: G },
V2 { a: F, b: G, c: H }
}

enum F has drop {
F1,
F2 { a: G }
}

enum G has drop {
G1 { a: H, b: H },
G2 { a: H }
}

enum H has drop {
H1 { a: u64},
H2 { b: u64 }
}

public fun test1(e: E) {
match (e) {
E::V1 {b: _, ..} => {},
E::V2 {..} => {}
}
}

public fun test2(e: E) {
match (e) {
E::V1 {b: G::G1{ a: H::H1 { a: _}, b: _}, ..} => {},
E::V1 {b: G::G1{ a: _, b: H::H1 { .. }}, ..} => {},
E::V1 {b: _, a: F::F1} => {},
E::V1 {b: _, a: F::F2 {..} } => {},
E::V2 {..} => {}
}
}

public fun test3(e: E) {
match (e) {
E::V1 {b: G::G1{ .. }, a: _} => {},
E::V1 {b: _, a: F::F2 {..} } => {},
E::V1 {b: G::G2{ a: H::H2 {b: _}}, a: F::F1} => {},
E::V1 {b: _, a: F::F1} => {},
E::V2 {..} => {}
}
}
}

//# publish
module 0xc0ffee::o_fail {
enum E has drop {
V1 { a: F, b: G },
V2 { a: F, b: G, c: H }
}

enum F has drop {
F1,
F2 { a: G }
}

enum G has drop {
G1 { a: H, b: H },
G2 { a: H }
}

enum H has drop {
H1 { a: u64},
H2 { b: u64 }
}

public fun test1(e: E) {
match (e) {
E::V1 {b: _, ..} => {},
E::V1 {..} => {}
E::V2 {..} => {}
}
}

public fun test2(e: E) {
match (e) {
E::V2 {..} => {}
E::V1 {b: G::G1{ .. }, a: _} => {},
E::V1 {b: _, a: F::F2 {..} } => {},
E::V1 {b: _, a: F::F1} => {},
E::V1 {b: G::G2{ a: H::H2 {b: _}}, a: F::F1} => {},
}
}

public fun test3(e: E) {
match (e) {
E::V1 {b: G::G1{ .. }, a: F::F1} => {},
E::V1 {b: G::G2{ .. }, a: F::F2 {..}} => {},
E::V1 {a: F::F2 {..}, ..} => {},
E::V1 {b: _, a: F::F1} => {},
E::V1 {..} => {}
E::V2 {..} => {}
}
}
}

0 comments on commit e035f86

Please sign in to comment.