Skip to content

Commit

Permalink
[compiler-v2] Some fixes to enum variant type checking (#14411)
Browse files Browse the repository at this point in the history
* [compiler-v2] Some fixes to enum variant type checking

Those fixes resulted from testing various scenarios for the Move book

- Ensured that simple variant names are inferred for pack and not just unpack. This makes scenarios like `let c: Color = Blue` work.
- Ensured that 0-ary constructors can be used as `Blue` and not need `Blue()` or `Blue{}`.

Fixes #14365

A few test cases also now produce better error messages because types are earlier specialized.

Added some new test cases.

* Fix tests
  • Loading branch information
wrwg authored Aug 27, 2024
1 parent 5a8ca0a commit 1a639a9
Show file tree
Hide file tree
Showing 17 changed files with 366 additions and 126 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,6 @@ error: type `Coin` is missing required ability `drop` (type was inferred)
= required by instantiating type parameter `T:drop` of struct `S`

error: type `R<key + integer>` is missing required ability `key` (type was inferred)
┌─ tests/ability-check/v1-typing/pack_constraint_not_satisfied.move:12:30
3 │ struct R<T: key> { r: T }
│ - declaration of type parameter `T`
·
12 │ R {r: R { r: _ } } = R { r: R { r: 0 }};
│ ^
= required by instantiating type parameter `T:key` of struct `R`

error: type `R<key>` is missing required ability `key` (type was inferred)
┌─ tests/ability-check/v1-typing/pack_constraint_not_satisfied.move:12:30
Expand All @@ -43,3 +32,4 @@ error: type `Coin` is missing required ability `drop` (type was inferred)
│ ^
= required by instantiating type parameter `T:drop` of struct `S`
= required by instantiating type parameter `T:drop` of struct `S`
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// -- Model dump before bytecode pipeline
module 0x815::m {
enum E {
None,
Some {
0: u64,
}
}
private fun t(self: m::E): u64 {
{
let m::E::Some{ 0: x } = self;
x
}
}
} // end 0x815::m

============ initial bytecode ================

[variant baseline]
fun m::t($t0: m::E): u64 {
var $t1: u64
var $t2: u64
0: $t2 := unpack_variant m::E::Some($t0)
1: $t1 := infer($t2)
2: return $t1
}


============ bytecode verification succeeded ========
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module 0x815::m {

enum E {
None,
Some(u64)
}

fun t(self: E): u64 {
// We currently allow matching refutable patterns with let
let Some(x) = self;
x
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// -- Model dump before bytecode pipeline
module 0x1::m {
struct R {
value: bool,
}
private fun f1()
acquires m::R(*)
{
{
let x: &mut m::R = BorrowGlobal(Mutable)<m::R>(0x1);
select m::R.value<&mut m::R>(x) = false;
if Eq<bool>(select m::R.value<m::R>(BorrowGlobal(Immutable)<m::R>(0x1)), false) {
Tuple()
} else {
Abort(1)
};
select m::R.value<m::R>(BorrowGlobal(Mutable)<m::R>(0x1)) = true;
if Eq<bool>(select m::R.value<m::R>(BorrowGlobal(Immutable)<m::R>(0x1)), true) {
Tuple()
} else {
Abort(2)
};
Tuple()
}
}
} // end 0x1::m
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module 0x1::m {

struct R has key, drop { value: bool }

fun f1() acquires R {
let x = &mut R[@0x1];
x.value = false;
assert!(R[@0x1].value == false, 1);
R[@0x1].value = true;
assert!(R[@0x1].value == true, 2);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ error: missing fields `y`, `z`
40 │ S{x: x}
│ ^^^^^^^

error: cannot return `G<u64>` from a function with result type `G<bool>`
┌─ tests/checking/specs/structs_err.move:45:7
error: expected `bool` but found a value of type `u64`
┌─ tests/checking/specs/structs_err.move:45:12
45 │ G{x: x, y: y}
^^^^^^^^^^^^^
^

error: expected 1 type argument but 2 were provided
┌─ tests/checking/specs/structs_err.move:50:7
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error: expected 1 type argument but 0 were provided
┌─ tests/checking/typing/bad_type_argument_arity_struct_unpack.move:7:13
7 │ let S<> { f } = copy s;
│ ^^^^^^^^^
│ ^

error: undeclared `f`
┌─ tests/checking/typing/bad_type_argument_arity_struct_unpack.move:8:9
Expand All @@ -16,7 +16,7 @@ error: expected 1 type argument but 2 were provided
┌─ tests/checking/typing/bad_type_argument_arity_struct_unpack.move:9:13
9 │ let S<u64, u64> { f } = copy s;
│ ^^^^^^^^^^^^^^^^^
│ ^

error: undeclared `f`
┌─ tests/checking/typing/bad_type_argument_arity_struct_unpack.move:10:9
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,17 @@

Diagnostics:
bug: inconsistent struct definition
error: native struct `C::T` has no fields
┌─ tests/checking/typing/native_structs_pack_unpack.move:9:9
9 │ C::T {}
│ ^^^^

bug: inconsistent struct definition
error: native struct `C::T` has no fields
┌─ tests/checking/typing/native_structs_pack_unpack.move:12:13
12 │ let C::T {} = c;
│ ^^^^

error: unable to infer instantiation of type `_` (consider providing type arguments or annotating the type)
┌─ tests/checking/typing/native_structs_pack_unpack.move:12:13
12 │ let C::T {} = c;
│ ^^^^^^^

error: field `f` not declared in struct `C::T`
┌─ tests/checking/typing/native_structs_pack_unpack.move:15:17
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ error: expected `u64` but found a value of type `bool`
18 │ f: false,
│ ^^^^^

error: expected `Nat<u64>` but found a value of type `Nat<bool>`
┌─ tests/checking/typing/pack_invalid_argument.move:19:17
error: expected `u64` but found a value of type `bool`
┌─ tests/checking/typing/pack_invalid_argument.move:19:26
19 │ n1: Nat { f: false },
^^^^^^^^^^^^^^^^
^^^^^

error: expected `Nat<S>` but found a value of type `Nat<R>`
┌─ tests/checking/typing/pack_invalid_argument.move:20:17
error: expected `S` but found a value of type `R`
┌─ tests/checking/typing/pack_invalid_argument.move:20:25
20 │ n2: Nat{ f: r }
^^^^^^^^^^^
^
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@ error: expected `bool` but found a value of type `integer`
5 │ let b = Box { f1: false, f2: 1 };
│ ^

error: expected `Box<integer>` but found a value of type `Box<bool>`
┌─ tests/checking/typing/type_variable_join_single_pack_invalid.move:6:55
error: expected `integer` but found a value of type `bool`
┌─ tests/checking/typing/type_variable_join_single_pack_invalid.move:6:65
6 │ let b2 = Box { f1: Box { f1: 0, f2: 0 }, f2: Box { f1: false, f2: false } };
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
│ ^^^^^

error: expected `integer` but found a value of type `bool`
┌─ tests/checking/typing/type_variable_join_single_pack_invalid.move:6:76
6 │ let b2 = Box { f1: Box { f1: 0, f2: 0 }, f2: Box { f1: false, f2: false } };
│ ^^^^^
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ error: variants not allowed in this context
27 │ fun missplaced_variant(self: Color::Red): bool {
│ ^^^^^^^^^^

error: undeclared struct `m::missplaced_variant`
error: variants not allowed in this context
┌─ tests/checking/variants/variants_check_err.move:28:9
28 │ 0x815::m::missplaced_variant::Red();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// -- Model dump before bytecode pipeline
module 0x815::m {
enum Color {
RGB {
red: u64,
green: u64,
blue: u64,
}
Red,
Blue,
}
private fun t0(): bool {
{
let c: m::Color = pack m::Color::Red();
Eq<u64>(select_variants m::Color.RGB.red<m::Color>(c), 1)
}
}
private fun t1(): bool {
{
let c: m::Color = pack m::Color::Red();
Eq<u64>(select_variants m::Color.RGB.red<m::Color>(c), 1)
}
}
private fun t2(): bool {
{
let c: m::Color = pack m::Color::Blue();
Eq<u64>(select_variants m::Color.RGB.red<m::Color>(c), 1)
}
}
private fun t3(): bool {
{
let c: m::Color = pack m::Color::Blue();
Eq<u64>(select_variants m::Color.RGB.red<m::Color>(c), 1)
}
}
private fun t4(c: &m::Color) {
match (c) {
m::Color::Red => {
Abort(1)
}
m::Color::Blue => {
Abort(2)
}
}

}
} // end 0x815::m
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module 0x815::m {

enum Color {
RGB{red: u64, green: u64, blue: u64},
Red,
Blue(),
}

fun t0(): bool {
let c = Color::Red; // no error expected
c.red == 1
}
fun t1(): bool {
let c : Color = Red; // no error expected
c.red == 1
}

fun t2(): bool {
let c : Color = Blue; // no error expected
c.red == 1
}

fun t3(): bool {
let c : Color = Blue(); // no error expected
c.red == 1
}

fun t4(c: &Color) {
match (c) { Red => abort 1, Blue => abort 2 } // no error
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

Diagnostics:
error: undeclared struct `m::Red`
┌─ tests/checking/variants/variants_inference.move:17:14
17 │ take(Red{}) // errors expected because of bottom-up type inference
│ ^^^

error: undeclared struct `m::Red`
┌─ tests/checking/variants/variants_inference.move:21:17
21 │ let c = Red{}; // error expected
│ ^^^

error: enum `m::Color` must be used with one of its variants
┌─ tests/checking/variants/variants_inference.move:26:17
26 │ let c = Color{}; // error expected
│ ^^^^^
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
module 0x815::m {

enum Color {
RGB{red: u64, green: u64, blue: u64},
Red,
Blue(u64),
}

fun take(_c: Color){}

fun t1(): bool {
let c : Color = Red{}; // no error expected
c.red == 1
}

fun t2() {
take(Red{}) // errors expected because of bottom-up type inference
}

fun t3(): Color {
let c = Red{}; // error expected
c
}

fun t4(): Color {
let c = Color{}; // error expected
c
}

fun t5(): Color {
let c : Color = Blue(0); // no error expected
c
}
}
Loading

0 comments on commit 1a639a9

Please sign in to comment.