diff --git a/third_party/move/move-compiler-v2/tests/op-equal/error_not_shown.exp b/third_party/move/move-compiler-v2/tests/op-equal/error_not_shown.exp new file mode 100644 index 0000000000000..9363c1382ce08 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/op-equal/error_not_shown.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: cannot mutably borrow from an immutable ref + ┌─ tests/op-equal/error_not_shown.move:9:17 + │ +9 │ let p = &mut self.0; + │ ^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/op-equal/error_not_shown.move b/third_party/move/move-compiler-v2/tests/op-equal/error_not_shown.move new file mode 100644 index 0000000000000..576f91afa91cf --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/op-equal/error_not_shown.move @@ -0,0 +1,12 @@ +module 0x42::test { + struct Coin(u256) has drop; + + fun inc_old(x: &u256) { + *x = *x + 1; + } + + fun coin_inc_new_1(self: &Coin) { + let p = &mut self.0; + *p += 1; + } +} diff --git a/third_party/move/move-compiler-v2/tests/op-equal/eval_order.exp b/third_party/move/move-compiler-v2/tests/op-equal/eval_order.exp new file mode 100644 index 0000000000000..af73f4aa09c89 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/op-equal/eval_order.exp @@ -0,0 +1,432 @@ +// -- Model dump before bytecode pipeline +module 0xc0ffee::m { + private fun mod1(r: &mut u64) { + { + let $t1: &mut u64 = r; + $t1 = Add(Deref($t1), 2) + }; + Tuple() + } + private fun mod2(r: &mut u64): u64 { + { + let $t1: &mut u64 = r; + $t1 = Add(Deref($t1), 2) + }; + Deref(r) + } + public fun test0(): u64 { + { + let v: u64 = 1; + { + let $t: u64 = { + let $t: u64 = v: u64 = Add(v, 2); + v; + v: u64 = Add(v, $t) + }; + v; + v: u64 = Add(v, $t) + }; + v + } + } + public fun test1(): u64 { + { + let v: u64 = 1; + { + let $t: u64 = v: u64 = Add(v, 2); + v; + v: u64 = Add(v, $t) + }; + v + } + } + public fun test2(): u64 { + { + let v: u64 = 1; + { + let $t: u64 = m::mod1(Borrow(Mutable)(v)); + v; + v: u64 = Add(v, $t) + }; + v + } + } + public fun test3(): u64 { + { + let v: u64 = 1; + { + let $t: u64 = m::mod2(Borrow(Mutable)(v)); + v: u64 = Add(v, $t) + }; + v + } + } +} // end 0xc0ffee::m + +============ initial bytecode ================ + +[variant baseline] +fun m::mod1($t0: &mut u64) { + var $t1: &mut u64 + var $t2: u64 + var $t3: u64 + var $t4: u64 + 0: $t1 := infer($t0) + 1: $t3 := read_ref($t1) + 2: $t4 := 2 + 3: $t2 := +($t3, $t4) + 4: write_ref($t1, $t2) + 5: return () +} + + +[variant baseline] +fun m::mod2($t0: &mut u64): u64 { + var $t1: u64 + var $t2: &mut u64 + var $t3: u64 + var $t4: u64 + var $t5: u64 + 0: $t2 := infer($t0) + 1: $t4 := read_ref($t2) + 2: $t5 := 2 + 3: $t3 := +($t4, $t5) + 4: write_ref($t2, $t3) + 5: $t1 := read_ref($t0) + 6: return $t1 +} + + +[variant baseline] +public fun m::test0(): u64 { + var $t0: u64 + var $t1: u64 + var $t2: u64 + var $t3: u64 + var $t4: u64 + var $t5: u64 + var $t6: u64 + var $t7: u64 + 0: $t1 := 1 + 1: $t5 := 2 + 2: $t4 := +($t1, $t5) + 3: $t1 := infer($t4) + 4: $t3 := infer($t1) + 5: $t6 := +($t1, $t3) + 6: $t1 := infer($t6) + 7: $t2 := infer($t1) + 8: $t7 := +($t1, $t2) + 9: $t1 := infer($t7) + 10: $t0 := infer($t1) + 11: return $t0 +} + + +[variant baseline] +public fun m::test1(): u64 { + var $t0: u64 + var $t1: u64 + var $t2: u64 + var $t3: u64 + var $t4: u64 + var $t5: u64 + 0: $t1 := 1 + 1: $t4 := 2 + 2: $t3 := +($t1, $t4) + 3: $t1 := infer($t3) + 4: $t2 := infer($t1) + 5: $t5 := +($t1, $t2) + 6: $t1 := infer($t5) + 7: $t0 := infer($t1) + 8: return $t0 +} + + +[variant baseline] +public fun m::test2(): u64 { + var $t0: u64 + var $t1: u64 + var $t2: u64 + var $t3: &mut u64 + var $t4: u64 + 0: $t1 := 1 + 1: $t3 := borrow_local($t1) + 2: m::mod1($t3) + 3: $t2 := infer($t1) + 4: $t4 := +($t1, $t2) + 5: $t1 := infer($t4) + 6: $t0 := infer($t1) + 7: return $t0 +} + + +[variant baseline] +public fun m::test3(): u64 { + var $t0: u64 + var $t1: u64 + var $t2: u64 + var $t3: &mut u64 + var $t4: u64 + 0: $t1 := 1 + 1: $t3 := borrow_local($t1) + 2: $t2 := m::mod2($t3) + 3: $t4 := +($t1, $t2) + 4: $t1 := infer($t4) + 5: $t0 := infer($t1) + 6: return $t0 +} + +============ after LiveVarAnalysisProcessor: ================ + +[variant baseline] +fun m::mod1($t0: &mut u64) { + var $t1: &mut u64 [unused] + var $t2: u64 [unused] + var $t3: u64 + var $t4: u64 + # live vars: $t0 + 0: $t3 := read_ref($t0) + # live vars: $t0, $t3 + 1: $t4 := 2 + # live vars: $t0, $t3, $t4 + 2: $t3 := +($t3, $t4) + # live vars: $t0, $t3 + 3: write_ref($t0, $t3) + # live vars: + 4: return () +} + + +[variant baseline] +fun m::mod2($t0: &mut u64): u64 { + var $t1: u64 [unused] + var $t2: &mut u64 + var $t3: u64 [unused] + var $t4: u64 + var $t5: u64 + # live vars: $t0 + 0: $t2 := copy($t0) + # live vars: $t0, $t2 + 1: $t4 := read_ref($t2) + # live vars: $t0, $t2, $t4 + 2: $t5 := 2 + # live vars: $t0, $t2, $t4, $t5 + 3: $t4 := +($t4, $t5) + # live vars: $t0, $t2, $t4 + 4: write_ref($t2, $t4) + # live vars: $t0 + 5: $t4 := read_ref($t0) + # live vars: $t4 + 6: return $t4 +} + + +[variant baseline] +public fun m::test0(): u64 { + var $t0: u64 [unused] + var $t1: u64 + var $t2: u64 [unused] + var $t3: u64 [unused] + var $t4: u64 [unused] + var $t5: u64 + var $t6: u64 [unused] + var $t7: u64 [unused] + # live vars: + 0: $t1 := 1 + # live vars: $t1 + 1: $t5 := 2 + # live vars: $t1, $t5 + 2: $t5 := +($t1, $t5) + # live vars: $t5 + 3: $t1 := move($t5) + # live vars: $t1 + 4: $t5 := copy($t1) + # live vars: $t1, $t5 + 5: $t5 := +($t1, $t5) + # live vars: $t5 + 6: $t1 := move($t5) + # live vars: $t1 + 7: $t5 := copy($t1) + # live vars: $t1, $t5 + 8: $t5 := +($t1, $t5) + # live vars: $t5 + 9: $t1 := move($t5) + # live vars: $t1 + 10: return $t1 +} + + +[variant baseline] +public fun m::test1(): u64 { + var $t0: u64 [unused] + var $t1: u64 + var $t2: u64 [unused] + var $t3: u64 [unused] + var $t4: u64 + var $t5: u64 [unused] + # live vars: + 0: $t1 := 1 + # live vars: $t1 + 1: $t4 := 2 + # live vars: $t1, $t4 + 2: $t4 := +($t1, $t4) + # live vars: $t4 + 3: $t1 := move($t4) + # live vars: $t1 + 4: $t4 := copy($t1) + # live vars: $t1, $t4 + 5: $t4 := +($t1, $t4) + # live vars: $t4 + 6: $t1 := move($t4) + # live vars: $t1 + 7: return $t1 +} + + +[variant baseline] +public fun m::test2(): u64 { + var $t0: u64 [unused] + var $t1: u64 + var $t2: u64 + var $t3: &mut u64 + var $t4: u64 [unused] + # live vars: + 0: $t1 := 1 + # live vars: $t1 + 1: $t3 := borrow_local($t1) + # live vars: $t1, $t3 + 2: m::mod1($t3) + # live vars: $t1 + 3: $t2 := copy($t1) + # live vars: $t1, $t2 + 4: $t2 := +($t1, $t2) + # live vars: $t2 + 5: $t1 := move($t2) + # live vars: $t1 + 6: $t2 := move($t1) + # live vars: $t2 + 7: return $t2 +} + + +[variant baseline] +public fun m::test3(): u64 { + var $t0: u64 [unused] + var $t1: u64 + var $t2: u64 + var $t3: &mut u64 + var $t4: u64 [unused] + # live vars: + 0: $t1 := 1 + # live vars: $t1 + 1: $t3 := borrow_local($t1) + # live vars: $t1, $t3 + 2: $t2 := m::mod2($t3) + # live vars: $t1, $t2 + 3: $t2 := +($t1, $t2) + # live vars: $t2 + 4: $t1 := move($t2) + # live vars: $t1 + 5: $t2 := move($t1) + # live vars: $t2 + 6: return $t2 +} + + +============ disassembled file-format ================== +// Move bytecode v7 +module c0ffee.m { + + +mod1(Arg0: &mut u64) /* def_idx: 0 */ { +B0: + 0: CopyLoc[0](Arg0: &mut u64) + 1: ReadRef + 2: LdU64(2) + 3: Add + 4: MoveLoc[0](Arg0: &mut u64) + 5: WriteRef + 6: Ret +} +mod2(Arg0: &mut u64): u64 /* def_idx: 1 */ { +L1: loc0: &mut u64 +B0: + 0: CopyLoc[0](Arg0: &mut u64) + 1: StLoc[1](loc0: &mut u64) + 2: CopyLoc[1](loc0: &mut u64) + 3: ReadRef + 4: LdU64(2) + 5: Add + 6: MoveLoc[1](loc0: &mut u64) + 7: WriteRef + 8: MoveLoc[0](Arg0: &mut u64) + 9: ReadRef + 10: Ret +} +public test0(): u64 /* def_idx: 2 */ { +L0: loc0: u64 +L1: loc1: u64 +B0: + 0: LdU64(1) + 1: LdU64(2) + 2: Add + 3: StLoc[0](loc0: u64) + 4: CopyLoc[0](loc0: u64) + 5: StLoc[1](loc1: u64) + 6: MoveLoc[0](loc0: u64) + 7: MoveLoc[1](loc1: u64) + 8: Add + 9: StLoc[0](loc0: u64) + 10: CopyLoc[0](loc0: u64) + 11: StLoc[1](loc1: u64) + 12: MoveLoc[0](loc0: u64) + 13: MoveLoc[1](loc1: u64) + 14: Add + 15: Ret +} +public test1(): u64 /* def_idx: 3 */ { +L0: loc0: u64 +L1: loc1: u64 +B0: + 0: LdU64(1) + 1: LdU64(2) + 2: Add + 3: StLoc[0](loc0: u64) + 4: CopyLoc[0](loc0: u64) + 5: StLoc[1](loc1: u64) + 6: MoveLoc[0](loc0: u64) + 7: MoveLoc[1](loc1: u64) + 8: Add + 9: Ret +} +public test2(): u64 /* def_idx: 4 */ { +L0: loc0: u64 +L1: loc1: u64 +B0: + 0: LdU64(1) + 1: StLoc[0](loc0: u64) + 2: MutBorrowLoc[0](loc0: u64) + 3: Call mod1(&mut u64) + 4: CopyLoc[0](loc0: u64) + 5: StLoc[1](loc1: u64) + 6: MoveLoc[0](loc0: u64) + 7: MoveLoc[1](loc1: u64) + 8: Add + 9: Ret +} +public test3(): u64 /* def_idx: 5 */ { +L0: loc0: u64 +L1: loc1: u64 +B0: + 0: LdU64(1) + 1: StLoc[0](loc0: u64) + 2: MutBorrowLoc[0](loc0: u64) + 3: Call mod2(&mut u64): u64 + 4: StLoc[1](loc1: u64) + 5: MoveLoc[0](loc0: u64) + 6: MoveLoc[1](loc1: u64) + 7: Add + 8: Ret +} +} +============ bytecode verification succeeded ======== diff --git a/third_party/move/move-compiler-v2/tests/op-equal/eval_order.move b/third_party/move/move-compiler-v2/tests/op-equal/eval_order.move new file mode 100644 index 0000000000000..a7ed50b6b2fd4 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/op-equal/eval_order.move @@ -0,0 +1,35 @@ +//# publish +module 0xc0ffee::m { + public fun test0(): u64 { + let v = 1; + v += {v += {v += 2; v}; v}; + v + } + + public fun test1(): u64 { + let v = 1; + v += {v += 2; v}; + v + } + + fun mod1(r: &mut u64) { + *r += 2; + } + + public fun test2(): u64 { + let v = 1; + v += {mod1(&mut v); v}; + v + } + + fun mod2(r: &mut u64): u64 { + *r += 2; + *r + } + + public fun test3(): u64 { + let v = 1; + v += mod2(&mut v); + v + } +} diff --git a/third_party/move/move-compiler-v2/tests/op-equal/invalid0.exp b/third_party/move/move-compiler-v2/tests/op-equal/invalid0.exp new file mode 100644 index 0000000000000..358a135228d62 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/op-equal/invalid0.exp @@ -0,0 +1,19 @@ + +Diagnostics: +error: cannot mutably borrow from an immutable ref + ┌─ tests/op-equal/invalid0.move:8:3 + │ +8 │ self.0 += 1; + │ ^^^^^^ + +error: expected `&mut` but `&` was provided + ┌─ tests/op-equal/invalid0.move:12:3 + │ +12 │ x[index] += 1; + │ ^ + +error: expected `&mut` but `&` was provided + ┌─ tests/op-equal/invalid0.move:16:3 + │ +16 │ x[index].0.0 += 1; + │ ^ diff --git a/third_party/move/move-compiler-v2/tests/op-equal/invalid0.move b/third_party/move/move-compiler-v2/tests/op-equal/invalid0.move new file mode 100644 index 0000000000000..7efcf97295eb5 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/op-equal/invalid0.move @@ -0,0 +1,18 @@ +module 0x42::test { + struct Coin(u256) has drop; + + struct Wrapper(T) has drop; + + + fun coin_inc_new_1(self: &Coin) { + self.0 += 1; + } + + fun inc_vec_new(x: &vector, index: u64) { + x[index] += 1; + } + + fun inc_vec_wrapped_coin_new(x: &vector>, index: u64) { + x[index].0.0 += 1; + } +} diff --git a/third_party/move/move-compiler-v2/tests/op-equal/invalid1.exp b/third_party/move/move-compiler-v2/tests/op-equal/invalid1.exp new file mode 100644 index 0000000000000..c4d6ef7d6de9f --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/op-equal/invalid1.exp @@ -0,0 +1,67 @@ +// -- Model dump before bytecode pipeline +module 0x42::test { + private fun test() { + { + let x: u64 = 42; + { + let p: &mut u64 = Borrow(Mutable)(x); + x: u64 = Add(x, 1); + { + let $t1: &mut u64 = p; + $t1 = Add(Deref($t1), 1) + }; + x; + Tuple() + } + } + } +} // end 0x42::test + +============ initial bytecode ================ + +[variant baseline] +fun test::test() { + var $t0: u64 + var $t1: &mut u64 + var $t2: u64 + var $t3: u64 + var $t4: &mut u64 + var $t5: u64 + var $t6: u64 + var $t7: u64 + var $t8: u64 + 0: $t0 := 42 + 1: $t1 := borrow_local($t0) + 2: $t3 := 1 + 3: $t2 := +($t0, $t3) + 4: $t0 := infer($t2) + 5: $t4 := infer($t1) + 6: $t6 := read_ref($t4) + 7: $t7 := 1 + 8: $t5 := +($t6, $t7) + 9: write_ref($t4, $t5) + 10: $t8 := infer($t0) + 11: return () +} + + +Diagnostics: +error: cannot copy local `x` which is still mutably borrowed + ┌─ tests/op-equal/invalid1.move:5:3 + │ +4 │ let p = &mut x; + │ ------ local `x` previously mutably borrowed here +5 │ x += 1; + │ ^^^^^^ copy attempted here +6 │ *p += 1; + │ - conflicting reference `p` used here + +error: cannot drop local `x` which is still borrowed + ┌─ tests/op-equal/invalid1.move:5:3 + │ +4 │ let p = &mut x; + │ ------ local `x` previously mutably borrowed here +5 │ x += 1; + │ ^^^^^^ dropped here +6 │ *p += 1; + │ - conflicting reference `p` used here diff --git a/third_party/move/move-compiler-v2/tests/op-equal/invalid1.move b/third_party/move/move-compiler-v2/tests/op-equal/invalid1.move new file mode 100644 index 0000000000000..dcca73a261272 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/op-equal/invalid1.move @@ -0,0 +1,9 @@ +module 0x42::test { + fun test() { + let x = 42; + let p = &mut x; + x += 1; + *p += 1; + x; + } +} diff --git a/third_party/move/move-compiler-v2/tests/op-equal/invalid2.exp b/third_party/move/move-compiler-v2/tests/op-equal/invalid2.exp new file mode 100644 index 0000000000000..ed3dc28c6ba5b --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/op-equal/invalid2.exp @@ -0,0 +1,19 @@ + +Diagnostics: +error: cannot use `bool` with an operator which expects a value of type `integer` + ┌─ tests/op-equal/invalid2.move:4:9 + │ +4 │ x += 1; + │ ^ + +error: cannot use `bool` with an operator which expects a value of type `integer` + ┌─ tests/op-equal/invalid2.move:9:9 + │ +9 │ x += true; + │ ^ + +error: cannot use `bool` with an operator which expects a value of type `integer` + ┌─ tests/op-equal/invalid2.move:14:14 + │ +14 │ x += false; + │ ^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/op-equal/invalid2.move b/third_party/move/move-compiler-v2/tests/op-equal/invalid2.move new file mode 100644 index 0000000000000..61edb2c1715b1 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/op-equal/invalid2.move @@ -0,0 +1,16 @@ +module 0x42::test { + fun test0() { + let x = false; + x += 1; + } + + fun test1() { + let x = false; + x += true; + } + + fun test2() { + let x = 1; + x += false; + } +} diff --git a/third_party/move/move-compiler-v2/tests/op-equal/invalid3.exp b/third_party/move/move-compiler-v2/tests/op-equal/invalid3.exp new file mode 100644 index 0000000000000..b983ec425e8fb --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/op-equal/invalid3.exp @@ -0,0 +1,13 @@ + +Diagnostics: +error: invalid assignment + ┌─ tests/op-equal/invalid3.move:3:9 + │ +3 │ 1 += 1; + │ ^ Invalid assignment syntax. Expected: a local, a field write, or a deconstructing assignment + +error: invalid assignment + ┌─ tests/op-equal/invalid3.move:11:9 + │ +11 │ foo() += 1; + │ ^^^^^ Invalid assignment syntax. Expected: a local, a field write, or a deconstructing assignment diff --git a/third_party/move/move-compiler-v2/tests/op-equal/invalid3.move b/third_party/move/move-compiler-v2/tests/op-equal/invalid3.move new file mode 100644 index 0000000000000..8600114840708 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/op-equal/invalid3.move @@ -0,0 +1,13 @@ +module 0x42::test { + fun test0() { + 1 += 1; + } + + fun foo(): u8 { + 42 + } + + fun test1() { + foo() += 1; + } +} diff --git a/third_party/move/move-compiler-v2/tests/op-equal/invalid4.exp b/third_party/move/move-compiler-v2/tests/op-equal/invalid4.exp new file mode 100644 index 0000000000000..1550536bbc989 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/op-equal/invalid4.exp @@ -0,0 +1,10 @@ + +Diagnostics: +error: unexpected token + ┌─ tests/op-equal/invalid4.move:3:15 + │ +3 │ let x += 1; + │ ^^ + │ │ + │ Unexpected '+=' + │ Expected ';' diff --git a/third_party/move/move-compiler-v2/tests/op-equal/invalid4.move b/third_party/move/move-compiler-v2/tests/op-equal/invalid4.move new file mode 100644 index 0000000000000..8b3d6ba344d7c --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/op-equal/invalid4.move @@ -0,0 +1,5 @@ +module 0x42::test { + fun test() { + let x += 1; + } +} diff --git a/third_party/move/move-compiler-v2/tests/op-equal/invalid5.exp b/third_party/move/move-compiler-v2/tests/op-equal/invalid5.exp new file mode 100644 index 0000000000000..e8856e5b040c6 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/op-equal/invalid5.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: cannot use `()` with an operator which expects a value of type `integer` + ┌─ tests/op-equal/invalid5.move:4:17 + │ +4 │ let y = (x += 2) * (x -= 1); + │ ^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/op-equal/invalid5.move b/third_party/move/move-compiler-v2/tests/op-equal/invalid5.move new file mode 100644 index 0000000000000..32be3bf383db8 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/op-equal/invalid5.move @@ -0,0 +1,6 @@ +module 0x42::test { + fun testZ() { + let x = 3; + let y = (x += 2) * (x -= 1); + } +} diff --git a/third_party/move/move-compiler-v2/tests/op-equal/invalid6.exp b/third_party/move/move-compiler-v2/tests/op-equal/invalid6.exp new file mode 100644 index 0000000000000..b0f19991064b6 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/op-equal/invalid6.exp @@ -0,0 +1,28 @@ +// -- Model dump before bytecode pipeline +module 0x42::test { + private fun inc_new(x: &u256) { + { + let $t1: &u256 = x; + $t1 = Add(Deref($t1), 1) + }; + Tuple() + } + private fun inc_old(x: &u256) { + x = Add(Deref(x), 1); + Tuple() + } +} // end 0x42::test + + +Diagnostics: +error: expected `&mut` but found `&u256` + ┌─ tests/op-equal/invalid6.move:3:10 + │ +3 │ *x = *x + 1; + │ ^ + +error: expected `&mut` but found `&u256` + ┌─ tests/op-equal/invalid6.move:7:11 + │ +7 │ *x += 1; + │ ^ diff --git a/third_party/move/move-compiler-v2/tests/op-equal/invalid6.move b/third_party/move/move-compiler-v2/tests/op-equal/invalid6.move new file mode 100644 index 0000000000000..684e628eacfe0 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/op-equal/invalid6.move @@ -0,0 +1,9 @@ +module 0x42::test { + fun inc_old(x: &u256) { + *x = *x + 1; + } + + fun inc_new(x: &u256) { + *x += 1; + } +} diff --git a/third_party/move/move-compiler-v2/tests/op-equal/valid0.exp b/third_party/move/move-compiler-v2/tests/op-equal/valid0.exp new file mode 100644 index 0000000000000..f8abe9f33a24b --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/op-equal/valid0.exp @@ -0,0 +1,1076 @@ +// -- Model dump before bytecode pipeline +module 0x42::test { + struct Coin { + 0: u256, + } + struct Wrapper { + 0: #0, + } + private fun add1_new(x: u256): u256 { + x: u256 = Add(x, 1); + x + } + private fun add1_old(x: u256): u256 { + x: u256 = Add(x, 1); + x + } + private fun coin_inc_new_1(self: &mut test::Coin) { + { + let $t1: &mut u256 = Borrow(Mutable)(select test::Coin.0<&mut test::Coin>(self)); + $t1 = Add(Deref($t1), 1) + }; + Tuple() + } + private fun coin_inc_new_2(self: &mut test::Coin) { + { + let p: &mut u256 = Borrow(Mutable)(select test::Coin.0<&mut test::Coin>(self)); + p = Add(Deref(p), 1); + Tuple() + } + } + private fun coin_inc_old_1(self: &mut test::Coin) { + select test::Coin.0<&mut test::Coin>(self) = Add(select test::Coin.0<&mut test::Coin>(self), 1); + Tuple() + } + private fun coin_inc_old_2(self: &mut test::Coin) { + { + let p: &mut u256 = Borrow(Mutable)(select test::Coin.0<&mut test::Coin>(self)); + p = Add(Deref(p), 1); + Tuple() + } + } + private fun inc_coin_at(addr: address) + acquires test::Coin(*) + { + { + let coin: &mut test::Coin = BorrowGlobal(Mutable)(addr); + { + let $t1: &mut u256 = Borrow(Mutable)(select test::Coin.0<&mut test::Coin>(coin)); + $t1 = Add(Deref($t1), 1) + }; + Tuple() + } + } + private fun inc_new(x: &mut u256) { + { + let $t1: &mut u256 = x; + $t1 = Add(Deref($t1), 1) + }; + Tuple() + } + private fun inc_old(x: &mut u256) { + x = Add(Deref(x), 1); + Tuple() + } + private fun inc_vec_coin_new(x: vector,index: u64) { + { + let $t1: &mut u256 = Borrow(Mutable)(select test::Coin.0(vector::borrow_mut(Borrow(Mutable)(x), index))); + $t1 = Add(Deref($t1), 1) + }; + Tuple() + } + private fun inc_vec_coin_old(x: vector,index: u64) { + select test::Coin.0(vector::borrow_mut(Borrow(Mutable)(x), index)) = Add(select test::Coin.0(vector::borrow(Borrow(Immutable)(x), index)), 1); + Tuple() + } + private fun inc_vec_new(x: &mut vector,index: u64) { + { + let $t1: &mut u256 = vector::borrow_mut(x, index); + $t1 = Add(Deref($t1), 1) + }; + Tuple() + } + private fun inc_vec_old(x: vector,index: u64) { + vector::borrow_mut(Borrow(Mutable)(x), index) = Add(Deref(vector::borrow(Borrow(Immutable)(x), index)), 1); + Tuple() + } + private fun inc_vec_wrapped_coin_new(x: vector>,index: u64) { + { + let $t1: &mut u256 = Borrow(Mutable)(select test::Coin.0(select test::Wrapper.0>(vector::borrow_mut>(Borrow(Mutable)(x), index)))); + $t1 = Add(Deref($t1), 1) + }; + Tuple() + } + private fun inc_vec_wrapped_coin_old(x: vector>,index: u64) { + select test::Coin.0(select test::Wrapper.0>(vector::borrow_mut>(Borrow(Mutable)(x), index))) = Add(select test::Coin.0(select test::Wrapper.0>(vector::borrow>(Borrow(Immutable)(x), index))), 1); + Tuple() + } + private fun inc_wrapped_coin_new(x: &mut test::Wrapper) { + { + let $t1: &mut u256 = Borrow(Mutable)(select test::Coin.0(select test::Wrapper.0<&mut test::Wrapper>(x))); + $t1 = Add(Deref($t1), 1) + }; + Tuple() + } + private fun inc_wrapped_coin_old(x: &mut test::Wrapper) { + select test::Coin.0(select test::Wrapper.0<&mut test::Wrapper>(x)) = Add(select test::Coin.0(select test::Wrapper.0<&mut test::Wrapper>(x)), 1); + Tuple() + } +} // end 0x42::test + +============ initial bytecode ================ + +[variant baseline] +fun test::add1_new($t0: u256): u256 { + var $t1: u256 + var $t2: u256 + var $t3: u256 + 0: $t3 := 1 + 1: $t2 := +($t0, $t3) + 2: $t0 := infer($t2) + 3: $t1 := infer($t0) + 4: return $t1 +} + + +[variant baseline] +fun test::add1_old($t0: u256): u256 { + var $t1: u256 + var $t2: u256 + var $t3: u256 + 0: $t3 := 1 + 1: $t2 := +($t0, $t3) + 2: $t0 := infer($t2) + 3: $t1 := infer($t0) + 4: return $t1 +} + + +[variant baseline] +fun test::coin_inc_new_1($t0: &mut test::Coin) { + var $t1: &mut u256 + var $t2: u256 + var $t3: u256 + var $t4: u256 + 0: $t1 := borrow_field.0($t0) + 1: $t3 := read_ref($t1) + 2: $t4 := 1 + 3: $t2 := +($t3, $t4) + 4: write_ref($t1, $t2) + 5: return () +} + + +[variant baseline] +fun test::coin_inc_new_2($t0: &mut test::Coin) { + var $t1: &mut u256 + var $t2: u256 + var $t3: u256 + var $t4: u256 + 0: $t1 := borrow_field.0($t0) + 1: $t3 := read_ref($t1) + 2: $t4 := 1 + 3: $t2 := +($t3, $t4) + 4: write_ref($t1, $t2) + 5: return () +} + + +[variant baseline] +fun test::coin_inc_old_1($t0: &mut test::Coin) { + var $t1: u256 + var $t2: u256 + var $t3: &u256 + var $t4: u256 + var $t5: &mut u256 + 0: $t3 := borrow_field.0($t0) + 1: $t2 := read_ref($t3) + 2: $t4 := 1 + 3: $t1 := +($t2, $t4) + 4: $t5 := borrow_field.0($t0) + 5: write_ref($t5, $t1) + 6: return () +} + + +[variant baseline] +fun test::coin_inc_old_2($t0: &mut test::Coin) { + var $t1: &mut u256 + var $t2: u256 + var $t3: u256 + var $t4: u256 + 0: $t1 := borrow_field.0($t0) + 1: $t3 := read_ref($t1) + 2: $t4 := 1 + 3: $t2 := +($t3, $t4) + 4: write_ref($t1, $t2) + 5: return () +} + + +[variant baseline] +fun test::inc_coin_at($t0: address) { + var $t1: &mut test::Coin + var $t2: &mut u256 + var $t3: u256 + var $t4: u256 + var $t5: u256 + 0: $t1 := borrow_global($t0) + 1: $t2 := borrow_field.0($t1) + 2: $t4 := read_ref($t2) + 3: $t5 := 1 + 4: $t3 := +($t4, $t5) + 5: write_ref($t2, $t3) + 6: return () +} + + +[variant baseline] +fun test::inc_new($t0: &mut u256) { + var $t1: &mut u256 + var $t2: u256 + var $t3: u256 + var $t4: u256 + 0: $t1 := infer($t0) + 1: $t3 := read_ref($t1) + 2: $t4 := 1 + 3: $t2 := +($t3, $t4) + 4: write_ref($t1, $t2) + 5: return () +} + + +[variant baseline] +fun test::inc_old($t0: &mut u256) { + var $t1: u256 + var $t2: u256 + var $t3: u256 + 0: $t2 := read_ref($t0) + 1: $t3 := 1 + 2: $t1 := +($t2, $t3) + 3: write_ref($t0, $t1) + 4: return () +} + + +[variant baseline] +fun test::inc_vec_coin_new($t0: vector, $t1: u64) { + var $t2: &mut u256 + var $t3: &mut test::Coin + var $t4: &mut vector + var $t5: u256 + var $t6: u256 + var $t7: u256 + 0: $t4 := borrow_local($t0) + 1: $t3 := vector::borrow_mut($t4, $t1) + 2: $t2 := borrow_field.0($t3) + 3: $t6 := read_ref($t2) + 4: $t7 := 1 + 5: $t5 := +($t6, $t7) + 6: write_ref($t2, $t5) + 7: return () +} + + +[variant baseline] +fun test::inc_vec_coin_old($t0: vector, $t1: u64) { + var $t2: u256 + var $t3: u256 + var $t4: &test::Coin + var $t5: &vector + var $t6: &u256 + var $t7: u256 + var $t8: &mut u256 + var $t9: &mut test::Coin + var $t10: &mut vector + 0: $t5 := borrow_local($t0) + 1: $t4 := vector::borrow($t5, $t1) + 2: $t6 := borrow_field.0($t4) + 3: $t3 := read_ref($t6) + 4: $t7 := 1 + 5: $t2 := +($t3, $t7) + 6: $t10 := borrow_local($t0) + 7: $t9 := vector::borrow_mut($t10, $t1) + 8: $t8 := borrow_field.0($t9) + 9: write_ref($t8, $t2) + 10: return () +} + + +[variant baseline] +fun test::inc_vec_new($t0: &mut vector, $t1: u64) { + var $t2: &mut u256 + var $t3: u256 + var $t4: u256 + var $t5: u256 + 0: $t2 := vector::borrow_mut($t0, $t1) + 1: $t4 := read_ref($t2) + 2: $t5 := 1 + 3: $t3 := +($t4, $t5) + 4: write_ref($t2, $t3) + 5: return () +} + + +[variant baseline] +fun test::inc_vec_old($t0: vector, $t1: u64) { + var $t2: u256 + var $t3: u256 + var $t4: &u256 + var $t5: &vector + var $t6: u256 + var $t7: &mut u256 + var $t8: &mut vector + 0: $t5 := borrow_local($t0) + 1: $t4 := vector::borrow($t5, $t1) + 2: $t3 := read_ref($t4) + 3: $t6 := 1 + 4: $t2 := +($t3, $t6) + 5: $t8 := borrow_local($t0) + 6: $t7 := vector::borrow_mut($t8, $t1) + 7: write_ref($t7, $t2) + 8: return () +} + + +[variant baseline] +fun test::inc_vec_wrapped_coin_new($t0: vector>, $t1: u64) { + var $t2: &mut u256 + var $t3: &mut test::Coin + var $t4: &mut test::Wrapper + var $t5: &mut vector> + var $t6: u256 + var $t7: u256 + var $t8: u256 + 0: $t5 := borrow_local($t0) + 1: $t4 := vector::borrow_mut>($t5, $t1) + 2: $t3 := borrow_field>.0($t4) + 3: $t2 := borrow_field.0($t3) + 4: $t7 := read_ref($t2) + 5: $t8 := 1 + 6: $t6 := +($t7, $t8) + 7: write_ref($t2, $t6) + 8: return () +} + + +[variant baseline] +fun test::inc_vec_wrapped_coin_old($t0: vector>, $t1: u64) { + var $t2: u256 + var $t3: u256 + var $t4: &test::Coin + var $t5: &test::Wrapper + var $t6: &vector> + var $t7: &u256 + var $t8: u256 + var $t9: &mut u256 + var $t10: &mut test::Coin + var $t11: &mut test::Wrapper + var $t12: &mut vector> + 0: $t6 := borrow_local($t0) + 1: $t5 := vector::borrow>($t6, $t1) + 2: $t4 := borrow_field>.0($t5) + 3: $t7 := borrow_field.0($t4) + 4: $t3 := read_ref($t7) + 5: $t8 := 1 + 6: $t2 := +($t3, $t8) + 7: $t12 := borrow_local($t0) + 8: $t11 := vector::borrow_mut>($t12, $t1) + 9: $t10 := borrow_field>.0($t11) + 10: $t9 := borrow_field.0($t10) + 11: write_ref($t9, $t2) + 12: return () +} + + +[variant baseline] +fun test::inc_wrapped_coin_new($t0: &mut test::Wrapper) { + var $t1: &mut u256 + var $t2: &mut test::Coin + var $t3: u256 + var $t4: u256 + var $t5: u256 + 0: $t2 := borrow_field>.0($t0) + 1: $t1 := borrow_field.0($t2) + 2: $t4 := read_ref($t1) + 3: $t5 := 1 + 4: $t3 := +($t4, $t5) + 5: write_ref($t1, $t3) + 6: return () +} + + +[variant baseline] +fun test::inc_wrapped_coin_old($t0: &mut test::Wrapper) { + var $t1: u256 + var $t2: u256 + var $t3: &test::Coin + var $t4: &u256 + var $t5: u256 + var $t6: &mut u256 + var $t7: &mut test::Coin + 0: $t3 := borrow_field>.0($t0) + 1: $t4 := borrow_field.0($t3) + 2: $t2 := read_ref($t4) + 3: $t5 := 1 + 4: $t1 := +($t2, $t5) + 5: $t7 := borrow_field>.0($t0) + 6: $t6 := borrow_field.0($t7) + 7: write_ref($t6, $t1) + 8: return () +} + +============ after LiveVarAnalysisProcessor: ================ + +[variant baseline] +fun test::add1_new($t0: u256): u256 { + var $t1: u256 [unused] + var $t2: u256 [unused] + var $t3: u256 + # live vars: $t0 + 0: $t3 := 1 + # live vars: $t0, $t3 + 1: $t3 := +($t0, $t3) + # live vars: $t3 + 2: $t0 := move($t3) + # live vars: $t0 + 3: return $t0 +} + + +[variant baseline] +fun test::add1_old($t0: u256): u256 { + var $t1: u256 [unused] + var $t2: u256 [unused] + var $t3: u256 + # live vars: $t0 + 0: $t3 := 1 + # live vars: $t0, $t3 + 1: $t3 := +($t0, $t3) + # live vars: $t3 + 2: $t0 := move($t3) + # live vars: $t0 + 3: return $t0 +} + + +[variant baseline] +fun test::coin_inc_new_1($t0: &mut test::Coin) { + var $t1: &mut u256 + var $t2: u256 [unused] + var $t3: u256 + var $t4: u256 + # live vars: $t0 + 0: $t1 := borrow_field.0($t0) + # live vars: $t1 + 1: $t3 := read_ref($t1) + # live vars: $t1, $t3 + 2: $t4 := 1 + # live vars: $t1, $t3, $t4 + 3: $t3 := +($t3, $t4) + # live vars: $t1, $t3 + 4: write_ref($t1, $t3) + # live vars: + 5: return () +} + + +[variant baseline] +fun test::coin_inc_new_2($t0: &mut test::Coin) { + var $t1: &mut u256 + var $t2: u256 [unused] + var $t3: u256 + var $t4: u256 + # live vars: $t0 + 0: $t1 := borrow_field.0($t0) + # live vars: $t1 + 1: $t3 := read_ref($t1) + # live vars: $t1, $t3 + 2: $t4 := 1 + # live vars: $t1, $t3, $t4 + 3: $t3 := +($t3, $t4) + # live vars: $t1, $t3 + 4: write_ref($t1, $t3) + # live vars: + 5: return () +} + + +[variant baseline] +fun test::coin_inc_old_1($t0: &mut test::Coin) { + var $t1: u256 [unused] + var $t2: u256 + var $t3: &u256 + var $t4: u256 + var $t5: &mut u256 + # live vars: $t0 + 0: $t3 := borrow_field.0($t0) + # live vars: $t0, $t3 + 1: $t2 := read_ref($t3) + # live vars: $t0, $t2 + 2: $t4 := 1 + # live vars: $t0, $t2, $t4 + 3: $t2 := +($t2, $t4) + # live vars: $t0, $t2 + 4: $t5 := borrow_field.0($t0) + # live vars: $t2, $t5 + 5: write_ref($t5, $t2) + # live vars: + 6: return () +} + + +[variant baseline] +fun test::coin_inc_old_2($t0: &mut test::Coin) { + var $t1: &mut u256 + var $t2: u256 [unused] + var $t3: u256 + var $t4: u256 + # live vars: $t0 + 0: $t1 := borrow_field.0($t0) + # live vars: $t1 + 1: $t3 := read_ref($t1) + # live vars: $t1, $t3 + 2: $t4 := 1 + # live vars: $t1, $t3, $t4 + 3: $t3 := +($t3, $t4) + # live vars: $t1, $t3 + 4: write_ref($t1, $t3) + # live vars: + 5: return () +} + + +[variant baseline] +fun test::inc_coin_at($t0: address) { + var $t1: &mut test::Coin + var $t2: &mut u256 + var $t3: u256 [unused] + var $t4: u256 + var $t5: u256 + # live vars: $t0 + 0: $t1 := borrow_global($t0) + # live vars: $t1 + 1: $t2 := borrow_field.0($t1) + # live vars: $t2 + 2: $t4 := read_ref($t2) + # live vars: $t2, $t4 + 3: $t5 := 1 + # live vars: $t2, $t4, $t5 + 4: $t4 := +($t4, $t5) + # live vars: $t2, $t4 + 5: write_ref($t2, $t4) + # live vars: + 6: return () +} + + +[variant baseline] +fun test::inc_new($t0: &mut u256) { + var $t1: &mut u256 [unused] + var $t2: u256 [unused] + var $t3: u256 + var $t4: u256 + # live vars: $t0 + 0: $t3 := read_ref($t0) + # live vars: $t0, $t3 + 1: $t4 := 1 + # live vars: $t0, $t3, $t4 + 2: $t3 := +($t3, $t4) + # live vars: $t0, $t3 + 3: write_ref($t0, $t3) + # live vars: + 4: return () +} + + +[variant baseline] +fun test::inc_old($t0: &mut u256) { + var $t1: u256 [unused] + var $t2: u256 + var $t3: u256 + # live vars: $t0 + 0: $t2 := read_ref($t0) + # live vars: $t0, $t2 + 1: $t3 := 1 + # live vars: $t0, $t2, $t3 + 2: $t2 := +($t2, $t3) + # live vars: $t0, $t2 + 3: write_ref($t0, $t2) + # live vars: + 4: return () +} + + +[variant baseline] +fun test::inc_vec_coin_new($t0: vector, $t1: u64) { + var $t2: &mut u256 + var $t3: &mut test::Coin + var $t4: &mut vector + var $t5: u256 [unused] + var $t6: u256 + var $t7: u256 + # live vars: $t0, $t1 + 0: $t4 := borrow_local($t0) + # live vars: $t1, $t4 + 1: $t3 := vector::borrow_mut($t4, $t1) + # live vars: $t3 + 2: $t2 := borrow_field.0($t3) + # live vars: $t2 + 3: $t6 := read_ref($t2) + # live vars: $t2, $t6 + 4: $t7 := 1 + # live vars: $t2, $t6, $t7 + 5: $t6 := +($t6, $t7) + # live vars: $t2, $t6 + 6: write_ref($t2, $t6) + # live vars: + 7: return () +} + + +[variant baseline] +fun test::inc_vec_coin_old($t0: vector, $t1: u64) { + var $t2: u256 [unused] + var $t3: u256 + var $t4: &test::Coin + var $t5: &vector + var $t6: &u256 + var $t7: u256 + var $t8: &mut u256 + var $t9: &mut test::Coin + var $t10: &mut vector + # live vars: $t0, $t1 + 0: $t5 := borrow_local($t0) + # live vars: $t0, $t1, $t5 + 1: $t4 := vector::borrow($t5, $t1) + # live vars: $t0, $t1, $t4 + 2: $t6 := borrow_field.0($t4) + # live vars: $t0, $t1, $t6 + 3: $t3 := read_ref($t6) + # live vars: $t0, $t1, $t3 + 4: $t7 := 1 + # live vars: $t0, $t1, $t3, $t7 + 5: $t3 := +($t3, $t7) + # live vars: $t0, $t1, $t3 + 6: $t10 := borrow_local($t0) + # live vars: $t1, $t3, $t10 + 7: $t9 := vector::borrow_mut($t10, $t1) + # live vars: $t3, $t9 + 8: $t8 := borrow_field.0($t9) + # live vars: $t3, $t8 + 9: write_ref($t8, $t3) + # live vars: + 10: return () +} + + +[variant baseline] +fun test::inc_vec_new($t0: &mut vector, $t1: u64) { + var $t2: &mut u256 + var $t3: u256 [unused] + var $t4: u256 + var $t5: u256 + # live vars: $t0, $t1 + 0: $t2 := vector::borrow_mut($t0, $t1) + # live vars: $t2 + 1: $t4 := read_ref($t2) + # live vars: $t2, $t4 + 2: $t5 := 1 + # live vars: $t2, $t4, $t5 + 3: $t4 := +($t4, $t5) + # live vars: $t2, $t4 + 4: write_ref($t2, $t4) + # live vars: + 5: return () +} + + +[variant baseline] +fun test::inc_vec_old($t0: vector, $t1: u64) { + var $t2: u256 [unused] + var $t3: u256 + var $t4: &u256 + var $t5: &vector + var $t6: u256 + var $t7: &mut u256 + var $t8: &mut vector + # live vars: $t0, $t1 + 0: $t5 := borrow_local($t0) + # live vars: $t0, $t1, $t5 + 1: $t4 := vector::borrow($t5, $t1) + # live vars: $t0, $t1, $t4 + 2: $t3 := read_ref($t4) + # live vars: $t0, $t1, $t3 + 3: $t6 := 1 + # live vars: $t0, $t1, $t3, $t6 + 4: $t3 := +($t3, $t6) + # live vars: $t0, $t1, $t3 + 5: $t8 := borrow_local($t0) + # live vars: $t1, $t3, $t8 + 6: $t7 := vector::borrow_mut($t8, $t1) + # live vars: $t3, $t7 + 7: write_ref($t7, $t3) + # live vars: + 8: return () +} + + +[variant baseline] +fun test::inc_vec_wrapped_coin_new($t0: vector>, $t1: u64) { + var $t2: &mut u256 + var $t3: &mut test::Coin + var $t4: &mut test::Wrapper + var $t5: &mut vector> + var $t6: u256 [unused] + var $t7: u256 + var $t8: u256 + # live vars: $t0, $t1 + 0: $t5 := borrow_local($t0) + # live vars: $t1, $t5 + 1: $t4 := vector::borrow_mut>($t5, $t1) + # live vars: $t4 + 2: $t3 := borrow_field>.0($t4) + # live vars: $t3 + 3: $t2 := borrow_field.0($t3) + # live vars: $t2 + 4: $t7 := read_ref($t2) + # live vars: $t2, $t7 + 5: $t8 := 1 + # live vars: $t2, $t7, $t8 + 6: $t7 := +($t7, $t8) + # live vars: $t2, $t7 + 7: write_ref($t2, $t7) + # live vars: + 8: return () +} + + +[variant baseline] +fun test::inc_vec_wrapped_coin_old($t0: vector>, $t1: u64) { + var $t2: u256 [unused] + var $t3: u256 + var $t4: &test::Coin + var $t5: &test::Wrapper + var $t6: &vector> + var $t7: &u256 + var $t8: u256 + var $t9: &mut u256 + var $t10: &mut test::Coin + var $t11: &mut test::Wrapper + var $t12: &mut vector> + # live vars: $t0, $t1 + 0: $t6 := borrow_local($t0) + # live vars: $t0, $t1, $t6 + 1: $t5 := vector::borrow>($t6, $t1) + # live vars: $t0, $t1, $t5 + 2: $t4 := borrow_field>.0($t5) + # live vars: $t0, $t1, $t4 + 3: $t7 := borrow_field.0($t4) + # live vars: $t0, $t1, $t7 + 4: $t3 := read_ref($t7) + # live vars: $t0, $t1, $t3 + 5: $t8 := 1 + # live vars: $t0, $t1, $t3, $t8 + 6: $t3 := +($t3, $t8) + # live vars: $t0, $t1, $t3 + 7: $t12 := borrow_local($t0) + # live vars: $t1, $t3, $t12 + 8: $t11 := vector::borrow_mut>($t12, $t1) + # live vars: $t3, $t11 + 9: $t10 := borrow_field>.0($t11) + # live vars: $t3, $t10 + 10: $t9 := borrow_field.0($t10) + # live vars: $t3, $t9 + 11: write_ref($t9, $t3) + # live vars: + 12: return () +} + + +[variant baseline] +fun test::inc_wrapped_coin_new($t0: &mut test::Wrapper) { + var $t1: &mut u256 + var $t2: &mut test::Coin + var $t3: u256 [unused] + var $t4: u256 + var $t5: u256 + # live vars: $t0 + 0: $t2 := borrow_field>.0($t0) + # live vars: $t2 + 1: $t1 := borrow_field.0($t2) + # live vars: $t1 + 2: $t4 := read_ref($t1) + # live vars: $t1, $t4 + 3: $t5 := 1 + # live vars: $t1, $t4, $t5 + 4: $t4 := +($t4, $t5) + # live vars: $t1, $t4 + 5: write_ref($t1, $t4) + # live vars: + 6: return () +} + + +[variant baseline] +fun test::inc_wrapped_coin_old($t0: &mut test::Wrapper) { + var $t1: u256 [unused] + var $t2: u256 + var $t3: &test::Coin + var $t4: &u256 + var $t5: u256 + var $t6: &mut u256 + var $t7: &mut test::Coin + # live vars: $t0 + 0: $t3 := borrow_field>.0($t0) + # live vars: $t0, $t3 + 1: $t4 := borrow_field.0($t3) + # live vars: $t0, $t4 + 2: $t2 := read_ref($t4) + # live vars: $t0, $t2 + 3: $t5 := 1 + # live vars: $t0, $t2, $t5 + 4: $t2 := +($t2, $t5) + # live vars: $t0, $t2 + 5: $t7 := borrow_field>.0($t0) + # live vars: $t2, $t7 + 6: $t6 := borrow_field.0($t7) + # live vars: $t2, $t6 + 7: write_ref($t6, $t2) + # live vars: + 8: return () +} + + +============ disassembled file-format ================== +// Move bytecode v7 +module 42.test { +struct Coin has drop, key { + _0: u256 +} +struct Wrapper has drop, key { + _0: Ty0 +} + +add1_new(Arg0: u256): u256 /* def_idx: 0 */ { +L1: loc0: u256 +B0: + 0: MoveLoc[0](Arg0: u256) + 1: LdU256(1) + 2: Add + 3: Ret +} +add1_old(Arg0: u256): u256 /* def_idx: 1 */ { +L1: loc0: u256 +B0: + 0: MoveLoc[0](Arg0: u256) + 1: LdU256(1) + 2: Add + 3: Ret +} +coin_inc_new_1(Arg0: &mut Coin) /* def_idx: 2 */ { +L1: loc0: &mut u256 +B0: + 0: MoveLoc[0](Arg0: &mut Coin) + 1: MutBorrowField[0](Coin._0: u256) + 2: StLoc[1](loc0: &mut u256) + 3: CopyLoc[1](loc0: &mut u256) + 4: ReadRef + 5: LdU256(1) + 6: Add + 7: MoveLoc[1](loc0: &mut u256) + 8: WriteRef + 9: Ret +} +coin_inc_new_2(Arg0: &mut Coin) /* def_idx: 3 */ { +L1: loc0: &mut u256 +B0: + 0: MoveLoc[0](Arg0: &mut Coin) + 1: MutBorrowField[0](Coin._0: u256) + 2: StLoc[1](loc0: &mut u256) + 3: CopyLoc[1](loc0: &mut u256) + 4: ReadRef + 5: LdU256(1) + 6: Add + 7: MoveLoc[1](loc0: &mut u256) + 8: WriteRef + 9: Ret +} +coin_inc_old_1(Arg0: &mut Coin) /* def_idx: 4 */ { +B0: + 0: CopyLoc[0](Arg0: &mut Coin) + 1: ImmBorrowField[0](Coin._0: u256) + 2: ReadRef + 3: LdU256(1) + 4: Add + 5: MoveLoc[0](Arg0: &mut Coin) + 6: MutBorrowField[0](Coin._0: u256) + 7: WriteRef + 8: Ret +} +coin_inc_old_2(Arg0: &mut Coin) /* def_idx: 5 */ { +L1: loc0: &mut u256 +B0: + 0: MoveLoc[0](Arg0: &mut Coin) + 1: MutBorrowField[0](Coin._0: u256) + 2: StLoc[1](loc0: &mut u256) + 3: CopyLoc[1](loc0: &mut u256) + 4: ReadRef + 5: LdU256(1) + 6: Add + 7: MoveLoc[1](loc0: &mut u256) + 8: WriteRef + 9: Ret +} +inc_coin_at(Arg0: address) /* def_idx: 6 */ { +L1: loc0: &mut u256 +B0: + 0: MoveLoc[0](Arg0: address) + 1: MutBorrowGlobal[0](Coin) + 2: MutBorrowField[0](Coin._0: u256) + 3: StLoc[1](loc0: &mut u256) + 4: CopyLoc[1](loc0: &mut u256) + 5: ReadRef + 6: LdU256(1) + 7: Add + 8: MoveLoc[1](loc0: &mut u256) + 9: WriteRef + 10: Ret +} +inc_new(Arg0: &mut u256) /* def_idx: 7 */ { +B0: + 0: CopyLoc[0](Arg0: &mut u256) + 1: ReadRef + 2: LdU256(1) + 3: Add + 4: MoveLoc[0](Arg0: &mut u256) + 5: WriteRef + 6: Ret +} +inc_old(Arg0: &mut u256) /* def_idx: 8 */ { +B0: + 0: CopyLoc[0](Arg0: &mut u256) + 1: ReadRef + 2: LdU256(1) + 3: Add + 4: MoveLoc[0](Arg0: &mut u256) + 5: WriteRef + 6: Ret +} +inc_vec_coin_new(Arg0: vector, Arg1: u64) /* def_idx: 9 */ { +L2: loc0: &mut u256 +B0: + 0: MutBorrowLoc[0](Arg0: vector) + 1: MoveLoc[1](Arg1: u64) + 2: VecMutBorrow(6) + 3: MutBorrowField[0](Coin._0: u256) + 4: StLoc[2](loc0: &mut u256) + 5: CopyLoc[2](loc0: &mut u256) + 6: ReadRef + 7: LdU256(1) + 8: Add + 9: MoveLoc[2](loc0: &mut u256) + 10: WriteRef + 11: Ret +} +inc_vec_coin_old(Arg0: vector, Arg1: u64) /* def_idx: 10 */ { +B0: + 0: ImmBorrowLoc[0](Arg0: vector) + 1: CopyLoc[1](Arg1: u64) + 2: VecImmBorrow(6) + 3: ImmBorrowField[0](Coin._0: u256) + 4: ReadRef + 5: LdU256(1) + 6: Add + 7: MutBorrowLoc[0](Arg0: vector) + 8: MoveLoc[1](Arg1: u64) + 9: VecMutBorrow(6) + 10: MutBorrowField[0](Coin._0: u256) + 11: WriteRef + 12: Ret +} +inc_vec_new(Arg0: &mut vector, Arg1: u64) /* def_idx: 11 */ { +L2: loc0: &mut u256 +B0: + 0: MoveLoc[0](Arg0: &mut vector) + 1: MoveLoc[1](Arg1: u64) + 2: VecMutBorrow(0) + 3: StLoc[2](loc0: &mut u256) + 4: CopyLoc[2](loc0: &mut u256) + 5: ReadRef + 6: LdU256(1) + 7: Add + 8: MoveLoc[2](loc0: &mut u256) + 9: WriteRef + 10: Ret +} +inc_vec_old(Arg0: vector, Arg1: u64) /* def_idx: 12 */ { +B0: + 0: ImmBorrowLoc[0](Arg0: vector) + 1: CopyLoc[1](Arg1: u64) + 2: VecImmBorrow(0) + 3: ReadRef + 4: LdU256(1) + 5: Add + 6: MutBorrowLoc[0](Arg0: vector) + 7: MoveLoc[1](Arg1: u64) + 8: VecMutBorrow(0) + 9: WriteRef + 10: Ret +} +inc_vec_wrapped_coin_new(Arg0: vector>, Arg1: u64) /* def_idx: 13 */ { +L2: loc0: &mut u256 +B0: + 0: MutBorrowLoc[0](Arg0: vector>) + 1: MoveLoc[1](Arg1: u64) + 2: VecMutBorrow(10) + 3: MutBorrowFieldGeneric[0](Wrapper._0: Ty0) + 4: MutBorrowField[0](Coin._0: u256) + 5: StLoc[2](loc0: &mut u256) + 6: CopyLoc[2](loc0: &mut u256) + 7: ReadRef + 8: LdU256(1) + 9: Add + 10: MoveLoc[2](loc0: &mut u256) + 11: WriteRef + 12: Ret +} +inc_vec_wrapped_coin_old(Arg0: vector>, Arg1: u64) /* def_idx: 14 */ { +B0: + 0: ImmBorrowLoc[0](Arg0: vector>) + 1: CopyLoc[1](Arg1: u64) + 2: VecImmBorrow(10) + 3: ImmBorrowFieldGeneric[0](Wrapper._0: Ty0) + 4: ImmBorrowField[0](Coin._0: u256) + 5: ReadRef + 6: LdU256(1) + 7: Add + 8: MutBorrowLoc[0](Arg0: vector>) + 9: MoveLoc[1](Arg1: u64) + 10: VecMutBorrow(10) + 11: MutBorrowFieldGeneric[0](Wrapper._0: Ty0) + 12: MutBorrowField[0](Coin._0: u256) + 13: WriteRef + 14: Ret +} +inc_wrapped_coin_new(Arg0: &mut Wrapper) /* def_idx: 15 */ { +L1: loc0: &mut u256 +B0: + 0: MoveLoc[0](Arg0: &mut Wrapper) + 1: MutBorrowFieldGeneric[0](Wrapper._0: Ty0) + 2: MutBorrowField[0](Coin._0: u256) + 3: StLoc[1](loc0: &mut u256) + 4: CopyLoc[1](loc0: &mut u256) + 5: ReadRef + 6: LdU256(1) + 7: Add + 8: MoveLoc[1](loc0: &mut u256) + 9: WriteRef + 10: Ret +} +inc_wrapped_coin_old(Arg0: &mut Wrapper) /* def_idx: 16 */ { +B0: + 0: CopyLoc[0](Arg0: &mut Wrapper) + 1: ImmBorrowFieldGeneric[0](Wrapper._0: Ty0) + 2: ImmBorrowField[0](Coin._0: u256) + 3: ReadRef + 4: LdU256(1) + 5: Add + 6: MoveLoc[0](Arg0: &mut Wrapper) + 7: MutBorrowFieldGeneric[0](Wrapper._0: Ty0) + 8: MutBorrowField[0](Coin._0: u256) + 9: WriteRef + 10: Ret +} +} +============ bytecode verification succeeded ======== diff --git a/third_party/move/move-compiler-v2/tests/op-equal/valid0.move b/third_party/move/move-compiler-v2/tests/op-equal/valid0.move new file mode 100644 index 0000000000000..329e680102db5 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/op-equal/valid0.move @@ -0,0 +1,78 @@ +module 0x42::test { + struct Coin(u256) has drop, key; + + struct Wrapper(T) has drop, key; + + fun add1_old(x: u256): u256 { + x = x + 1; + x + } + + fun add1_new(x: u256): u256 { + x += 1; + x + } + + fun inc_new(x: &mut u256) { + *x += 1; + } + + fun inc_old(x: &mut u256) { + *x = *x + 1; + } + + fun coin_inc_new_1(self: &mut Coin) { + self.0 += 1; + } + + fun coin_inc_new_2(self: &mut Coin) { + let p = &mut self.0; + *p = *p + 1; + } + + fun coin_inc_old_1(self: &mut Coin) { + self.0 = self.0 + 1; + } + + fun coin_inc_old_2(self: &mut Coin) { + let p = &mut self.0; + *p = *p + 1; + } + + fun inc_wrapped_coin_new(x: &mut Wrapper) { + x.0.0 += 1; + } + + fun inc_wrapped_coin_old(x: &mut Wrapper) { + x.0.0 = x.0.0 + 1; + } + + fun inc_vec_new(x: &mut vector, index: u64) { + x[index] += 1; + } + + fun inc_vec_old(x: vector, index: u64) { + x[index] = x[index] + 1; + } + + fun inc_vec_coin_new(x: vector, index: u64) { + x[index].0 += 1; + } + + fun inc_vec_coin_old(x: vector, index: u64) { + x[index].0 = x[index].0 + 1; + } + + fun inc_vec_wrapped_coin_new(x: vector>, index: u64) { + x[index].0.0 += 1; + } + + fun inc_vec_wrapped_coin_old(x: vector>, index: u64) { + x[index].0.0 = x[index].0.0 + 1; + } + + fun inc_coin_at(addr: address) acquires Coin { + let coin = &mut Coin[addr]; + coin.0 += 1; + } +} diff --git a/third_party/move/move-compiler-v2/tests/op-equal/valid1.exp b/third_party/move/move-compiler-v2/tests/op-equal/valid1.exp new file mode 100644 index 0000000000000..e6a3ff288eab3 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/op-equal/valid1.exp @@ -0,0 +1,598 @@ +// -- Model dump before bytecode pipeline +module 0x42::test { + struct Coin { + 0: u256, + } + struct Wrapper { + 0: #0, + } + private fun bitand_vec_coin_new(x: vector,index: u64) { + { + let $t1: &mut u256 = Borrow(Mutable)(select test::Coin.0(vector::borrow_mut(Borrow(Mutable)(x), index))); + $t1 = BitAnd(Deref($t1), 42) + }; + Tuple() + } + private fun bitor_vec_new(x: &mut vector,index: u64) { + { + let $t1: &mut u256 = vector::borrow_mut(x, index); + $t1 = BitOr(Deref($t1), 42) + }; + Tuple() + } + private fun coin_double(self: &mut test::Coin) { + { + let $t1: &mut u256 = Borrow(Mutable)(select test::Coin.0<&mut test::Coin>(self)); + $t1 = Mul(Deref($t1), 2) + }; + Tuple() + } + private fun coin_mod_2(self: &mut test::Coin) { + { + let $t1: &mut u256 = Borrow(Mutable)(select test::Coin.0<&mut test::Coin>(self)); + $t1 = Mod(Deref($t1), 2) + }; + Tuple() + } + private fun half_wrapped_coin_new(x: &mut test::Wrapper) { + { + let $t1: &mut u256 = Borrow(Mutable)(select test::Coin.0(select test::Wrapper.0<&mut test::Wrapper>(x))); + $t1 = Div(Deref($t1), 2) + }; + Tuple() + } + private fun shl_vec_wrapped_coin_old(x: vector>,index: u64) { + { + let $t1: &mut u256 = Borrow(Mutable)(select test::Coin.0(select test::Wrapper.0>(vector::borrow_mut>(Borrow(Mutable)(x), index)))); + $t1 = Shl(Deref($t1), 1) + }; + Tuple() + } + private fun shr_coin_at(addr: address) + acquires test::Coin(*) + { + { + let coin: &mut test::Coin = BorrowGlobal(Mutable)(addr); + { + let $t1: &mut u256 = Borrow(Mutable)(select test::Coin.0<&mut test::Coin>(coin)); + $t1 = Shr(Deref($t1), 1) + }; + Tuple() + } + } + private fun sub1(x: &mut u256) { + { + let $t1: &mut u256 = x; + $t1 = Sub(Deref($t1), 1) + }; + Tuple() + } + private fun xor_vec_wrapped_coin_new(x: vector>,index: u64) { + { + let $t1: &mut u256 = Borrow(Mutable)(select test::Coin.0(select test::Wrapper.0>(vector::borrow_mut>(Borrow(Mutable)(x), index)))); + $t1 = Xor(Deref($t1), 1) + }; + Tuple() + } +} // end 0x42::test + +============ initial bytecode ================ + +[variant baseline] +fun test::bitand_vec_coin_new($t0: vector, $t1: u64) { + var $t2: &mut u256 + var $t3: &mut test::Coin + var $t4: &mut vector + var $t5: u256 + var $t6: u256 + var $t7: u256 + 0: $t4 := borrow_local($t0) + 1: $t3 := vector::borrow_mut($t4, $t1) + 2: $t2 := borrow_field.0($t3) + 3: $t6 := read_ref($t2) + 4: $t7 := 42 + 5: $t5 := &($t6, $t7) + 6: write_ref($t2, $t5) + 7: return () +} + + +[variant baseline] +fun test::bitor_vec_new($t0: &mut vector, $t1: u64) { + var $t2: &mut u256 + var $t3: u256 + var $t4: u256 + var $t5: u256 + 0: $t2 := vector::borrow_mut($t0, $t1) + 1: $t4 := read_ref($t2) + 2: $t5 := 42 + 3: $t3 := |($t4, $t5) + 4: write_ref($t2, $t3) + 5: return () +} + + +[variant baseline] +fun test::coin_double($t0: &mut test::Coin) { + var $t1: &mut u256 + var $t2: u256 + var $t3: u256 + var $t4: u256 + 0: $t1 := borrow_field.0($t0) + 1: $t3 := read_ref($t1) + 2: $t4 := 2 + 3: $t2 := *($t3, $t4) + 4: write_ref($t1, $t2) + 5: return () +} + + +[variant baseline] +fun test::coin_mod_2($t0: &mut test::Coin) { + var $t1: &mut u256 + var $t2: u256 + var $t3: u256 + var $t4: u256 + 0: $t1 := borrow_field.0($t0) + 1: $t3 := read_ref($t1) + 2: $t4 := 2 + 3: $t2 := %($t3, $t4) + 4: write_ref($t1, $t2) + 5: return () +} + + +[variant baseline] +fun test::half_wrapped_coin_new($t0: &mut test::Wrapper) { + var $t1: &mut u256 + var $t2: &mut test::Coin + var $t3: u256 + var $t4: u256 + var $t5: u256 + 0: $t2 := borrow_field>.0($t0) + 1: $t1 := borrow_field.0($t2) + 2: $t4 := read_ref($t1) + 3: $t5 := 2 + 4: $t3 := /($t4, $t5) + 5: write_ref($t1, $t3) + 6: return () +} + + +[variant baseline] +fun test::shl_vec_wrapped_coin_old($t0: vector>, $t1: u64) { + var $t2: &mut u256 + var $t3: &mut test::Coin + var $t4: &mut test::Wrapper + var $t5: &mut vector> + var $t6: u256 + var $t7: u256 + var $t8: u8 + 0: $t5 := borrow_local($t0) + 1: $t4 := vector::borrow_mut>($t5, $t1) + 2: $t3 := borrow_field>.0($t4) + 3: $t2 := borrow_field.0($t3) + 4: $t7 := read_ref($t2) + 5: $t8 := 1 + 6: $t6 := <<($t7, $t8) + 7: write_ref($t2, $t6) + 8: return () +} + + +[variant baseline] +fun test::shr_coin_at($t0: address) { + var $t1: &mut test::Coin + var $t2: &mut u256 + var $t3: u256 + var $t4: u256 + var $t5: u8 + 0: $t1 := borrow_global($t0) + 1: $t2 := borrow_field.0($t1) + 2: $t4 := read_ref($t2) + 3: $t5 := 1 + 4: $t3 := >>($t4, $t5) + 5: write_ref($t2, $t3) + 6: return () +} + + +[variant baseline] +fun test::sub1($t0: &mut u256) { + var $t1: &mut u256 + var $t2: u256 + var $t3: u256 + var $t4: u256 + 0: $t1 := infer($t0) + 1: $t3 := read_ref($t1) + 2: $t4 := 1 + 3: $t2 := -($t3, $t4) + 4: write_ref($t1, $t2) + 5: return () +} + + +[variant baseline] +fun test::xor_vec_wrapped_coin_new($t0: vector>, $t1: u64) { + var $t2: &mut u256 + var $t3: &mut test::Coin + var $t4: &mut test::Wrapper + var $t5: &mut vector> + var $t6: u256 + var $t7: u256 + var $t8: u256 + 0: $t5 := borrow_local($t0) + 1: $t4 := vector::borrow_mut>($t5, $t1) + 2: $t3 := borrow_field>.0($t4) + 3: $t2 := borrow_field.0($t3) + 4: $t7 := read_ref($t2) + 5: $t8 := 1 + 6: $t6 := ^($t7, $t8) + 7: write_ref($t2, $t6) + 8: return () +} + +============ after LiveVarAnalysisProcessor: ================ + +[variant baseline] +fun test::bitand_vec_coin_new($t0: vector, $t1: u64) { + var $t2: &mut u256 + var $t3: &mut test::Coin + var $t4: &mut vector + var $t5: u256 [unused] + var $t6: u256 + var $t7: u256 + # live vars: $t0, $t1 + 0: $t4 := borrow_local($t0) + # live vars: $t1, $t4 + 1: $t3 := vector::borrow_mut($t4, $t1) + # live vars: $t3 + 2: $t2 := borrow_field.0($t3) + # live vars: $t2 + 3: $t6 := read_ref($t2) + # live vars: $t2, $t6 + 4: $t7 := 42 + # live vars: $t2, $t6, $t7 + 5: $t6 := &($t6, $t7) + # live vars: $t2, $t6 + 6: write_ref($t2, $t6) + # live vars: + 7: return () +} + + +[variant baseline] +fun test::bitor_vec_new($t0: &mut vector, $t1: u64) { + var $t2: &mut u256 + var $t3: u256 [unused] + var $t4: u256 + var $t5: u256 + # live vars: $t0, $t1 + 0: $t2 := vector::borrow_mut($t0, $t1) + # live vars: $t2 + 1: $t4 := read_ref($t2) + # live vars: $t2, $t4 + 2: $t5 := 42 + # live vars: $t2, $t4, $t5 + 3: $t4 := |($t4, $t5) + # live vars: $t2, $t4 + 4: write_ref($t2, $t4) + # live vars: + 5: return () +} + + +[variant baseline] +fun test::coin_double($t0: &mut test::Coin) { + var $t1: &mut u256 + var $t2: u256 [unused] + var $t3: u256 + var $t4: u256 + # live vars: $t0 + 0: $t1 := borrow_field.0($t0) + # live vars: $t1 + 1: $t3 := read_ref($t1) + # live vars: $t1, $t3 + 2: $t4 := 2 + # live vars: $t1, $t3, $t4 + 3: $t3 := *($t3, $t4) + # live vars: $t1, $t3 + 4: write_ref($t1, $t3) + # live vars: + 5: return () +} + + +[variant baseline] +fun test::coin_mod_2($t0: &mut test::Coin) { + var $t1: &mut u256 + var $t2: u256 [unused] + var $t3: u256 + var $t4: u256 + # live vars: $t0 + 0: $t1 := borrow_field.0($t0) + # live vars: $t1 + 1: $t3 := read_ref($t1) + # live vars: $t1, $t3 + 2: $t4 := 2 + # live vars: $t1, $t3, $t4 + 3: $t3 := %($t3, $t4) + # live vars: $t1, $t3 + 4: write_ref($t1, $t3) + # live vars: + 5: return () +} + + +[variant baseline] +fun test::half_wrapped_coin_new($t0: &mut test::Wrapper) { + var $t1: &mut u256 + var $t2: &mut test::Coin + var $t3: u256 [unused] + var $t4: u256 + var $t5: u256 + # live vars: $t0 + 0: $t2 := borrow_field>.0($t0) + # live vars: $t2 + 1: $t1 := borrow_field.0($t2) + # live vars: $t1 + 2: $t4 := read_ref($t1) + # live vars: $t1, $t4 + 3: $t5 := 2 + # live vars: $t1, $t4, $t5 + 4: $t4 := /($t4, $t5) + # live vars: $t1, $t4 + 5: write_ref($t1, $t4) + # live vars: + 6: return () +} + + +[variant baseline] +fun test::shl_vec_wrapped_coin_old($t0: vector>, $t1: u64) { + var $t2: &mut u256 + var $t3: &mut test::Coin + var $t4: &mut test::Wrapper + var $t5: &mut vector> + var $t6: u256 [unused] + var $t7: u256 + var $t8: u8 + # live vars: $t0, $t1 + 0: $t5 := borrow_local($t0) + # live vars: $t1, $t5 + 1: $t4 := vector::borrow_mut>($t5, $t1) + # live vars: $t4 + 2: $t3 := borrow_field>.0($t4) + # live vars: $t3 + 3: $t2 := borrow_field.0($t3) + # live vars: $t2 + 4: $t7 := read_ref($t2) + # live vars: $t2, $t7 + 5: $t8 := 1 + # live vars: $t2, $t7, $t8 + 6: $t7 := <<($t7, $t8) + # live vars: $t2, $t7 + 7: write_ref($t2, $t7) + # live vars: + 8: return () +} + + +[variant baseline] +fun test::shr_coin_at($t0: address) { + var $t1: &mut test::Coin + var $t2: &mut u256 + var $t3: u256 [unused] + var $t4: u256 + var $t5: u8 + # live vars: $t0 + 0: $t1 := borrow_global($t0) + # live vars: $t1 + 1: $t2 := borrow_field.0($t1) + # live vars: $t2 + 2: $t4 := read_ref($t2) + # live vars: $t2, $t4 + 3: $t5 := 1 + # live vars: $t2, $t4, $t5 + 4: $t4 := >>($t4, $t5) + # live vars: $t2, $t4 + 5: write_ref($t2, $t4) + # live vars: + 6: return () +} + + +[variant baseline] +fun test::sub1($t0: &mut u256) { + var $t1: &mut u256 [unused] + var $t2: u256 [unused] + var $t3: u256 + var $t4: u256 + # live vars: $t0 + 0: $t3 := read_ref($t0) + # live vars: $t0, $t3 + 1: $t4 := 1 + # live vars: $t0, $t3, $t4 + 2: $t3 := -($t3, $t4) + # live vars: $t0, $t3 + 3: write_ref($t0, $t3) + # live vars: + 4: return () +} + + +[variant baseline] +fun test::xor_vec_wrapped_coin_new($t0: vector>, $t1: u64) { + var $t2: &mut u256 + var $t3: &mut test::Coin + var $t4: &mut test::Wrapper + var $t5: &mut vector> + var $t6: u256 [unused] + var $t7: u256 + var $t8: u256 + # live vars: $t0, $t1 + 0: $t5 := borrow_local($t0) + # live vars: $t1, $t5 + 1: $t4 := vector::borrow_mut>($t5, $t1) + # live vars: $t4 + 2: $t3 := borrow_field>.0($t4) + # live vars: $t3 + 3: $t2 := borrow_field.0($t3) + # live vars: $t2 + 4: $t7 := read_ref($t2) + # live vars: $t2, $t7 + 5: $t8 := 1 + # live vars: $t2, $t7, $t8 + 6: $t7 := ^($t7, $t8) + # live vars: $t2, $t7 + 7: write_ref($t2, $t7) + # live vars: + 8: return () +} + + +============ disassembled file-format ================== +// Move bytecode v7 +module 42.test { +struct Coin has drop, key { + _0: u256 +} +struct Wrapper has drop, key { + _0: Ty0 +} + +bitand_vec_coin_new(Arg0: vector, Arg1: u64) /* def_idx: 0 */ { +L2: loc0: &mut u256 +B0: + 0: MutBorrowLoc[0](Arg0: vector) + 1: MoveLoc[1](Arg1: u64) + 2: VecMutBorrow(2) + 3: MutBorrowField[0](Coin._0: u256) + 4: StLoc[2](loc0: &mut u256) + 5: CopyLoc[2](loc0: &mut u256) + 6: ReadRef + 7: LdU256(42) + 8: BitAnd + 9: MoveLoc[2](loc0: &mut u256) + 10: WriteRef + 11: Ret +} +bitor_vec_new(Arg0: &mut vector, Arg1: u64) /* def_idx: 1 */ { +L2: loc0: &mut u256 +B0: + 0: MoveLoc[0](Arg0: &mut vector) + 1: MoveLoc[1](Arg1: u64) + 2: VecMutBorrow(5) + 3: StLoc[2](loc0: &mut u256) + 4: CopyLoc[2](loc0: &mut u256) + 5: ReadRef + 6: LdU256(42) + 7: BitOr + 8: MoveLoc[2](loc0: &mut u256) + 9: WriteRef + 10: Ret +} +coin_double(Arg0: &mut Coin) /* def_idx: 2 */ { +L1: loc0: &mut u256 +B0: + 0: MoveLoc[0](Arg0: &mut Coin) + 1: MutBorrowField[0](Coin._0: u256) + 2: StLoc[1](loc0: &mut u256) + 3: CopyLoc[1](loc0: &mut u256) + 4: ReadRef + 5: LdU256(2) + 6: Mul + 7: MoveLoc[1](loc0: &mut u256) + 8: WriteRef + 9: Ret +} +coin_mod_2(Arg0: &mut Coin) /* def_idx: 3 */ { +L1: loc0: &mut u256 +B0: + 0: MoveLoc[0](Arg0: &mut Coin) + 1: MutBorrowField[0](Coin._0: u256) + 2: StLoc[1](loc0: &mut u256) + 3: CopyLoc[1](loc0: &mut u256) + 4: ReadRef + 5: LdU256(2) + 6: Mod + 7: MoveLoc[1](loc0: &mut u256) + 8: WriteRef + 9: Ret +} +half_wrapped_coin_new(Arg0: &mut Wrapper) /* def_idx: 4 */ { +L1: loc0: &mut u256 +B0: + 0: MoveLoc[0](Arg0: &mut Wrapper) + 1: MutBorrowFieldGeneric[0](Wrapper._0: Ty0) + 2: MutBorrowField[0](Coin._0: u256) + 3: StLoc[1](loc0: &mut u256) + 4: CopyLoc[1](loc0: &mut u256) + 5: ReadRef + 6: LdU256(2) + 7: Div + 8: MoveLoc[1](loc0: &mut u256) + 9: WriteRef + 10: Ret +} +shl_vec_wrapped_coin_old(Arg0: vector>, Arg1: u64) /* def_idx: 5 */ { +L2: loc0: &mut u256 +B0: + 0: MutBorrowLoc[0](Arg0: vector>) + 1: MoveLoc[1](Arg1: u64) + 2: VecMutBorrow(9) + 3: MutBorrowFieldGeneric[0](Wrapper._0: Ty0) + 4: MutBorrowField[0](Coin._0: u256) + 5: StLoc[2](loc0: &mut u256) + 6: CopyLoc[2](loc0: &mut u256) + 7: ReadRef + 8: LdU8(1) + 9: Shl + 10: MoveLoc[2](loc0: &mut u256) + 11: WriteRef + 12: Ret +} +shr_coin_at(Arg0: address) /* def_idx: 6 */ { +L1: loc0: &mut u256 +B0: + 0: MoveLoc[0](Arg0: address) + 1: MutBorrowGlobal[0](Coin) + 2: MutBorrowField[0](Coin._0: u256) + 3: StLoc[1](loc0: &mut u256) + 4: CopyLoc[1](loc0: &mut u256) + 5: ReadRef + 6: LdU8(1) + 7: Shr + 8: MoveLoc[1](loc0: &mut u256) + 9: WriteRef + 10: Ret +} +sub1(Arg0: &mut u256) /* def_idx: 7 */ { +B0: + 0: CopyLoc[0](Arg0: &mut u256) + 1: ReadRef + 2: LdU256(1) + 3: Sub + 4: MoveLoc[0](Arg0: &mut u256) + 5: WriteRef + 6: Ret +} +xor_vec_wrapped_coin_new(Arg0: vector>, Arg1: u64) /* def_idx: 8 */ { +L2: loc0: &mut u256 +B0: + 0: MutBorrowLoc[0](Arg0: vector>) + 1: MoveLoc[1](Arg1: u64) + 2: VecMutBorrow(9) + 3: MutBorrowFieldGeneric[0](Wrapper._0: Ty0) + 4: MutBorrowField[0](Coin._0: u256) + 5: StLoc[2](loc0: &mut u256) + 6: CopyLoc[2](loc0: &mut u256) + 7: ReadRef + 8: LdU256(1) + 9: Xor + 10: MoveLoc[2](loc0: &mut u256) + 11: WriteRef + 12: Ret +} +} +============ bytecode verification succeeded ======== diff --git a/third_party/move/move-compiler-v2/tests/op-equal/valid1.move b/third_party/move/move-compiler-v2/tests/op-equal/valid1.move new file mode 100644 index 0000000000000..0ddf501781519 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/op-equal/valid1.move @@ -0,0 +1,42 @@ +module 0x42::test { + struct Coin(u256) has drop, key; + + struct Wrapper(T) has drop, key; + + fun sub1(x: &mut u256) { + *x -= 1; + } + + fun coin_double(self: &mut Coin) { + self.0 *= 2; + } + + fun coin_mod_2(self: &mut Coin) { + self.0 %= 2; + } + + fun half_wrapped_coin_new(x: &mut Wrapper) { + x.0.0 /= 2; + } + + fun bitor_vec_new(x: &mut vector, index: u64) { + x[index] |= 42; + } + + fun bitand_vec_coin_new(x: vector, index: u64) { + x[index].0 &= 42; + } + + fun xor_vec_wrapped_coin_new(x: vector>, index: u64) { + x[index].0.0 ^= 1; + } + + fun shl_vec_wrapped_coin_old(x: vector>, index: u64) { + x[index].0.0 <<= 1; + } + + fun shr_coin_at(addr: address) acquires Coin { + let coin = &mut Coin[addr]; + coin.0 >>= 1; + } +} diff --git a/third_party/move/move-compiler-v2/tests/op-equal/valid2.exp b/third_party/move/move-compiler-v2/tests/op-equal/valid2.exp new file mode 100644 index 0000000000000..772a9507ed263 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/op-equal/valid2.exp @@ -0,0 +1,191 @@ +// -- Model dump before bytecode pipeline +module 0xc0ffee::m { + struct S { + x: u64, + } + private fun foo(self: &mut m::S): u64 { + { + let $t1: &mut u64 = Borrow(Mutable)(select m::S.x<&mut m::S>(self)); + $t1 = Add(Deref($t1), 1) + }; + 1 + } + public fun test(): u64 { + { + let s: m::S = pack m::S(0); + { + let $t2: u64 = m::foo(Borrow(Mutable)(s)); + { + let $t1: &mut u64 = Borrow(Mutable)(select m::S.x(s)); + $t1 = Add(Deref($t1), $t2) + } + }; + select m::S.x(s) + } + } +} // end 0xc0ffee::m + +============ initial bytecode ================ + +[variant baseline] +fun m::foo($t0: &mut m::S): u64 { + var $t1: u64 + var $t2: &mut u64 + var $t3: u64 + var $t4: u64 + var $t5: u64 + 0: $t2 := borrow_field.x($t0) + 1: $t4 := read_ref($t2) + 2: $t5 := 1 + 3: $t3 := +($t4, $t5) + 4: write_ref($t2, $t3) + 5: $t1 := 1 + 6: return $t1 +} + + +[variant baseline] +public fun m::test(): u64 { + var $t0: u64 + var $t1: m::S + var $t2: u64 + var $t3: u64 + var $t4: &mut m::S + var $t5: &mut u64 + var $t6: &mut m::S + var $t7: u64 + var $t8: u64 + var $t9: &m::S + var $t10: &u64 + 0: $t2 := 0 + 1: $t1 := pack m::S($t2) + 2: $t4 := borrow_local($t1) + 3: $t3 := m::foo($t4) + 4: $t6 := borrow_local($t1) + 5: $t5 := borrow_field.x($t6) + 6: $t8 := read_ref($t5) + 7: $t7 := +($t8, $t3) + 8: write_ref($t5, $t7) + 9: $t9 := borrow_local($t1) + 10: $t10 := borrow_field.x($t9) + 11: $t0 := read_ref($t10) + 12: return $t0 +} + +============ after LiveVarAnalysisProcessor: ================ + +[variant baseline] +fun m::foo($t0: &mut m::S): u64 { + var $t1: u64 [unused] + var $t2: &mut u64 + var $t3: u64 [unused] + var $t4: u64 + var $t5: u64 + # live vars: $t0 + 0: $t2 := borrow_field.x($t0) + # live vars: $t2 + 1: $t4 := read_ref($t2) + # live vars: $t2, $t4 + 2: $t5 := 1 + # live vars: $t2, $t4, $t5 + 3: $t4 := +($t4, $t5) + # live vars: $t2, $t4 + 4: write_ref($t2, $t4) + # live vars: + 5: $t4 := 1 + # live vars: $t4 + 6: return $t4 +} + + +[variant baseline] +public fun m::test(): u64 { + var $t0: u64 [unused] + var $t1: m::S + var $t2: u64 + var $t3: u64 [unused] + var $t4: &mut m::S + var $t5: &mut u64 + var $t6: &mut m::S [unused] + var $t7: u64 [unused] + var $t8: u64 + var $t9: &m::S + var $t10: &u64 + # live vars: + 0: $t2 := 0 + # live vars: $t2 + 1: $t1 := pack m::S($t2) + # live vars: $t1 + 2: $t4 := borrow_local($t1) + # live vars: $t1, $t4 + 3: $t2 := m::foo($t4) + # live vars: $t1, $t2 + 4: $t4 := borrow_local($t1) + # live vars: $t1, $t2, $t4 + 5: $t5 := borrow_field.x($t4) + # live vars: $t1, $t2, $t5 + 6: $t8 := read_ref($t5) + # live vars: $t1, $t2, $t5, $t8 + 7: $t2 := +($t8, $t2) + # live vars: $t1, $t2, $t5 + 8: write_ref($t5, $t2) + # live vars: $t1 + 9: $t9 := borrow_local($t1) + # live vars: $t9 + 10: $t10 := borrow_field.x($t9) + # live vars: $t10 + 11: $t2 := read_ref($t10) + # live vars: $t2 + 12: return $t2 +} + + +============ disassembled file-format ================== +// Move bytecode v7 +module c0ffee.m { +struct S has drop { + x: u64 +} + +foo(Arg0: &mut S): u64 /* def_idx: 0 */ { +L1: loc0: &mut u64 +B0: + 0: MoveLoc[0](Arg0: &mut S) + 1: MutBorrowField[0](S.x: u64) + 2: StLoc[1](loc0: &mut u64) + 3: CopyLoc[1](loc0: &mut u64) + 4: ReadRef + 5: LdU64(1) + 6: Add + 7: MoveLoc[1](loc0: &mut u64) + 8: WriteRef + 9: LdU64(1) + 10: Ret +} +public test(): u64 /* def_idx: 1 */ { +L0: loc0: S +L1: loc1: u64 +L2: loc2: &mut u64 +B0: + 0: LdU64(0) + 1: Pack[0](S) + 2: StLoc[0](loc0: S) + 3: MutBorrowLoc[0](loc0: S) + 4: Call foo(&mut S): u64 + 5: StLoc[1](loc1: u64) + 6: MutBorrowLoc[0](loc0: S) + 7: MutBorrowField[0](S.x: u64) + 8: StLoc[2](loc2: &mut u64) + 9: CopyLoc[2](loc2: &mut u64) + 10: ReadRef + 11: MoveLoc[1](loc1: u64) + 12: Add + 13: MoveLoc[2](loc2: &mut u64) + 14: WriteRef + 15: ImmBorrowLoc[0](loc0: S) + 16: ImmBorrowField[0](S.x: u64) + 17: ReadRef + 18: Ret +} +} +============ bytecode verification succeeded ======== diff --git a/third_party/move/move-compiler-v2/tests/op-equal/valid2.move b/third_party/move/move-compiler-v2/tests/op-equal/valid2.move new file mode 100644 index 0000000000000..2d6ca0632dd4f --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/op-equal/valid2.move @@ -0,0 +1,16 @@ +module 0xc0ffee::m { + struct S has drop { + x: u64, + } + + fun foo(self: &mut S): u64 { + self.x += 1; + 1 + } + + public fun test(): u64 { + let s = S { x: 0 }; + s.x += s.foo(); + s.x + } +} diff --git a/third_party/move/move-compiler-v2/tests/testsuite.rs b/third_party/move/move-compiler-v2/tests/testsuite.rs index 850dd563cc379..bbc988185007a 100644 --- a/third_party/move/move-compiler-v2/tests/testsuite.rs +++ b/third_party/move/move-compiler-v2/tests/testsuite.rs @@ -717,6 +717,19 @@ const TEST_CONFIGS: Lazy> = Lazy::new(|| { dump_bytecode: DumpLevel::EndStage, dump_bytecode_filter: Some(vec![FILE_FORMAT_STAGE]), }, + TestConfig { + name: "op-equal", + runner: |p| run_test(p, get_config_by_name("op-equal")), + include: vec!["/op-equal/"], + exclude: vec![], + exp_suffix: None, + options: opts.clone().set_language_version(LanguageVersion::V2_1), + // Run the entire compiler pipeline to double-check the result + stop_after: StopAfter::FileFormat, + dump_ast: DumpLevel::EndStage, + dump_bytecode: DumpLevel::EndStage, + dump_bytecode_filter: None, + }, ]; configs.into_iter().map(|c| (c.name, c)).collect() }); diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/op_equal/eval_order.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/op_equal/eval_order.exp new file mode 100644 index 0000000000000..2301000e50ae4 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/op_equal/eval_order.exp @@ -0,0 +1 @@ +processed 6 tasks diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/op_equal/eval_order.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/op_equal/eval_order.move new file mode 100644 index 0000000000000..3629bf1b1ae26 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/op_equal/eval_order.move @@ -0,0 +1,52 @@ +//# publish +module 0xc0ffee::m { + public fun test0() { + let v = 1; + v += {v += {v += 2; v}; v}; + assert!(v == 12); + } + + public fun test1() { + let v = 1; + v += {v += 2; v}; + assert!(v == 6); + } + + fun mod1(r: &mut u64) { + *r += 2; + } + + public fun test2() { + let v = 1; + v += {mod1(&mut v); v}; + assert!(v == 6); + } + + fun mod2(r: &mut u64): u64 { + *r += 2; + *r + } + + public fun test3() { + let v = 1; + v += mod2(&mut v); + assert!(v == 6); + } + + public fun test4() { + let i = 0; + let xs = vector[1, 2, 3]; + xs[{ i += 1; i }] += xs[{ i += 1; i }]; + assert!(xs == vector[1, 2, 5]); + } +} + +//# run --verbose -- 0xc0ffee::m::test0 + +//# run --verbose -- 0xc0ffee::m::test1 + +//# run --verbose -- 0xc0ffee::m::test2 + +//# run --verbose -- 0xc0ffee::m::test3 + +//# run --verbose -- 0xc0ffee::m::test4 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/op_equal/no_double_eval.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/op_equal/no_double_eval.exp new file mode 100644 index 0000000000000..457ace9c4acb6 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/op_equal/no_double_eval.exp @@ -0,0 +1 @@ +processed 4 tasks diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/op_equal/no_double_eval.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/op_equal/no_double_eval.move new file mode 100644 index 0000000000000..1ca982b34a547 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/op_equal/no_double_eval.move @@ -0,0 +1,30 @@ +//# publish +module 0xc0ffee::m1 { + fun foo(r: &mut u64): &mut u64 { + *r += 1; + r + } + + public fun test() { + let x = 1; + *{foo(&mut x)} += 1; + assert!(x == 3); + } +} + +//# publish +module 0xc0ffee::m2 { + fun foo(r: &mut u64) { + *r += 2; + } + + public fun test() { + let x = 1; + *{foo(&mut x); foo(&mut x); &mut x} += 1; + assert!(x == 6); + } +} + +//# run --verbose -- 0xc0ffee::m1::test + +//# run --verbose -- 0xc0ffee::m2::test diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/op_equal/valid.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/op_equal/valid.exp new file mode 100644 index 0000000000000..8c37110a41a8c --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/op_equal/valid.exp @@ -0,0 +1 @@ +processed 9 tasks diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/op_equal/valid.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/op_equal/valid.move new file mode 100644 index 0000000000000..d1827deb71830 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/op_equal/valid.move @@ -0,0 +1,166 @@ +//# publish +module 0x42::test { + struct Coin(u256) has drop; + + struct Wrapper(T) has drop; + + fun add1_old(x: u256): u256 { + x = x + 1; + x + } + + fun add1_new(x: u256): u256 { + x += 1; + x + } + + fun test1() { + assert!(add1_old(42) == add1_new(42)); + } + + fun inc_new(x: &mut u256) { + *x += 1; + } + + fun inc_old(x: &mut u256) { + *x = *x + 1; + } + + fun test2() { + let x = 42; + let y = x; + inc_new(&mut x); + inc_old(&mut y); + assert!(x == y); + } + + fun coin_inc_new_1(self: &mut Coin) { + self.0 += 1; + } + + fun coin_inc_new_2(self: &mut Coin) { + let p = &mut self.0; + *p = *p + 1; + } + + fun coin_inc_old_1(self: &mut Coin) { + self.0 = self.0 + 1; + } + + fun coin_inc_old_2(self: &mut Coin) { + let p = &mut self.0; + *p = *p + 1; + } + + fun test3() { + let x = Coin(42); + let y = Coin(42); + let z = Coin(42); + let w = Coin(42); + coin_inc_new_1(&mut x); + coin_inc_new_2(&mut y); + coin_inc_old_1(&mut z); + coin_inc_old_2(&mut w); + assert!(&x == &y); + assert!(&x == &z); + assert!(&x == &w); + } + + fun inc_wrapped_coin_new(x: &mut Wrapper) { + x.0.0 += 1; + } + + fun inc_wrapped_coin_old(x: &mut Wrapper) { + x.0.0 = x.0.0 + 1; + } + + fun test4() { + let x = Wrapper(Coin(42)); + let y = Wrapper(Coin(42)); + inc_wrapped_coin_new(&mut x); + inc_wrapped_coin_old(&mut y); + assert!(x == y); + } + + fun inc_vec_new(x: &mut vector, index: u64) { + x[index] += 1; + } + + fun inc_vec_old(x: &mut vector, index: u64) { + x[index] = x[index] + 1; + } + + fun test5() { + let x = vector[42]; + let y = vector[42]; + inc_vec_new(&mut x, 0); + inc_vec_old(&mut y, 0); + assert!(x == y); + } + + fun inc_vec_coin_new(x: vector, index: u64): vector { + x[index].0 += 1; + x + } + + fun inc_vec_coin_old(x: vector, index: u64): vector { + x[index].0 = x[index].0 + 1; + x + } + + fun test6() { + let x = vector[Coin(42)]; + let y = vector[Coin(42)]; + let x = inc_vec_coin_new(x, 0); + let y = inc_vec_coin_old(y, 0); + assert!(x == y); + } + + fun inc_vec_wrapped_coin_new(x: vector>, index: u64): vector> { + x[index].0.0 += 1; + x + } + + fun inc_vec_wrapped_coin_old(x: vector>, index: u64): vector> { + x[index].0.0 = x[index].0.0 + 1; + x + } + + fun test7() { + let x = vector>[Wrapper(Coin(42))]; + let y = vector>[Wrapper(Coin(42))]; + let x = inc_vec_wrapped_coin_new(x, 0); + let y = inc_vec_wrapped_coin_old(y, 0); + assert!(x == y); + } + + fun x_plusplus(x: &mut u64): u64 { + let res = *x; + *x += 1; + res + } + + fun test8() { + let x = 0; + let y = vector[0, 1]; + y[x_plusplus(&mut x)] += 1; + assert!(y == vector[1, 1]); + } + +} + +//# run --verbose -- 0x42::test::test1 + +//# run --verbose -- 0x42::test::test2 + +//# run --verbose -- 0x42::test::test3 + +//# run --verbose -- 0x42::test::test4 + +//# run --verbose -- 0x42::test::test5 + +//# run --verbose -- 0x42::test::test6 + +//# run --verbose -- 0x42::test::test7 + +//# run --verbose -- 0x42::test::test8 diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/tests.rs b/third_party/move/move-compiler-v2/transactional-tests/tests/tests.rs index 7f92f87fa4522..15ac83d8d0dae 100644 --- a/third_party/move/move-compiler-v2/transactional-tests/tests/tests.rs +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/tests.rs @@ -44,7 +44,7 @@ const TEST_CONFIGS: &[TestConfig] = &[ (Experiment::OPTIMIZE_WAITING_FOR_COMPARE_TESTS, true), (Experiment::ACQUIRES_CHECK, false), ], - language_version: LanguageVersion::V2_0, + language_version: LanguageVersion::V2_1, include: &[], // all tests except those excluded below exclude: &["/operator_eval/"], }, @@ -55,7 +55,7 @@ const TEST_CONFIGS: &[TestConfig] = &[ (Experiment::OPTIMIZE, false), (Experiment::ACQUIRES_CHECK, false), ], - language_version: LanguageVersion::V2_0, + language_version: LanguageVersion::V2_1, include: &[], // all tests except those excluded below exclude: &["/operator_eval/"], }, @@ -68,7 +68,7 @@ const TEST_CONFIGS: &[TestConfig] = &[ (Experiment::AST_SIMPLIFY, false), (Experiment::ACQUIRES_CHECK, false), ], - language_version: LanguageVersion::V2_0, + language_version: LanguageVersion::V2_1, include: &[], // all tests except those excluded below exclude: &["/operator_eval/"], }, @@ -84,7 +84,7 @@ const TEST_CONFIGS: &[TestConfig] = &[ name: "operator-eval-lang-2", runner: |p| run(p, get_config_by_name("operator-eval-lang-2")), experiments: &[(Experiment::OPTIMIZE, true)], - language_version: LanguageVersion::V2_0, + language_version: LanguageVersion::V2_1, include: &["/operator_eval/"], exclude: &[], }, diff --git a/third_party/move/move-compiler/src/command_line/mod.rs b/third_party/move/move-compiler/src/command_line/mod.rs index 4439856d1ab52..c829b905d5f36 100644 --- a/third_party/move/move-compiler/src/command_line/mod.rs +++ b/third_party/move/move-compiler/src/command_line/mod.rs @@ -34,6 +34,8 @@ pub const FLAVOR: &str = "flavor"; pub const BYTECODE_VERSION: &str = "bytecode-version"; +pub const LANGUAGE_VERSION: &str = "language-version"; + /// Color flag interpreted locally in diagnostics/mod.rs. /// (Is translated to codespan_reporting::term::termcolor::ColorChoice). /// Choices here are `NONE`, `ANSI`, `ALWAYS`, with default to Auto. diff --git a/third_party/move/move-compiler/src/expansion/translate.rs b/third_party/move/move-compiler/src/expansion/translate.rs index 4fec7ef662b1f..12cc0f80cc2af 100644 --- a/third_party/move/move-compiler/src/expansion/translate.rs +++ b/third_party/move/move-compiler/src/expansion/translate.rs @@ -10,8 +10,8 @@ use crate::{ expansion::{ aliases::{AliasMap, AliasSet}, ast::{ - self as E, Address, Fields, LValueOrDotDot_, ModuleAccess_, ModuleIdent, ModuleIdent_, - SpecId, + self as E, Address, Fields, LValueOrDotDot_, LValue_, ModuleAccess_, ModuleIdent, + ModuleIdent_, SequenceItem_, SpecId, }, byte_string, hex_string, }, @@ -2654,7 +2654,7 @@ fn exp_(context: &mut Context, sp!(loc, pe_): P::Exp) -> E::Exp { EE::ExpList(exps(context, pes)) }, - PE::Assign(lvalue, rhs) => { + PE::Assign(lvalue, op_opt, rhs) => { let l_opt = lvalues(context, *lvalue); let er = exp(context, *rhs); match l_opt { @@ -2662,9 +2662,101 @@ fn exp_(context: &mut Context, sp!(loc, pe_): P::Exp) -> E::Exp { assert!(context.env.has_errors()); EE::UnresolvedError }, - Some(LValue::Assigns(al)) => EE::Assign(al, er), - Some(LValue::Mutate(el)) => EE::Mutate(el, er), - Some(LValue::FieldMutate(edotted)) => EE::FieldMutate(edotted, er), + Some(LValue::Assigns(al)) => match op_opt { + Some(op) => { + if al.value.len() == 1 { + match &al.value[0] { + // x += e (similarly for other binary operators) + // => + // { let t = e; x = x + t; } + sp!(var_loc, LValue_::Var(module_access, ty_opt)) => { + let x = sp( + *var_loc, + EE::Name(module_access.clone(), ty_opt.clone()), + ); + // t, let t = e; + let (t, bind) = + let_symbol_eq_exp(er.loc, Symbol::from("$t"), *er); + // x + t; + let rhs_expanded = + sp(loc, EE::BinopExp(Box::new(x), op, Box::new(t))); + // x = x + t; + let assign = sp(loc, EE::Assign(al, Box::new(rhs_expanded))); + // { let t = e; x = x + t; } + let sequence = + VecDeque::from([bind, sp(loc, SequenceItem_::Seq(assign))]); + EE::Block(sequence) + }, + _ => { + context.env.add_diag(diag!(Syntax::InvalidLValue, (loc, "Invalid assignment syntax. Expected: a local, a field write, or a deconstructing assignment"))); + EE::UnresolvedError + }, + } + } else { + context.env.add_diag(diag!(Syntax::InvalidLValue, (loc, "Invalid assignment syntax. Expected: a local, a field write, or a deconstructing assignment"))); + EE::UnresolvedError + } + }, + None => EE::Assign(al, er), + }, + Some(LValue::Mutate(el)) => { + match op_opt { + // *e1 += e2 + // => + // { let t2 = e2; let t1 = e1; *t1 = *t1 + t2 } + Some(op) => { + // t2, let t2 = e2; + let (tmp2, bind2) = let_symbol_eq_exp(er.loc, Symbol::from("$t2"), *er); + // t1, let t1 = e1; + let (tmp1, bind1) = + let_symbol_eq_exp(el.loc, Symbol::from("$t1"), match &el.value { + EE::Index(..) => sp(el.loc, EE::Borrow(true, el)), + _ => *el, + }); + // *t1 + let deref_tmp1 = sp(loc, EE::Dereference(Box::new(tmp1.clone()))); + // *t1 + t2 + let rhs_expanded = + sp(loc, EE::BinopExp(Box::new(deref_tmp1), op, Box::new(tmp2))); + // *t1 = *t1 + t2 + let assign = + sp(loc, EE::Mutate(Box::new(tmp1), Box::new(rhs_expanded))); + // { let t2 = e2; let t1 = e1; *t1 = *t1 + t2 } + let sequence = + VecDeque::from([bind2, bind1, sp(loc, SequenceItem_::Seq(assign))]); + EE::Block(sequence) + }, + None => EE::Mutate(el, er), + } + }, + Some(LValue::FieldMutate(edotted)) => match op_opt { + // e1.f += e2 + // => + // { let t2 = e2; let t1 = &mut e1.f; *t1 = *t1 + t2 } + Some(op) => { + let lhs_loc = edotted.loc; + // t2, let t2 = e2; + let (tmp2, bind2) = let_symbol_eq_exp(er.loc, Symbol::from("$t2"), *er); + // e1.f + let e = sp(lhs_loc, EE::ExpDotted(edotted)); + // &mut e1.f + let e_mut = sp(lhs_loc, EE::Borrow(true, Box::new(e))); + // t1, let t1 = &mut e1.f; + let (tmp1, bind1) = let_symbol_eq_exp(lhs_loc, Symbol::from("$t1"), e_mut); + // *t1 + let deref_tmp1 = sp(loc, EE::Dereference(Box::new(tmp1.clone()))); + // *t1 + t2 + let rhs_expanded = + sp(loc, EE::BinopExp(Box::new(deref_tmp1), op, Box::new(tmp2))); + // *t1 = *t1 + t2 + let assign = sp(loc, EE::Mutate(Box::new(tmp1), Box::new(rhs_expanded))); + // { let t2 = e2; let t1 = &mut e1.f; *t1 = *t1 + t2 } + let sequence = + VecDeque::from([bind2, bind1, sp(loc, SequenceItem_::Seq(assign))]); + EE::Block(sequence) + }, + None => EE::FieldMutate(edotted, er), + }, } }, PE::Return(pe_opt) => { @@ -3663,3 +3755,23 @@ fn restricted_name_error(case: NameCase, loc: Loc, restricted: &str) -> Diagnost ); diag!(NameResolution::ReservedName, (loc, msg)) } + +//************************************************************************************************** +// Utility functions +//************************************************************************************************** + +/// Returns expansion expressions `(t, let t = e)` where `t` is a variable named `symbol` +fn let_symbol_eq_exp(loc: Loc, symbol: Symbol, e: E::Exp) -> (E::Exp, E::SequenceItem) { + // t + let tmp_name = sp(loc, symbol); + let mod_acc = ModuleAccess_::Name(tmp_name); + let tmp_ = E::Exp_::Name(sp(loc, mod_acc.clone()), None); + let tmp = sp(loc, tmp_); + // let t = e; + let lval_ = LValue_::Var(sp(loc, mod_acc), None); + let lval = sp(loc, lval_); + let lvals = sp(loc, vec![lval]); + let bind_ = SequenceItem_::Bind(lvals, e); + let bind = sp(loc, bind_); + (tmp, bind) +} diff --git a/third_party/move/move-compiler/src/parser/ast.rs b/third_party/move/move-compiler/src/parser/ast.rs index bd22eca723c27..34e4dba75570d 100644 --- a/third_party/move/move-compiler/src/parser/ast.rs +++ b/third_party/move/move-compiler/src/parser/ast.rs @@ -702,8 +702,8 @@ pub enum Exp_ { // () Unit, - // a = e - Assign(Box, Box), + // a [binop]= e + Assign(Box, Option, Box), // return e Return(Option>), @@ -1916,9 +1916,13 @@ impl AstDebug for Exp_ { w.comma(es, |w, e| e.ast_debug(w)); w.write(")"); }, - E::Assign(lvalue, rhs) => { + E::Assign(lvalue, op_opt, rhs) => { lvalue.ast_debug(w); - w.write(" = "); + w.write(" "); + if let Some(op) = op_opt { + op.ast_debug(w); + } + w.write("= "); rhs.ast_debug(w); }, E::Return(e) => { diff --git a/third_party/move/move-compiler/src/parser/lexer.rs b/third_party/move/move-compiler/src/parser/lexer.rs index b2a3439ff182e..89667fe8d8ea7 100644 --- a/third_party/move/move-compiler/src/parser/lexer.rs +++ b/third_party/move/move-compiler/src/parser/lexer.rs @@ -41,6 +41,16 @@ pub enum Tok { LessEqual, LessLess, Equal, + PlusEqual, + SubEqual, + MulEqual, + ModEqual, + DivEqual, + BitOrEqual, + BitAndEqual, + XorEqual, + ShlEqual, + ShrEqual, EqualEqual, EqualGreater, EqualEqualGreater, @@ -105,6 +115,16 @@ impl fmt::Display for Tok { RBracket => "]", Star => "*", Plus => "+", + PlusEqual => "+=", + SubEqual => "-=", + MulEqual => "*=", + ModEqual => "%=", + DivEqual => "/=", + BitOrEqual => "|=", + BitAndEqual => "&=", + XorEqual => "^=", + ShlEqual => "<<=", + ShrEqual => ">>=", Comma => ",", Minus => "-", Period => ".", @@ -420,6 +440,13 @@ impl<'input> Lexer<'input> { Ok(()) } + pub fn advance_with_loc(&mut self) -> Result> { + let start_loc = self.start_loc(); + self.advance()?; + let end_loc = self.previous_end_loc(); + Ok(make_loc(self.file_hash, start_loc, end_loc)) + } + // Replace the current token. The lexer will always match the longest token, // but sometimes the parser will prefer to replace it with a shorter one, // e.g., ">" instead of ">>". @@ -502,6 +529,8 @@ fn find_token( (Tok::AmpMut, 5) } else if text.starts_with("&&") { (Tok::AmpAmp, 2) + } else if text.starts_with("&=") { + (Tok::BitAndEqual, 2) } else { (Tok::Amp, 1) } @@ -509,6 +538,8 @@ fn find_token( '|' => { if text.starts_with("||") { (Tok::PipePipe, 2) + } else if text.starts_with("|=") { + (Tok::BitOrEqual, 2) } else { (Tok::Pipe, 1) } @@ -534,6 +565,8 @@ fn find_token( '<' => { if text.starts_with("<==>") { (Tok::LessEqualEqualGreater, 4) + } else if text.starts_with("<<=") { + (Tok::ShlEqual, 3) } else if text.starts_with("<=") { (Tok::LessEqual, 2) } else if text.starts_with("<<") { @@ -543,7 +576,9 @@ fn find_token( } }, '>' => { - if text.starts_with(">=") { + if text.starts_with(">>=") { + (Tok::ShrEqual, 3) + } else if text.starts_with(">=") { (Tok::GreaterEqual, 2) } else if text.starts_with(">>") { (Tok::GreaterGreater, 2) @@ -558,15 +593,39 @@ fn find_token( (Tok::Colon, 1) } }, - '%' => (Tok::Percent, 1), + '%' => { + if text.starts_with("%=") { + (Tok::ModEqual, 2) + } else { + (Tok::Percent, 1) + } + }, '(' => (Tok::LParen, 1), ')' => (Tok::RParen, 1), '[' => (Tok::LBracket, 1), ']' => (Tok::RBracket, 1), - '*' => (Tok::Star, 1), - '+' => (Tok::Plus, 1), + '*' => { + if text.starts_with("*=") { + (Tok::MulEqual, 2) + } else { + (Tok::Star, 1) + } + }, + '+' => { + if text.starts_with("+=") { + (Tok::PlusEqual, 2) + } else { + (Tok::Plus, 1) + } + }, ',' => (Tok::Comma, 1), - '-' => (Tok::Minus, 1), + '-' => { + if text.starts_with("-=") { + (Tok::SubEqual, 2) + } else { + (Tok::Minus, 1) + } + }, '.' => { if text.starts_with("..") { (Tok::PeriodPeriod, 2) @@ -574,9 +633,21 @@ fn find_token( (Tok::Period, 1) } }, - '/' => (Tok::Slash, 1), + '/' => { + if text.starts_with("/=") { + (Tok::DivEqual, 2) + } else { + (Tok::Slash, 1) + } + }, ';' => (Tok::Semicolon, 1), - '^' => (Tok::Caret, 1), + '^' => { + if text.starts_with("^=") { + (Tok::XorEqual, 2) + } else { + (Tok::Caret, 1) + } + }, '{' => (Tok::LBrace, 1), '}' => (Tok::RBrace, 1), '#' => (Tok::NumSign, 1), diff --git a/third_party/move/move-compiler/src/parser/syntax.rs b/third_party/move/move-compiler/src/parser/syntax.rs index 1c4aee7141204..07f6cf531246a 100644 --- a/third_party/move/move-compiler/src/parser/syntax.rs +++ b/third_party/move/move-compiler/src/parser/syntax.rs @@ -82,14 +82,41 @@ fn add_type_args_ambiguity_label(loc: Loc, mut diag: Box) -> Box bool { - if !context.env.flags().lang_v2() { - context.env.add_diag(diag!( - Syntax::UnsupportedLanguageItem, - ( - loc, - format!("Move 2 language construct is not enabled: {}", description) - ) - )); + require_language_version_msg( + context, + loc, + LanguageVersion::V2, + &format!("Move 2 language construct is not enabled: {}", description), + ) +} + +fn require_language_version( + context: &mut Context, + loc: Loc, + min_language_version: LanguageVersion, + description: &str, +) -> bool { + require_language_version_msg( + context, + loc, + min_language_version, + &format!( + "Move language construct `{}` is not enabled until version {}", + description, min_language_version + ), + ) +} + +fn require_language_version_msg( + context: &mut Context, + loc: Loc, + min_language_version: LanguageVersion, + msg: &str, +) -> bool { + if context.env.flags().language_version() < min_language_version { + context + .env + .add_diag(diag!(Syntax::UnsupportedLanguageItem, (loc, msg))); false } else { true @@ -160,14 +187,6 @@ fn consume_token_( } } -// let unexp_loc = current_token_loc(tokens); -// let unexp_msg = format!("Unexpected {}", current_token_error_string(tokens)); - -// let end_loc = tokens.previous_end_loc(); -// let addr_loc = make_loc(tokens.file_hash(), start_loc, end_loc); -// let exp_msg = format!("Expected '::' {}", case); -// Err(vec![(unexp_loc, unexp_msg), (addr_loc, exp_msg)]) - // Check for the identifier token with specified value and return an error if it does not match. fn consume_identifier(tokens: &mut Lexer, value: &str) -> Result<(), Box> { if tokens.peek() == Tok::Identifier && tokens.content() == value { @@ -1534,7 +1553,7 @@ fn parse_for_loop(context: &mut Context) -> Result<(Exp, bool), Box> ); let update = sp( for_loc, - Exp_::Assign(Box::new(iter_exp.clone()), Box::new(updated_exp)), + Exp_::Assign(Box::new(iter_exp.clone()), None, Box::new(updated_exp)), ); // Create the assignment "flag = true;" @@ -1548,7 +1567,7 @@ fn parse_for_loop(context: &mut Context) -> Result<(Exp, bool), Box> let true_exp = sp(for_loc, Exp_::Value(sp(for_loc, Value_::Bool(true)))); let assign_iter = sp( for_loc, - Exp_::Assign(Box::new(flag_exp.clone()), Box::new(true_exp.clone())), + Exp_::Assign(Box::new(flag_exp.clone()), None, Box::new(true_exp.clone())), ); // construct flag conditional "if (flag) { update; } else { flag = true; }" @@ -1852,6 +1871,7 @@ fn at_start_of_exp(context: &mut Context) -> bool { // | spec only // | // | "=" +// | ("+=" | "-=" | "*=" | "/=" | "%=" | "&=" | "|=" | "^=" | "<<=" | ">>=") // | ("as" | "is") Type fn parse_exp(context: &mut Context) -> Result> { let start_loc = context.tokens.start_loc(); @@ -1870,32 +1890,80 @@ fn parse_exp(context: &mut Context) -> Result> { }, Tok::Identifier if is_quant(context) => parse_quant(context)?, _ => { - // This could be either an assignment or a binary operator + // This could be either an assignment, operator assignment (e.g., +=), or a binary operator // expression, or a cast or test let lhs = parse_unary_exp(context)?; - if context.tokens.peek() != Tok::Equal { - if let Some(exp) = - parse_cast_or_test_exp(context, &lhs, /*allow_colon_exp*/ false)? - { - let loc = make_loc( - context.tokens.file_hash(), - start_loc, - context.tokens.previous_end_loc(), + let current_token = context.tokens.peek(); + match current_token { + Tok::Equal => { + context.tokens.advance()?; // consume the "=" + let rhs = Box::new(parse_exp(context)?); + Exp_::Assign(Box::new(lhs), None, rhs) + }, + Tok::PlusEqual + | Tok::SubEqual + | Tok::MulEqual + | Tok::ModEqual + | Tok::DivEqual + | Tok::BitOrEqual + | Tok::BitAndEqual + | Tok::XorEqual + | Tok::ShlEqual + | Tok::ShrEqual => { + require_language_version( + context, + current_token_loc(context.tokens), + LanguageVersion::V2_1, + ¤t_token.to_string(), ); - return Ok(sp(loc, exp)); - } else { - return parse_binop_exp(context, lhs, /* min_prec */ 1); - } + let op_loc = context.tokens.advance_with_loc()?; // consume the "op=" + let rhs = Box::new(parse_exp(context)?); + Exp_::Assign( + Box::new(lhs), + Some(sp( + op_loc, + op_equal_to_binop(¤t_token).expect("binop"), + )), + rhs, + ) + }, + _ => { + if let Some(exp) = + parse_cast_or_test_exp(context, &lhs, /*allow_colon_exp*/ false)? + { + let loc = make_loc( + context.tokens.file_hash(), + start_loc, + context.tokens.previous_end_loc(), + ); + return Ok(sp(loc, exp)); + } else { + return parse_binop_exp(context, lhs, /* min_prec */ 1); + } + }, } - context.tokens.advance()?; // consume the "=" - let rhs = Box::new(parse_exp(context)?); - Exp_::Assign(Box::new(lhs), rhs) }, }; let end_loc = context.tokens.previous_end_loc(); Ok(spanned(context.tokens.file_hash(), start_loc, end_loc, exp)) } +fn op_equal_to_binop(token: &Tok) -> Option { + match token { + Tok::PlusEqual => Some(BinOp_::Add), + Tok::SubEqual => Some(BinOp_::Sub), + Tok::MulEqual => Some(BinOp_::Mul), + Tok::ModEqual => Some(BinOp_::Mod), + Tok::DivEqual => Some(BinOp_::Div), + Tok::BitOrEqual => Some(BinOp_::BitOr), + Tok::BitAndEqual => Some(BinOp_::BitAnd), + Tok::XorEqual => Some(BinOp_::Xor), + Tok::ShlEqual => Some(BinOp_::Shl), + Tok::ShrEqual => Some(BinOp_::Shr), + _ => None, + } +} + // Get the precedence of a binary operator. The minimum precedence value // is 1, and larger values have higher precedence. For tokens that are not // binary operators, this returns a value of zero so that they will be diff --git a/third_party/move/move-compiler/src/shared/mod.rs b/third_party/move/move-compiler/src/shared/mod.rs index a03a7147904c3..596329c4bf1a0 100644 --- a/third_party/move/move-compiler/src/shared/mod.rs +++ b/third_party/move/move-compiler/src/shared/mod.rs @@ -414,6 +414,10 @@ pub struct Flags { #[clap(long = cli::COMPILER_V2_FLAG)] compiler_v2: bool, + /// Language version + #[clap(long = cli::LANGUAGE_VERSION, default_value="1")] + language_version: LanguageVersion, + /// Block v1 runs past expansion phase #[clap(long = MOVE_COMPILER_BLOCK_V1_FLAG, default_value=bool_to_str(get_move_compiler_block_v1_from_env()))] block_v1_compiler: bool, @@ -435,6 +439,7 @@ impl Flags { warn_unused: false, lang_v2: false, compiler_v2: false, + language_version: LanguageVersion::V1, block_v1_compiler: get_move_compiler_block_v1_from_env(), } } @@ -593,9 +598,14 @@ impl Flags { self.lang_v2 } - pub fn set_lang_v2(self, v2: bool) -> Self { + pub fn language_version(&self) -> LanguageVersion { + self.language_version + } + + pub fn set_language_version(self, language_version: LanguageVersion) -> Self { Self { - lang_v2: v2, + language_version, + lang_v2: language_version >= LanguageVersion::V2, ..self } } @@ -612,6 +622,60 @@ impl Flags { } } +#[derive(Clone, Copy, Debug, ValueEnum)] +pub enum LanguageVersion { + #[value(name = "1")] + V1, + #[value(name = "2")] + V2, /* V2 is the same as V2_0, here for the parser */ + #[value(name = "2.0")] + V2_0, + #[value(name = "2.1")] + V2_1, +} + +impl LanguageVersion { + fn to_ordinal(self) -> usize { + match self { + LanguageVersion::V1 => 0, + LanguageVersion::V2 => 1, + LanguageVersion::V2_0 => 1, + LanguageVersion::V2_1 => 2, + } + } +} + +impl PartialEq for LanguageVersion { + fn eq(&self, other: &LanguageVersion) -> bool { + self.to_ordinal() == other.to_ordinal() + } +} + +impl Eq for LanguageVersion {} + +impl PartialOrd for LanguageVersion { + fn partial_cmp(&self, other: &LanguageVersion) -> Option { + Some(self.to_ordinal().cmp(&other.to_ordinal())) + } +} + +impl Ord for LanguageVersion { + fn cmp(&self, other: &LanguageVersion) -> std::cmp::Ordering { + self.to_ordinal().cmp(&other.to_ordinal()) + } +} + +impl std::fmt::Display for LanguageVersion { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", match self { + LanguageVersion::V1 => "1", + LanguageVersion::V2 => "2", + LanguageVersion::V2_0 => "2.0", + LanguageVersion::V2_1 => "2.1", + }) + } +} + //************************************************************************************************** // Attributes //************************************************************************************************** diff --git a/third_party/move/move-model/src/lib.rs b/third_party/move/move-model/src/lib.rs index 3fa833f86f9a0..8be42edd8e20d 100644 --- a/third_party/move/move-model/src/lib.rs +++ b/third_party/move/move-model/src/lib.rs @@ -118,7 +118,7 @@ pub fn run_model_builder_in_compiler_mode( .set_skip_attribute_checks(skip_attribute_checks) .set_verify(compile_verify_code) .set_keep_testing_functions(compile_test_code) - .set_lang_v2(language_version != LanguageVersion::V1) + .set_language_version(language_version.into()) .set_compiler_v2(true), known_attributes, ) diff --git a/third_party/move/move-model/src/metadata.rs b/third_party/move/move-model/src/metadata.rs index 63f018944b399..c1a26833bffc8 100644 --- a/third_party/move/move-model/src/metadata.rs +++ b/third_party/move/move-model/src/metadata.rs @@ -7,6 +7,7 @@ use move_command_line_common::{ env, env::{get_move_compiler_v2_from_env, read_bool_env_var}, }; +use move_compiler::shared::LanguageVersion as CompilerLanguageVersion; use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; use std::{ @@ -214,6 +215,16 @@ impl FromStr for LanguageVersion { } } +impl From for CompilerLanguageVersion { + fn from(val: LanguageVersion) -> Self { + match val { + LanguageVersion::V1 => CompilerLanguageVersion::V1, + LanguageVersion::V2_0 => CompilerLanguageVersion::V2_0, + LanguageVersion::V2_1 => CompilerLanguageVersion::V2_1, + } + } +} + impl LanguageVersion { /// Whether the language version is unstable. An unstable version /// should not be allowed on production networks.