diff --git a/third_party/move/move-compiler-v2/tests/checking-lang-v1/eq_inline_typed.exp b/third_party/move/move-compiler-v2/tests/checking-lang-v1/eq_inline_typed.exp new file mode 100644 index 0000000000000..7eecb2c8d0891 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking-lang-v1/eq_inline_typed.exp @@ -0,0 +1,18 @@ + +Diagnostics: +warning: Unused parameter `f`. Consider removing or prefixing with an underscore: `_f` + ┌─ tests/checking-lang-v1/eq_inline_typed.move:3:20 + │ +3 │ inline fun foo(f: |&u64|) { + │ ^ + +// -- Model dump before bytecode pipeline +module 0x42::m { + private inline fun foo(f: |&u64|) { + Tuple() + } + private fun g() { + Tuple(); + Tuple() + } +} // end 0x42::m diff --git a/third_party/move/move-compiler-v2/tests/checking-lang-v1/eq_inline_typed.move b/third_party/move/move-compiler-v2/tests/checking-lang-v1/eq_inline_typed.move new file mode 100644 index 0000000000000..fd6c39261d521 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking-lang-v1/eq_inline_typed.move @@ -0,0 +1,13 @@ +module 0x42::m { + + inline fun foo(f: |&u64|) { + } + + fun g() { + foo(|v: &u64| { + v == &1; + }); + } + + +} diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/break_continue_in_lambda_typed.exp b/third_party/move/move-compiler-v2/tests/checking/inlining/break_continue_in_lambda_typed.exp new file mode 100644 index 0000000000000..85d0ec7301714 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/break_continue_in_lambda_typed.exp @@ -0,0 +1,13 @@ + +Diagnostics: +error: Break outside of a loop not currently supported in inline functions + ┌─ tests/checking/inlining/break_continue_in_lambda_typed.move:3:9 + │ +3 │ break; + │ ^^^^^ + +error: Break outside of a loop not supported in function-typed arguments (lambda expressions) + ┌─ tests/checking/inlining/break_continue_in_lambda_typed.move:40:32 + │ +40 │ brk2(|_x: u64| break); + │ ^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/break_continue_in_lambda_typed.move b/third_party/move/move-compiler-v2/tests/checking/inlining/break_continue_in_lambda_typed.move new file mode 100644 index 0000000000000..52d85e2156339 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/break_continue_in_lambda_typed.move @@ -0,0 +1,55 @@ +module 0xc0ffee::m { + inline fun brk() { + break; + } + + inline fun brk2(f: |u64|) { + f(2); + } + + inline fun brk3() { + while (true) { + break; + } + } + + inline fun brk4() { + while (true) { + continue; + } + } + + public fun foo(): u64 { + let i = 0; + while (i < 10) { + i = i + 1; + if (i == 5) { + brk(); + brk3(); + brk4(); + } + }; + i + } + + public fun bar(): u64 { + let i = 0; + while (i < 10) { + i = i + 1; + if (i == 5) { + brk2(|_x: u64| break); + brk2(|_x: u64| while (true) { break }); + brk2(|_x: u64| while (true) { continue }); + } + }; + i + } + + fun broken() { + break; + } + + fun continued() { + continue; + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/cool_inlining_test_typed.exp b/third_party/move/move-compiler-v2/tests/checking/inlining/cool_inlining_test_typed.exp new file mode 100644 index 0000000000000..9b193b7c044a2 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/cool_inlining_test_typed.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: no function named `beans` found + ┌─ tests/checking/inlining/cool_inlining_test_typed.move:15:22 + │ +15 │ foo(|_x: u8| beans()) + │ ^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/cool_inlining_test_typed.move b/third_party/move/move-compiler-v2/tests/checking/inlining/cool_inlining_test_typed.move new file mode 100644 index 0000000000000..530805b4f198a --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/cool_inlining_test_typed.move @@ -0,0 +1,17 @@ +module 0xc0ffee::cool { + public fun beans(): u64 { + 42 + } +} + +module 0xc0ffee::m { + inline fun foo(f: |u8| u64): u64 { + use 0xc0ffee::cool::beans; + beans(); // discharge unused use warning + f(3) + } + + public fun bar(): u64 { + foo(|_x: u8| beans()) + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_param_typed.exp b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_param_typed.exp new file mode 100644 index 0000000000000..6e66b076fa40b --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_param_typed.exp @@ -0,0 +1,13 @@ + +Diagnostics: +error: Currently, a function-typed parameter to an inline function must be a literal lambda expression + ┌─ tests/checking/inlining/lambda_param_typed.move:7:15 + │ +7 │ inline_apply(f, b) + │ ^ + +error: Currently, a function-typed parameter to an inline function must be a literal lambda expression + ┌─ tests/checking/inlining/lambda_param_typed.move:11:16 + │ +11 │ inline_apply4(f, b) + │ ^ diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_param_typed.move b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_param_typed.move new file mode 100644 index 0000000000000..98e5b59e65ddb --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_param_typed.move @@ -0,0 +1,31 @@ +module 0x42::LambdaParam { + public inline fun inline_apply(f: |u64|u64, b: u64) : u64 { + f(b) + } + + public inline fun inline_apply2(f: |u64|u64, b: u64) : u64 { + inline_apply(f, b) + } + + public inline fun inline_apply3(f: |u64|u64, b: u64) : u64 { + inline_apply4(f, b) + } + + public inline fun inline_apply4(_f: |u64|u64, b: u64) : u64 { + b + } + + fun test_lambda_symbol_param1() { + let a = inline_apply2(|x: u64| x, 3); + assert!(a == 3, 0); + } + + fun test_lambda_symbol_param2() { + let a = inline_apply2(|x: u64| x, 3); + assert!(a == 3, 0); + let b = inline_apply(|x: u64| x, 3); + assert!(b == 3, 0); + let b = inline_apply3(|x: u64| x, 3); + assert!(b == 3, 0); + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_return_typed.exp b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_return_typed.exp new file mode 100644 index 0000000000000..f52bf7c3477ba --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_return_typed.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Return not currently supported in inline functions + ┌─ tests/checking/inlining/lambda_return_typed.move:3:2 + │ +3 │ return f(b) + │ ^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_return_typed.move b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_return_typed.move new file mode 100644 index 0000000000000..1ea4d58270306 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_return_typed.move @@ -0,0 +1,10 @@ +module 0x42::LambdaReturn { + public inline fun inline_apply2(f: |u64|u64, b: u64) : u64 { + return f(b) + } + + fun test_lambda_symbol_param() { + let a = inline_apply2(|x: u64| { x }, 3); + assert!(a == 3, 0); + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_typed.exp b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_typed.exp new file mode 100644 index 0000000000000..11a8de528f5cb --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_typed.exp @@ -0,0 +1,98 @@ +// -- Model dump before bytecode pipeline +module 0x42::LambdaTest1 { + public inline fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public inline fun inline_apply1(f: |u64|u64,b: u64): u64 { + { + let (a: u64, b: u64): (u64, u64) = Tuple(Add((f)(b), 1), 12); + Mul(a, 12) + } + } + public inline fun inline_mul(a: u64,b: u64): u64 { + Mul(a, b) + } +} // end 0x42::LambdaTest1 +module 0x42::LambdaTest2 { + use 0x42::LambdaTest1; // resolved as: 0x42::LambdaTest1 + use std::vector; + public inline fun foreach(v: &vector<#0>,action: |�|) { + { + let i: u64 = 0; + loop { + if Lt(i, vector::length(v)) { + (action)(vector::borrow(v, i)); + i: u64 = Add(i, 1); + Tuple() + } else { + break + } + } + } + } + public inline fun inline_apply2(g: |u64|u64,c: u64): u64 { + Add({ + let (b: u64): (u64) = Tuple((g)({ + let (a: u64, b: u64): (u64, u64) = Tuple(c, 3); + Mul(a, 3) + })); + { + let (a: u64, b: u64): (u64, u64) = Tuple(Add({ + let (z: u64): (u64) = Tuple(b); + z + }, 1), 12); + Mul(a, 12) + } + }, 2) + } + public inline fun inline_apply3(g: |u64|u64,c: u64): u64 { + Add(LambdaTest1::inline_apply1(g, LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(|x: u64| LambdaTest1::inline_apply(|y: u64| y, x), 3))), 4) + } + public fun test_inline_lambda() { + { + let product: u64 = 1; + { + let (v: &vector): (&vector) = Tuple(Borrow(Immutable)([Number(1), Number(2), Number(3)])); + { + let i: u64 = 0; + loop { + if Lt(i, vector::length(v)) { + { + let (e: &u64): (&u64) = Tuple(vector::borrow(v, i)); + product: u64 = { + let (a: u64, b: u64): (u64, u64) = Tuple(product, Deref(e)); + Mul(a, b) + } + }; + i: u64 = Add(i, 1); + Tuple() + } else { + break + } + } + } + }; + Tuple() + } + } +} // end 0x42::LambdaTest2 +module 0x42::LambdaTest { + use 0x42::LambdaTest2; // resolved as: 0x42::LambdaTest2 + public inline fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public inline fun inline_apply_test(): u64 { + 1120 + } + private fun test_lambda() { + if false { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::LambdaTest + + +============ bytecode verification succeeded ======== diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_typed.move b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_typed.move new file mode 100644 index 0000000000000..e690fc4ffec92 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_typed.move @@ -0,0 +1,62 @@ +module 0x42::LambdaTest1 { + public inline fun inline_mul(a: u64, b: u64): u64 { + a * b + } + + public inline fun inline_apply1(f: |u64|u64, b: u64) : u64 { + inline_mul(f(b) + 1, inline_mul(3, 4)) + } + + public inline fun inline_apply(f: |u64|u64, b: u64) : u64 { + f(b) + } +} + +module 0x42::LambdaTest2 { + use 0x42::LambdaTest1; + use std::vector; + + public inline fun foreach(v: &vector, action: |&T|) { // expected to be not implemented + let i = 0; + while (i < vector::length(v)) { + action(vector::borrow(v, i)); + i = i + 1; + } + } + + public fun test_inline_lambda() { + let v = vector[1, 2, 3]; + let product = 1; + foreach(&v, |e: &u64| product = LambdaTest1::inline_mul(product, *e)); + } + + public inline fun inline_apply2(g: |u64|u64, c: u64) : u64 { + LambdaTest1::inline_apply1(|z: u64|z, g(LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(|x: u64|x, 3)))) + 2 + } + + public inline fun inline_apply3(g: |u64|u64, c: u64) : u64 { + LambdaTest1::inline_apply1(g, + LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(|x:u64| { + LambdaTest1::inline_apply(|y: u64|y, x) + }, + 3))) + 4 + } +} + +module 0x42::LambdaTest { + use 0x42::LambdaTest2; + + public inline fun inline_apply(f: |u64|u64, b: u64) : u64 { + f(b) + } + + public inline fun inline_apply_test() : u64 { + LambdaTest2::inline_apply2(|x: u64| x + 1, 3) + + LambdaTest2::inline_apply2(|x: u64| x * x, inline_apply(|y: u64|y, 3)) + } + + fun test_lambda() { + let a = inline_apply_test(); + assert!(a == 1, 0); + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/return_in_lambda_typed.exp b/third_party/move/move-compiler-v2/tests/checking/inlining/return_in_lambda_typed.exp new file mode 100644 index 0000000000000..565b1d881cec9 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/return_in_lambda_typed.exp @@ -0,0 +1,19 @@ + +Diagnostics: +error: Return not currently supported in function-typed arguments (lambda expressions) + ┌─ tests/checking/inlining/return_in_lambda_typed.move:13:13 + │ +13 │ return adder(x, y) + │ ^^^^^^^^^^^^^^^^^^ + +error: Return not currently supported in function-typed arguments (lambda expressions) + ┌─ tests/checking/inlining/return_in_lambda_typed.move:16:13 + │ +16 │ return adder(x, y) + │ ^^^^^^^^^^^^^^^^^^ + +error: Return not currently supported in function-typed arguments (lambda expressions) + ┌─ tests/checking/inlining/return_in_lambda_typed.move:19:13 + │ +19 │ return adder(x, y) + │ ^^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/return_in_lambda_typed.move b/third_party/move/move-compiler-v2/tests/checking/inlining/return_in_lambda_typed.move new file mode 100644 index 0000000000000..c59650aec4734 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/return_in_lambda_typed.move @@ -0,0 +1,22 @@ +module 0x42::Test { + + inline fun apply(f:|u64, u64| u64, x: u64, y: u64): u64 { + f(x, y) + } + + inline fun adder(x: u64, y: u64): u64 { + x + y + } + + public fun main(): u64 { + apply(|x: u64, y: u64| { + return adder(x, y) + }, 10, 100); + apply(|x: u64, y| { + return adder(x, y) + }, 10, 100); + apply(|x, y: u64| { + return adder(x, y) + }, 10, 100) + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/shadowing_unused_nodecl_typed.exp b/third_party/move/move-compiler-v2/tests/checking/inlining/shadowing_unused_nodecl_typed.exp new file mode 100644 index 0000000000000..4f7f74661aa59 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/shadowing_unused_nodecl_typed.exp @@ -0,0 +1,51 @@ + +Diagnostics: +warning: Unused parameter `z`. Consider removing or prefixing with an underscore: `_z` + ┌─ tests/checking/inlining/shadowing_unused_nodecl_typed.move:6:42 + │ +6 │ public inline fun quux(f:|u64, u64|, z: u64) { + │ ^ + +// -- Model dump before bytecode pipeline +module 0x42::Test { + public inline fun foo(f: |(u64, u64)|,z: u64) { + { + let (z: u64): (u64) = Tuple(z); + (f)(3, 5); + Tuple() + }; + Tuple() + } + public inline fun quux(f: |(u64, u64)|,z: u64) { + (f)(3, 5); + Tuple() + } + public fun test_shadowing() { + { + let _x: u64 = 1; + _x: u64 = 3; + Tuple(); + Tuple(); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + public fun test_shadowing2() { + { + let _x: u64 = 1; + _x: u64 = 3; + Tuple(); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + +============ bytecode verification succeeded ======== diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/shadowing_unused_nodecl_typed.move b/third_party/move/move-compiler-v2/tests/checking/inlining/shadowing_unused_nodecl_typed.move new file mode 100644 index 0000000000000..3191a28a0d3ca --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/shadowing_unused_nodecl_typed.move @@ -0,0 +1,37 @@ +//# publish +module 0x42::Test { + + // Ideally, we would have a warning about unused var "z" here, but + // we don't check inlined functions until they are inlined. + public inline fun quux(f:|u64, u64|, z: u64) { + let x = 3; + let q = 5; + f(x, q); + } + + public inline fun foo(f:|u64, u64|, z: u64) { + quux(|a: u64, b: u64| f(a, b), z); + } + + public fun test_shadowing() { + let _x = 1; + let z = 4; + foo(|y: u64, _q: u64| { + _x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would + // have the value 1. + }, z); + assert!(_x == 3, 0) + } + + public fun test_shadowing2() { + let _x = 1; + let z = 4; + quux(|y: u64, _q: u64| { + _x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would + // have the value 1. + }, z); + assert!(_x == 3, 0) + } +} + +//# run 0x42::Test::test_shadowing diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/shadowing_unused_typed.exp b/third_party/move/move-compiler-v2/tests/checking/inlining/shadowing_unused_typed.exp new file mode 100644 index 0000000000000..2c3a1c4b158bd --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/shadowing_unused_typed.exp @@ -0,0 +1,43 @@ +// -- Model dump before bytecode pipeline +module 0x42::Test { + public inline fun foo(f: |(u64, u64)|,z: u64) { + { + let (_z: u64): (u64) = Tuple(z); + (f)(3, 5); + Tuple() + }; + Tuple() + } + public inline fun quux(f: |(u64, u64)|,_z: u64) { + (f)(3, 5); + Tuple() + } + public fun test_shadowing() { + { + let _x: u64 = 1; + _x: u64 = 3; + Tuple(); + Tuple(); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + public fun test_shadowing2() { + { + let _x: u64 = 1; + _x: u64 = 3; + Tuple(); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + +============ bytecode verification succeeded ======== diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/shadowing_unused_typed.move b/third_party/move/move-compiler-v2/tests/checking/inlining/shadowing_unused_typed.move new file mode 100644 index 0000000000000..2366415033c67 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/shadowing_unused_typed.move @@ -0,0 +1,35 @@ +//# publish +module 0x42::Test { + + public inline fun quux(f:|u64, u64|, _z: u64) { + let x = 3; + let q = 5; + f(x, q); + } + + public inline fun foo(f:|u64, u64|, z: u64) { + quux(|a: u64, b: u64| f(a, b), z); + } + + public fun test_shadowing() { + let _x = 1; + let z = 4; + foo(|y: u64, _q: u64| { + _x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would + // have the value 1. + }, z); + assert!(_x == 3, 0) + } + + public fun test_shadowing2() { + let _x = 1; + let z = 4; + quux(|y: u64, _q: u64| { + _x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would + // have the value 1. + }, z); + assert!(_x == 3, 0) + } +} + +//# run 0x42::Test::test_shadowing diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/spec_inlining_typed.exp b/third_party/move/move-compiler-v2/tests/checking/inlining/spec_inlining_typed.exp new file mode 100644 index 0000000000000..f5a5f2de0f028 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/spec_inlining_typed.exp @@ -0,0 +1,60 @@ +// -- Model dump before bytecode pipeline +module 0x42::Test { + private inline fun apply(v: u64,predicate: |u64|bool): bool { + spec { + assert Ge($t0, 0); + } + ; + (predicate)(v) + } + public fun test_apply(x: u64) { + { + let r1: bool = { + let (v: u64): (u64) = Tuple(x); + spec { + assert Ge(v, 0); + } + ; + { + let (v: u64): (u64) = Tuple(v); + Ge(v, 0) + } + }; + spec { + assert r1; + } + ; + if r1 { + Tuple() + } else { + Abort(1) + }; + { + let r2: bool = { + let (v: u64): (u64) = Tuple(x); + spec { + assert Ge(v, 0); + } + ; + { + let (v: u64): (u64) = Tuple(v); + Neq(v, 0) + } + }; + spec { + assert r2; + } + ; + if r2 { + Tuple() + } else { + Abort(2) + }; + Tuple() + } + } + } +} // end 0x42::Test + + +============ bytecode verification succeeded ======== diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/spec_inlining_typed.move b/third_party/move/move-compiler-v2/tests/checking/inlining/spec_inlining_typed.move new file mode 100644 index 0000000000000..060e459a17ef0 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/spec_inlining_typed.move @@ -0,0 +1,22 @@ +module 0x42::Test { + inline fun apply(v: u64, predicate: |u64| bool): bool { + spec { + assert v >= 0; + }; + predicate(v) + } + + public fun test_apply(x: u64) { + let r1 = apply(x, |v: u64| v >= 0); + spec { + assert r1; + }; + assert!(r1, 1); + + let r2 = apply(x, |v: u64| v != 0); + spec { + assert r2; + }; + assert!(r2, 2); + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/receiver/generic_calls_typed.exp b/third_party/move/move-compiler-v2/tests/checking/receiver/generic_calls_typed.exp new file mode 100644 index 0000000000000..b396815647805 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/receiver/generic_calls_typed.exp @@ -0,0 +1,47 @@ +// -- Model dump before bytecode pipeline +module 0x42::m { + struct S { + x: #0, + } + private fun id(self: m::S<#0>): m::S<#0> { + self + } + private inline fun inlined(f: |m::S<#0>|m::S<#0>,s: m::S<#0>) { + (f)(s); + Tuple() + } + private fun receiver(self: m::S<#0>,y: #0) { + select m::S.x>(self) = y; + Tuple() + } + private fun receiver_more_generics(self: m::S<#0>,_y: #1) { + Tuple() + } + private fun receiver_needs_type_args(self: m::S<#0>,_y: #0) { + Abort(1) + } + private fun receiver_ref(self: &m::S<#0>,_y: #0) { + Tuple() + } + private fun receiver_ref_mut(self: &mut m::S<#0>,y: #0) { + select m::S.x<&mut m::S>(self) = y + } + private fun test_call_styles(s: m::S,x: u64) { + m::receiver(s, x); + m::receiver_ref(Borrow(Immutable)(s), x); + m::receiver_ref_mut(Borrow(Mutable)(s), x); + m::receiver_more_generics(s, 22); + m::receiver_needs_type_args(s, x); + Tuple() + } + private fun test_receiver_inference(s: m::S) { + { + let (s: m::S): (m::S) = Tuple(s); + { + let (s: m::S): (m::S) = Tuple(s); + m::id(s) + }; + Tuple() + } + } +} // end 0x42::m diff --git a/third_party/move/move-compiler-v2/tests/checking/receiver/generic_calls_typed.move b/third_party/move/move-compiler-v2/tests/checking/receiver/generic_calls_typed.move new file mode 100644 index 0000000000000..6b5a48ebc7d2a --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/receiver/generic_calls_typed.move @@ -0,0 +1,49 @@ +module 0x42::m { + + struct S { x: T } + + // Call styles + + fun receiver(self: S, y: T) { + self.x = y; + } + + fun receiver_ref(self: &S, _y: T) { + } + + fun receiver_ref_mut(self: &mut S, y: T) { + self.x = y + } + + fun receiver_more_generics(self: S, _y: R) { + } + + fun receiver_needs_type_args(self: S, _y: T) { + abort 1 + } + + fun test_call_styles(s: S, x: u64) { + s.receiver(x); + s.receiver_ref(x); + s.receiver_ref_mut(x); + s.receiver_more_generics(22); + s.receiver_needs_type_args::(x); + } + + // Inference of receiver function + + inline fun inlined(f: |S|S, s: S) { + f(s); + } + + fun id(self: S): S { + self + } + + fun test_receiver_inference(s: S) { + // In the lambda the type of `s` is not known when the expression is checked, + // and the receiver function `id` is resolved later when the parameter type is unified + // with the lambda expression + inlined(|s: S| s.id(), s) + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/receiver/same_names_typed.exp b/third_party/move/move-compiler-v2/tests/checking/receiver/same_names_typed.exp new file mode 100644 index 0000000000000..b45494f8c2cf6 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/receiver/same_names_typed.exp @@ -0,0 +1,37 @@ +// -- Model dump before bytecode pipeline +module 0x42::b { + struct MyOtherList { + len: u64, + } + public fun len(self: &b::MyOtherList): u64 { + select b::MyOtherList.len<&b::MyOtherList>(self) + } +} // end 0x42::b +module 0x42::a { + struct MyList { + len: u64, + } + public fun len(self: &a::MyList): u64 { + select a::MyList.len<&a::MyList>(self) + } +} // end 0x42::a +module 0x42::c { + use 0x42::a; // resolved as: 0x42::a + use 0x42::b; // resolved as: 0x42::b + private inline fun foo(f: |(a::MyList, b::MyOtherList)|,x: a::MyList,y: b::MyOtherList) { + (f)(x, y) + } + private fun test(x: a::MyList,y: b::MyOtherList) { + { + let (x: a::MyList, y: b::MyOtherList): (a::MyList, b::MyOtherList) = Tuple(x, y); + { + let (x: a::MyList, y: b::MyOtherList): (a::MyList, b::MyOtherList) = Tuple(x, y); + if Eq(Add(a::len(Borrow(Immutable)(x)), b::len(Borrow(Immutable)(y))), 1) { + Tuple() + } else { + Abort(1) + } + } + } + } +} // end 0x42::c diff --git a/third_party/move/move-compiler-v2/tests/checking/receiver/same_names_typed.move b/third_party/move/move-compiler-v2/tests/checking/receiver/same_names_typed.move new file mode 100644 index 0000000000000..dc5b73e4e55ca --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/receiver/same_names_typed.move @@ -0,0 +1,32 @@ +module 0x42::a { + + struct MyList { len: u64 } + + public fun len(self: &MyList): u64 { + self.len + } +} + +module 0x42::b { + + struct MyOtherList { len: u64 } + + public fun len(self: &MyOtherList): u64 { + self.len + } +} + +module 0x42::c { + use 0x42::a; + use 0x42::b; + + inline fun foo(f: |a::MyList, b::MyOtherList|, x: a::MyList, y: b::MyOtherList) { + f(x, y) + } + + fun test(x: a::MyList, y: b::MyOtherList) { + // In the lambda below, the type of x and y is not known when the + // expression is checked. + foo(|x: a::MyList, y: b::MyOtherList| { assert!(x.len() + y.len() == 1, 1) }, x, y) + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/specs/inline_fun_in_spec_typed.exp b/third_party/move/move-compiler-v2/tests/checking/specs/inline_fun_in_spec_typed.exp new file mode 100644 index 0000000000000..e3c750934cc8c --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/specs/inline_fun_in_spec_typed.exp @@ -0,0 +1,80 @@ +// -- Model dump before bytecode pipeline +module 0x42::m { + spec { + invariant forall a: address: TypeDomain
(): Implies(exists(a), { + let (x: address): (address) = Tuple(a); + { + let r: bool = { + let (a: address): (address) = Tuple(x); + Lt(select m::S.f({ + let (a: address): (address) = Tuple(a); + global(a) + }), 10) + }; + r + } + }); + } + + struct S { + f: u64, + } + spec { + invariant { + let (x: u64): (u64) = Tuple(select m::S.f()); + { + let r: bool = { + let (x: u64): (u64) = Tuple(x); + Gt(x, 0) + }; + r + } + }; + } + + private inline fun exec(f: |#0|#1,x: #0): #1 { + { + let r: R = (f)(x); + spec { + assert Eq<#1>(r, (f)($t1)); + } + ; + r + } + } + private fun function_code_spec_block(x: u64): u64 { + spec { + assert { + let (x: u64): (u64) = Tuple($t0); + { + let r: bool = { + let (y: u64): (u64) = Tuple(x); + Gt(y, 0) + }; + r + } + }; + } + ; + Add(x, 1) + } + private fun function_spec_block(x: u64): u64 { + Add(x, 1) + } + spec { + ensures Eq(result0(), { + let (x: u64): (u64) = Tuple($t0); + { + let r: num = { + let (x: u64): (u64) = Tuple(x); + Add(x, 1) + }; + r + } + }); + } + + private inline fun get(a: address): � { + BorrowGlobal(Immutable)(a) + } +} // end 0x42::m diff --git a/third_party/move/move-compiler-v2/tests/checking/specs/inline_fun_in_spec_typed.move b/third_party/move/move-compiler-v2/tests/checking/specs/inline_fun_in_spec_typed.move new file mode 100644 index 0000000000000..fcbfc1d52ec19 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/specs/inline_fun_in_spec_typed.move @@ -0,0 +1,33 @@ +module 0x42::m { + + inline fun exec(f: |T|R, x: T): R { + let r = f(x); + spec { assert r == f(x); }; + r + } + + // Function spec block + fun function_spec_block(x: u64): u64 { + x + 1 + } + spec function_spec_block { + ensures result == exec(|x: u64| x + 1, x); + } + + // Function code spec block + fun function_code_spec_block(x: u64): u64 { + spec { assert exec(|y: u64| y > 0, x); }; + x + 1 + } + + // Struct spec block + struct S has key { f: u64 } + spec S { invariant exec(|x: u64| x > 0, f); } + + // Global invariant + spec module { + invariant forall a: address: + exists(a) ==> exec(|a: address| get(a).f < 10, a); + } + inline fun get(a: address): &R { borrow_global(a) } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/eq_inline_typed.exp b/third_party/move/move-compiler-v2/tests/checking/typing/eq_inline_typed.exp new file mode 100644 index 0000000000000..c7449303ddf2c --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/typing/eq_inline_typed.exp @@ -0,0 +1,18 @@ + +Diagnostics: +warning: Unused parameter `f`. Consider removing or prefixing with an underscore: `_f` + ┌─ tests/checking/typing/eq_inline_typed.move:3:20 + │ +3 │ inline fun foo(f: |&u64|) { + │ ^ + +// -- Model dump before bytecode pipeline +module 0x42::m { + private inline fun foo(f: |&u64|) { + Tuple() + } + private fun g() { + Tuple(); + Tuple() + } +} // end 0x42::m diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/eq_inline_typed.move b/third_party/move/move-compiler-v2/tests/checking/typing/eq_inline_typed.move new file mode 100644 index 0000000000000..fd6c39261d521 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/typing/eq_inline_typed.move @@ -0,0 +1,13 @@ +module 0x42::m { + + inline fun foo(f: |&u64|) { + } + + fun g() { + foo(|v: &u64| { + v == &1; + }); + } + + +} diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed.exp b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed.exp new file mode 100644 index 0000000000000..351d607a7b2b7 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed.exp @@ -0,0 +1,37 @@ + +Diagnostics: +error: expected `|(&T, u64)|_` but found a value of type `|&T|` + ┌─ tests/checking/typing/lambda_typed.move:40:13 + │ +40 │ action(XVector::borrow(v, i), i); // expected to have wrong argument count + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected `|u64|_` but found a value of type `|&T|` + ┌─ tests/checking/typing/lambda_typed.move:48:13 + │ +48 │ action(i); // expected to have wrong argument type + │ ^^^^^^^^^ + +error: cannot use `()` with an operator which expects a value of type `u64` + ┌─ tests/checking/typing/lambda_typed.move:56:21 + │ +56 │ i = i + action(XVector::borrow(v, i)); // expected to have wrong result type + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: cannot return `u64` from a function with result type `|integer|` + ┌─ tests/checking/typing/lambda_typed.move:61:9 + │ +61 │ x(1) // expected to be not a function + │ ^^^^ + +error: cannot use `&u64` with an operator which expects a value of type `integer` + ┌─ tests/checking/typing/lambda_typed.move:67:43 + │ +67 │ foreach(&v, |e: &u64| sum = sum + e) // expected to cannot infer type + │ ^ + +error: cannot pass `|&u64|u64` to a function which expects argument of type `|&u64|` + ┌─ tests/checking/typing/lambda_typed.move:73:21 + │ +73 │ foreach(&v, |e: &u64| { sum = sum + *e; *e }) // expected to have wrong result type of lambda + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed.move b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed.move new file mode 100644 index 0000000000000..391db99ddd587 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed.move @@ -0,0 +1,110 @@ +module 0x8675309::M { + use 0x1::XVector; + + public inline fun foreach(v: &vector, action: |&T|) { // expected to be not implemented + let i = 0; + while (i < XVector::length(v)) { + action(XVector::borrow(v, i)); + i = i + 1; + } + } + + public inline fun reduce(v: vector, accu: R, reducer: |T, R|R): R { + while (!XVector::is_empty(&v)) { + accu = reducer(XVector::pop_back(&mut v), accu); + }; + accu + } + + + public fun correct_foreach() { + let v = vector[1, 2, 3]; + let sum = 0; + foreach(&v, |e: &u64| sum = sum + *e) // expected to be not implemented + } + + public fun correct_reduce(): u64 { + let v = vector[1, 2, 3]; + reduce(v, 0, |t: u64, r: u64| t + r) + } + + public fun corrected_nested() { + let v = vector[vector[1,2], vector[3]]; + let sum = 0; + foreach(&v, |e: &vector| sum = sum + reduce(*e, 0, |t: u64, r: u64| t + r)); + } + + public inline fun wrong_local_call_arg_count(v: &vector, action: |&T|) { + let i = 0; + while (i < XVector::length(v)) { + action(XVector::borrow(v, i), i); // expected to have wrong argument count + i = i + 1; + } + } + + public inline fun wrong_local_call_arg_type(v: &vector, action: |&T|) { + let i = 0; + while (i < XVector::length(v)) { + action(i); // expected to have wrong argument type + i = i + 1; + } + } + + public inline fun wrong_local_call_result_type(v: &vector, action: |&T|) { + let i = 0; + while (i < XVector::length(v)) { + i = i + action(XVector::borrow(v, i)); // expected to have wrong result type + } + } + + public fun wrong_local_call_no_fun(x: u64) { + x(1) // expected to be not a function + } + + public fun wrong_lambda_inferred_type() { + let v = vector[1, 2, 3]; + let sum = 0; + foreach(&v, |e: &u64| sum = sum + e) // expected to cannot infer type + } + + public fun wrong_lambda_result_type() { + let v = vector[1, 2, 3]; + let sum = 0; + foreach(&v, |e: &u64| { sum = sum + *e; *e }) // expected to have wrong result type of lambda + } + + public fun lambda_not_allowed() { + let _x = |i: u64| i + 1; // expected lambda not allowed + } + + struct FieldFunNotAllowed { + f: |u64|u64, // expected lambda not allowed + } + + public fun fun_arg_lambda_not_allowed(x: |u64|) {} // expected lambda not allowed + + public inline fun macro_result_lambda_not_allowed(): |u64| { // expected lambda not allowed + abort (1) + } + public fun fun_result_lambda_not_allowed(): |u64| { // expected lambda not allowed + abort (1) + } + + public fun correct_reduce2(): u64 { + let v = vector[1, 2, 3]; + reduce(v, 0, |t: u64, r| t + r) + } + + public fun corrected_nested2() { + let v = vector[vector[1,2], vector[3]]; + let sum = 0; + foreach(&v, |e: &vector| sum = sum + reduce(*e, 0, |t, r: u64| t + r)); + } +} + +module 0x1::XVector { + public fun length(v: &vector): u64 { abort(1) } + public fun is_empty(v: &vector): bool { abort(1) } + public fun borrow(v: &vector, i: u64): &T { abort(1) } + public fun pop_back(v: &mut vector): T { abort(1) } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed_widen.exp b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed_widen.exp new file mode 100644 index 0000000000000..28c542fa4b1d4 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed_widen.exp @@ -0,0 +1,25 @@ + +Diagnostics: +error: the function takes `&mut` but `&` was provided + ┌─ tests/checking/typing/lambda_typed_widen.move:38:38 + │ +38 │ let r = use_mut2_ref(&mut v, |x: &mut u64| *x); + │ ^^^^^^^^^^^^^^^^ + +error: the function takes `&mut` but `&` was provided + ┌─ tests/checking/typing/lambda_typed_widen.move:53:38 + │ +53 │ let r = use_mut2_ref(&mut v, |x: &mut u64| *(freeze(x))); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: the function takes `&mut` but `&` was provided + ┌─ tests/checking/typing/lambda_typed_widen.move:58:37 + │ +58 │ let r = use_imm_ref(&mut v, |x: &mut u64| *x); + │ ^^^^^^^^^^^^^^^^ + +error: the function takes `&mut` but `&` was provided + ┌─ tests/checking/typing/lambda_typed_widen.move:73:37 + │ +73 │ let r = use_imm_ref(&mut v, |x: &mut u64| *(freeze(x))); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed_widen.move b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed_widen.move new file mode 100644 index 0000000000000..df50f25e6d39b --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed_widen.move @@ -0,0 +1,75 @@ +module 0x8675309::M { + use std::vector; + + public inline fun use_mut_ref(v: &mut vector, action: |&mut T|T): T { + action(vector::borrow_mut(v, 0)) + } + + public inline fun use_mut2_ref(v: &mut vector, action: |&T|T): T { + return action(vector::borrow_mut(v, 0)) + } + + public inline fun use_imm_ref(v: &mut vector, action: |&T|T): T { + return action(vector::borrow(v, 0)) + } + + public fun consume_mut_mut() { + let v = vector[1, 2, 3]; + let r = use_mut_ref(&mut v, |x: &mut u64| *x); + } + + public fun consume_mut_imm() { + let v = vector[1, 2, 3]; + let r = use_mut_ref(&mut v, |x: &u64| *x); + } + + public fun consume_mut_untyped() { + let v = vector[1, 2, 3]; + let r = use_mut_ref(&mut v, |x| *x); + } + + public fun consume_mut_freeze() { + let v = vector[1, 2, 3]; + let r = use_mut_ref(&mut v, |x: &mut u64| *(freeze(x))); + } + + public fun consume_mut2_mut() { + let v = vector[1, 2, 3]; + let r = use_mut2_ref(&mut v, |x: &mut u64| *x); + } + + public fun consume_mut2_imm() { + let v = vector[1, 2, 3]; + let r = use_mut2_ref(&mut v, |x: &u64| *x); + } + + public fun consume_mut2_untyped() { + let v = vector[1, 2, 3]; + let r = use_mut2_ref(&mut v, |x| *x); + } + + public fun consume_mut2_freeze() { + let v = vector[1, 2, 3]; + let r = use_mut2_ref(&mut v, |x: &mut u64| *(freeze(x))); + } + + public fun consume_imm_mut() { + let v = vector[1, 2, 3]; + let r = use_imm_ref(&mut v, |x: &mut u64| *x); + } + + public fun consume_imm_imm() { + let v = vector[1, 2, 3]; + let r = use_imm_ref(&mut v, |x: &u64| *x); + } + + public fun consume_imm_untyped() { + let v = vector[1, 2, 3]; + let r = use_imm_ref(&mut v, |x| *x); + } + + public fun consume_imm_freeze() { + let v = vector[1, 2, 3]; + let r = use_imm_ref(&mut v, |x: &mut u64| *(freeze(x))); + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed_widen_result.exp b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed_widen_result.exp new file mode 100644 index 0000000000000..7c5cd89701bbe --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed_widen_result.exp @@ -0,0 +1,49 @@ + +Diagnostics: +error: the function takes `&mut` but `&` was provided + ┌─ tests/checking/typing/lambda_typed_widen_result.move:33:38 + │ +33 │ let r = pass_mut_ref(&mut v, |x: &u64| x); + │ ^^^^^^^^^^^ + +error: the function takes `&mut` but `&` was provided + ┌─ tests/checking/typing/lambda_typed_widen_result.move:43:38 + │ +43 │ let r = pass_mut_ref(&mut v, |x: &mut u64| (freeze(x))); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: the function takes `&mut` but `&` was provided + ┌─ tests/checking/typing/lambda_typed_widen_result.move:55:39 + │ +55 │ let r = pass_mut2_ref(&mut v, |x: &u64| x); + │ ^^^^^^^^^^^ + +error: the function takes `&mut` but `&` was provided + ┌─ tests/checking/typing/lambda_typed_widen_result.move:65:39 + │ +65 │ let r = pass_mut2_ref(&mut v, |x: &mut u64| (freeze(x))); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: the function takes `&mut` but `&` was provided + ┌─ tests/checking/typing/lambda_typed_widen_result.move:94:39 + │ +94 │ let r = pass_mut4_ref(&mut v, |x: &mut u64| x); + │ ^^^^^^^^^^^^^^^ + +error: the function takes `&mut` but `&` was provided + ┌─ tests/checking/typing/lambda_typed_widen_result.move:109:39 + │ +109 │ let r = pass_mut4_ref(&mut v, |x: &mut u64| (freeze(x))); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: the function takes `&mut` but `&` was provided + ┌─ tests/checking/typing/lambda_typed_widen_result.move:116:38 + │ +116 │ let r = pass_imm_ref(&mut v, |x: &mut u64| x); + │ ^^^^^^^^^^^^^^^ + +error: the function takes `&mut` but `&` was provided + ┌─ tests/checking/typing/lambda_typed_widen_result.move:131:38 + │ +131 │ let r = pass_imm_ref(&mut v, |x: &mut u64| (freeze(x))); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed_widen_result.move b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed_widen_result.move new file mode 100644 index 0000000000000..601cab6492a29 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed_widen_result.move @@ -0,0 +1,133 @@ +module 0x8675309::M { + use std::vector; + + public inline fun pass_mut_ref(v: &mut vector, action: |&mut T|&mut T): &mut T { + action(vector::borrow_mut(v, 0)) + } + + public inline fun pass_mut2_ref(v: &mut vector, action: |&mut T|&mut T): &T { + action(vector::borrow_mut(v, 0)) + } + + public inline fun pass_mut3_ref(v: &mut vector, action: |&mut T|&T): &T { + action(vector::borrow_mut(v, 0)) + } + + public inline fun pass_mut4_ref(v: &mut vector, action: |&T|&T): &T { + action(vector::borrow_mut(v, 0)) + } + + public inline fun pass_imm_ref(v: &mut vector, action: |&T|&T): &T { + return action(vector::borrow(v, 0)) + } + + // 1 + + public fun consume_mut_mut() { + let v = vector[1, 2, 3]; + let r = pass_mut_ref(&mut v, |x: &mut u64| x); + } + + public fun consume_mut_imm() { + let v = vector[1, 2, 3]; + let r = pass_mut_ref(&mut v, |x: &u64| x); + } + + public fun consume_mut_untyped() { + let v = vector[1, 2, 3]; + let r = pass_mut_ref(&mut v, |x| x); + } + + public fun consume_mut_freeze() { + let v = vector[1, 2, 3]; + let r = pass_mut_ref(&mut v, |x: &mut u64| (freeze(x))); + } + + // 2 + + public fun consume_mut2_mut() { + let v = vector[1, 2, 3]; + let r = pass_mut2_ref(&mut v, |x: &mut u64| x); + } + + public fun consume_mut2_imm() { + let v = vector[1, 2, 3]; + let r = pass_mut2_ref(&mut v, |x: &u64| x); + } + + public fun consume_mut2_untyped() { + let v = vector[1, 2, 3]; + let r = pass_mut2_ref(&mut v, |x| x); + } + + public fun consume_mut2_freeze() { + let v = vector[1, 2, 3]; + let r = pass_mut2_ref(&mut v, |x: &mut u64| (freeze(x))); + } + + // 3 + + public fun consume_mut3_mut() { + let v = vector[1, 2, 3]; + let r = pass_mut3_ref(&mut v, |x: &mut u64| x); + } + + public fun consume_mut3_imm() { + let v = vector[1, 2, 3]; + let r = pass_mut3_ref(&mut v, |x: &u64| x); + } + + public fun consume_mut3_untyped() { + let v = vector[1, 2, 3]; + let r = pass_mut3_ref(&mut v, |x| x); + } + + public fun consume_mut3_freeze() { + let v = vector[1, 2, 3]; + let r = pass_mut3_ref(&mut v, |x: &mut u64| (freeze(x))); + } + + // 4 + + public fun consume_mut4_mut() { + let v = vector[1, 2, 3]; + let r = pass_mut4_ref(&mut v, |x: &mut u64| x); + } + + public fun consume_mut4_imm() { + let v = vector[1, 2, 3]; + let r = pass_mut4_ref(&mut v, |x: &u64| x); + } + + public fun consume_mut4_untyped() { + let v = vector[1, 2, 3]; + let r = pass_mut4_ref(&mut v, |x| x); + } + + public fun consume_mut4_freeze() { + let v = vector[1, 2, 3]; + let r = pass_mut4_ref(&mut v, |x: &mut u64| (freeze(x))); + } + + // imm + + public fun consume_imm_mut() { + let v = vector[1, 2, 3]; + let r = pass_imm_ref(&mut v, |x: &mut u64| x); + } + + public fun consume_imm_imm() { + let v = vector[1, 2, 3]; + let r = pass_imm_ref(&mut v, |x: &u64| x); + } + + public fun consume_imm_untyped() { + let v = vector[1, 2, 3]; + let r = pass_imm_ref(&mut v, |x| x); + } + + public fun consume_imm_freeze() { + let v = vector[1, 2, 3]; + let r = pass_imm_ref(&mut v, |x: &mut u64| (freeze(x))); + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/lambda_widen.exp b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_widen.exp new file mode 100644 index 0000000000000..641f4f0165093 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_widen.exp @@ -0,0 +1,13 @@ + +Diagnostics: +error: the function takes `&mut` but `&` was provided + ┌─ tests/checking/typing/lambda_widen.move:33:38 + │ +33 │ let r = use_mut2_ref(&mut v, |x| *(freeze(x))); + │ ^^^^^^^^^^^^^^^^ + +error: the function takes `&mut` but `&` was provided + ┌─ tests/checking/typing/lambda_widen.move:43:37 + │ +43 │ let r = use_imm_ref(&mut v, |x| *(freeze(x))); + │ ^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/lambda_widen.move b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_widen.move new file mode 100644 index 0000000000000..748d60f38498c --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_widen.move @@ -0,0 +1,45 @@ +module 0x8675309::M { + use std::vector; + + public inline fun use_mut_ref(v: &mut vector, action: |&mut T|T): T { + action(vector::borrow_mut(v, 0)) + } + + public inline fun use_mut2_ref(v: &mut vector, action: |&T|T): T { + return action(vector::borrow_mut(v, 0)) + } + + public inline fun use_imm_ref(v: &mut vector, action: |&T|T): T { + return action(vector::borrow(v, 0)) + } + + public fun consume_mut_mut() { + let v = vector[1, 2, 3]; + let r = use_mut_ref(&mut v, |x| *x); + } + + public fun consume_mut_freeze() { + let v = vector[1, 2, 3]; + let r = use_mut_ref(&mut v, |x| *(freeze(x))); + } + + public fun consume_mut2_mut() { + let v = vector[1, 2, 3]; + let r = use_mut2_ref(&mut v, |x| *x); + } + + public fun consume_mut2_freeze() { + let v = vector[1, 2, 3]; + let r = use_mut2_ref(&mut v, |x| *(freeze(x))); + } + + public fun consume_imm_mut() { + let v = vector[1, 2, 3]; + let r = use_imm_ref(&mut v, |x| *x); + } + + public fun consume_imm_freeze() { + let v = vector[1, 2, 3]; + let r = use_imm_ref(&mut v, |x| *(freeze(x))); + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/lambda_widen_result.exp b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_widen_result.exp new file mode 100644 index 0000000000000..065dfb4facfde --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_widen_result.exp @@ -0,0 +1,31 @@ + +Diagnostics: +error: the function takes `&mut` but `&` was provided + ┌─ tests/checking/typing/lambda_widen_result.move:43:38 + │ +43 │ let r = pass_mut_ref(&mut v, |x| (freeze(x))); + │ ^^^^^^^^^^^^^^^ + +error: the function takes `&mut` but `&` was provided + ┌─ tests/checking/typing/lambda_widen_result.move:65:39 + │ +65 │ let r = pass_mut2_ref(&mut v, |x| (freeze(x))); + │ ^^^^^^^^^^^^^^^ + +error: the function takes `&mut` but `&` was provided + ┌─ tests/checking/typing/lambda_widen_result.move:109:39 + │ +109 │ let r = pass_mut4_ref(&mut v, |x| (freeze(x))); + │ ^^^^^^^^^^^^^^^ + +error: the function takes `&mut` but `&` was provided + ┌─ tests/checking/typing/lambda_widen_result.move:126:38 + │ +126 │ let r = pass_imm_ref(&mut v, |x| freeze(x)); + │ ^^^^^^^^^^^^^ + +error: the function takes `&mut` but `&` was provided + ┌─ tests/checking/typing/lambda_widen_result.move:136:38 + │ +136 │ let r = pass_imm_ref(&mut v, |x| (freeze(x))); + │ ^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/lambda_widen_result.move b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_widen_result.move new file mode 100644 index 0000000000000..f49a5c4a2728e --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_widen_result.move @@ -0,0 +1,138 @@ +module 0x8675309::M { + use std::vector; + + public inline fun pass_mut_ref(v: &mut vector, action: |&mut T|&mut T): &mut T { + action(vector::borrow_mut(v, 0)) + } + + public inline fun pass_mut2_ref(v: &mut vector, action: |&mut T|&mut T): &T { + action(vector::borrow_mut(v, 0)) + } + + public inline fun pass_mut3_ref(v: &mut vector, action: |&mut T|&T): &T { + action(vector::borrow_mut(v, 0)) + } + + public inline fun pass_mut4_ref(v: &mut vector, action: |&T|&T): &T { + action(vector::borrow_mut(v, 0)) + } + + public inline fun pass_imm_ref(v: &mut vector, action: |&T|&T): &T { + return action(vector::borrow(v, 0)) + } + + // 1 + + public fun consume_mut_mut() { + let v = vector[1, 2, 3]; + let r = pass_mut_ref(&mut v, |x| x); + } + + public fun consume_mut_imm() { + let v = vector[1, 2, 3]; + let r = pass_mut_ref(&mut v, |x| x); + } + + public fun consume_mut_untyped() { + let v = vector[1, 2, 3]; + let r = pass_mut_ref(&mut v, |x| x); + } + + public fun consume_mut_freeze() { + let v = vector[1, 2, 3]; + let r = pass_mut_ref(&mut v, |x| (freeze(x))); + } + + // 2 + + public fun consume_mut2_mut() { + let v = vector[1, 2, 3]; + let r = pass_mut2_ref(&mut v, |x| x); + } + + public fun consume_mut2_imm() { + let v = vector[1, 2, 3]; + let r = pass_mut2_ref(&mut v, |x| x); + } + + public fun consume_mut2_untyped() { + let v = vector[1, 2, 3]; + let r = pass_mut2_ref(&mut v, |x| x); + } + + public fun consume_mut2_freeze() { + let v = vector[1, 2, 3]; + let r = pass_mut2_ref(&mut v, |x| (freeze(x))); + } + + // 3 + + public fun consume_mut3_mut() { + let v = vector[1, 2, 3]; + let r = pass_mut3_ref(&mut v, |x| x); + } + + public fun consume_mut3_imm() { + let v = vector[1, 2, 3]; + let r = pass_mut3_ref(&mut v, |x| x); + } + + public fun consume_mut3_untyped() { + let v = vector[1, 2, 3]; + let r = pass_mut3_ref(&mut v, |x| x); + } + + public fun consume_mut3_freeze() { + let v = vector[1, 2, 3]; + let r = pass_mut3_ref(&mut v, |x| (freeze(x))); + } + + // 4 + + public fun consume_mut4_mut() { + let v = vector[1, 2, 3]; + let r = pass_mut4_ref(&mut v, |x| x); + } + + public fun consume_mut4_imm() { + let v = vector[1, 2, 3]; + let r = pass_mut4_ref(&mut v, |x| x); + } + + public fun consume_mut4_untyped() { + let v = vector[1, 2, 3]; + let r = pass_mut4_ref(&mut v, |x| x); + } + + public fun consume_mut4_freeze() { + let v = vector[1, 2, 3]; + let r = pass_mut4_ref(&mut v, |x| (freeze(x))); + } + + // imm + + public fun consume_imm_mut() { + let v = vector[1, 2, 3]; + let r = pass_imm_ref(&mut v, |x| x); + } + + public fun consume_imm_imm() { + let v = vector[1, 2, 3]; + let r = pass_imm_ref(&mut v, |x| x); + } + + public fun consume_imm_imm_freeze() { + let v = vector[1, 2, 3]; + let r = pass_imm_ref(&mut v, |x| freeze(x)); + } + + public fun consume_imm_untyped() { + let v = vector[1, 2, 3]; + let r = pass_imm_ref(&mut v, |x| x); + } + + public fun consume_imm_freeze() { + let v = vector[1, 2, 3]; + let r = pass_imm_ref(&mut v, |x| (freeze(x))); + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/unused_lambda_param_typed.exp b/third_party/move/move-compiler-v2/tests/checking/typing/unused_lambda_param_typed.exp new file mode 100644 index 0000000000000..ca98b47e485f2 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/typing/unused_lambda_param_typed.exp @@ -0,0 +1,26 @@ + +Diagnostics: +warning: Unused anonymous function parameter `x`. Consider removing or prefixing with an underscore: `_x` + ┌─ tests/checking/typing/unused_lambda_param_typed.move:7:18 + │ +7 │ test(0, |x: u64| 1); + │ ^ + +// -- Model dump before bytecode pipeline +module 0xc0ffee::m { + private inline fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + 1; + Tuple() + } + private fun unused_lambda_suppressed1() { + 1; + Tuple() + } + private fun unused_lambda_suppressed2() { + 1; + Tuple() + } +} // end 0xc0ffee::m diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/unused_lambda_param_typed.move b/third_party/move/move-compiler-v2/tests/checking/typing/unused_lambda_param_typed.move new file mode 100644 index 0000000000000..eb82be0c92b67 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/typing/unused_lambda_param_typed.move @@ -0,0 +1,17 @@ +module 0xc0ffee::m { + inline fun test(p: u64, f: |u64| u64): u64 { + f(p) + } + + fun unused_lambda() { + test(0, |x: u64| 1); + } + + fun unused_lambda_suppressed1() { + test(0, |_x: u64| 1); + } + + fun unused_lambda_suppressed2() { + test(0, |_: u64| 1); + } +} diff --git a/third_party/move/move-compiler-v2/tests/file-format-generator/unpack_generic_struct_typed.exp b/third_party/move/move-compiler-v2/tests/file-format-generator/unpack_generic_struct_typed.exp new file mode 100644 index 0000000000000..efb4cdee84f64 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/file-format-generator/unpack_generic_struct_typed.exp @@ -0,0 +1,64 @@ + +============ disassembled file-format ================== +// Move bytecode v7 +module 42.m { +use 0000000000000000000000000000000000000000000000000000000000000001::vector; + + +struct E has copy, drop, store { + key: Ty0 +} +struct Option has copy, drop, store { + vec: vector +} + +public destroy_none(Arg0: Option) /* def_idx: 0 */ { +B0: + 0: ImmBorrowLoc[0](Arg0: Option) + 1: Call is_none(&Option): bool + 2: BrFalse(4) +B1: + 3: Branch(6) +B2: + 4: LdU64(262144) + 5: Abort +B3: + 6: MoveLoc[0](Arg0: Option) + 7: UnpackGeneric[0](Option) + 8: VecUnpack(2, 0) + 9: Ret +} +public foo(Arg0: E, Arg1: &mut Ty0) /* def_idx: 1 */ { +L2: loc0: E +L3: loc1: Ty0 +L4: loc2: E +L5: loc3: E +L6: loc4: u64 +B0: + 0: MoveLoc[0](Arg0: E) + 1: StLoc[2](loc0: E) + 2: MoveLoc[2](loc0: E) + 3: UnpackGeneric[1](E) + 4: StLoc[3](loc1: Ty0) + 5: MoveLoc[3](loc1: Ty0) + 6: PackGeneric[1](E) + 7: StLoc[4](loc2: E) + 8: MoveLoc[4](loc2: E) + 9: StLoc[5](loc3: E) + 10: MoveLoc[5](loc3: E) + 11: UnpackGeneric[1](E) + 12: LdU64(3) + 13: StLoc[6](loc4: u64) + 14: MoveLoc[1](Arg1: &mut Ty0) + 15: WriteRef + 16: Ret +} +public is_none(Arg0: &Option): bool /* def_idx: 2 */ { +B0: + 0: MoveLoc[0](Arg0: &Option) + 1: ImmBorrowFieldGeneric[0](Option.vec: vector) + 2: Call vector::is_empty(&vector): bool + 3: Ret +} +} +============ bytecode verification succeeded ======== diff --git a/third_party/move/move-compiler-v2/tests/file-format-generator/unpack_generic_struct_typed.move b/third_party/move/move-compiler-v2/tests/file-format-generator/unpack_generic_struct_typed.move new file mode 100644 index 0000000000000..a38d3de9db2a4 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/file-format-generator/unpack_generic_struct_typed.move @@ -0,0 +1,42 @@ +module 0x42::m { + use std::vector; + + struct Option has copy, drop, store { + vec: vector + } + + public fun is_none(t: &Option): bool { + vector::is_empty(&t.vec) + } + + public fun destroy_none(t: Option) { + assert!(is_none(&t), 0x40000); + let Option { vec } = t; + vector::destroy_empty(vec) + } + + struct E has copy, drop, store { + key: Key, + } + + public inline fun h(x: E, v: |Key| E): E { + let E { key } = x; + v(key) + } + + public inline fun g(x: E, v: |E|) { + v(x) + } + + public fun foo( + data: E, v: &mut Key) { + let f = h(data, |e: Key| { + E {key: e} + }); + g(f, |e: E| { + let (E { key }, _x) = (e, 3); + *v = key; + }); + } + +} diff --git a/third_party/move/move-compiler-v2/tests/file-format-generator/unpack_generic_struct_typed.opt.exp b/third_party/move/move-compiler-v2/tests/file-format-generator/unpack_generic_struct_typed.opt.exp new file mode 100644 index 0000000000000..046a3069a091c --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/file-format-generator/unpack_generic_struct_typed.opt.exp @@ -0,0 +1,47 @@ + +============ disassembled file-format ================== +// Move bytecode v7 +module 42.m { +use 0000000000000000000000000000000000000000000000000000000000000001::vector; + + +struct E has copy, drop, store { + key: Ty0 +} +struct Option has copy, drop, store { + vec: vector +} + +public destroy_none(Arg0: Option) /* def_idx: 0 */ { +B0: + 0: ImmBorrowLoc[0](Arg0: Option) + 1: Call is_none(&Option): bool + 2: BrFalse(7) +B1: + 3: MoveLoc[0](Arg0: Option) + 4: UnpackGeneric[0](Option) + 5: VecUnpack(2, 0) + 6: Ret +B2: + 7: LdU64(262144) + 8: Abort +} +public foo(Arg0: E, Arg1: &mut Ty0) /* def_idx: 1 */ { +B0: + 0: MoveLoc[0](Arg0: E) + 1: UnpackGeneric[1](E) + 2: PackGeneric[1](E) + 3: UnpackGeneric[1](E) + 4: MoveLoc[1](Arg1: &mut Ty0) + 5: WriteRef + 6: Ret +} +public is_none(Arg0: &Option): bool /* def_idx: 2 */ { +B0: + 0: MoveLoc[0](Arg0: &Option) + 1: ImmBorrowFieldGeneric[0](Option.vec: vector) + 2: Call vector::is_empty(&vector): bool + 3: Ret +} +} +============ bytecode verification succeeded ======== diff --git a/third_party/move/move-compiler-v2/tests/live-var/mut_inline_typed.exp b/third_party/move/move-compiler-v2/tests/live-var/mut_inline_typed.exp new file mode 100644 index 0000000000000..294f89be7fbf0 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/live-var/mut_inline_typed.exp @@ -0,0 +1,291 @@ +============ initial bytecode ================ + +[variant baseline] +fun m::foo(): u64 { + var $t0: u64 + var $t1: vector + var $t2: &mut vector + var $t3: u64 + var $t4: &mut vector + var $t5: u64 + var $t6: u64 + var $t7: &vector + var $t8: bool + var $t9: bool + var $t10: bool + var $t11: &u64 + var $t12: &u64 + var $t13: &vector + var $t14: u64 + var $t15: u64 + var $t16: u64 + var $t17: u64 + var $t18: u64 + var $t19: u64 + var $t20: u64 + var $t21: bool + var $t22: bool + var $t23: &u64 + var $t24: &u64 + var $t25: &vector + var $t26: u64 + var $t27: u64 + var $t28: u64 + var $t29: u64 + var $t30: u64 + var $t31: u64 + var $t32: &u64 + var $t33: &vector + var $t34: u64 + 0: $t1 := ["1", "2", "3"] + 1: $t2 := borrow_local($t1) + 2: $t4 := infer($t2) + 3: $t5 := 0 + 4: $t7 := freeze_ref(implicit)($t4) + 5: $t6 := vector::length($t7) + 6: label L0 + 7: $t8 := <($t5, $t6) + 8: if ($t8) goto 9 else goto 27 + 9: label L2 + 10: $t13 := freeze_ref(implicit)($t4) + 11: $t12 := vector::borrow($t13, $t5) + 12: $t11 := infer($t12) + 13: $t14 := read_ref($t11) + 14: $t15 := 1 + 15: $t10 := >($t14, $t15) + 16: $t9 := !($t10) + 17: if ($t9) goto 18 else goto 21 + 18: label L5 + 19: goto 31 + 20: goto 22 + 21: label L6 + 22: label L7 + 23: $t17 := 1 + 24: $t16 := +($t5, $t17) + 25: $t5 := infer($t16) + 26: goto 29 + 27: label L3 + 28: goto 31 + 29: label L4 + 30: goto 6 + 31: label L1 + 32: $t18 := infer($t5) + 33: $t20 := 1 + 34: $t19 := +($t5, $t20) + 35: $t5 := infer($t19) + 36: label L8 + 37: $t21 := <($t5, $t6) + 38: if ($t21) goto 39 else goto 59 + 39: label L10 + 40: $t25 := freeze_ref(implicit)($t4) + 41: $t24 := vector::borrow($t25, $t5) + 42: $t23 := infer($t24) + 43: $t26 := read_ref($t23) + 44: $t27 := 1 + 45: $t22 := >($t26, $t27) + 46: if ($t22) goto 47 else goto 53 + 47: label L13 + 48: vector::swap($t4, $t18, $t5) + 49: $t29 := 1 + 50: $t28 := +($t18, $t29) + 51: $t18 := infer($t28) + 52: goto 54 + 53: label L14 + 54: label L15 + 55: $t31 := 1 + 56: $t30 := +($t5, $t31) + 57: $t5 := infer($t30) + 58: goto 61 + 59: label L11 + 60: goto 63 + 61: label L12 + 62: goto 36 + 63: label L9 + 64: $t3 := infer($t18) + 65: $t33 := freeze_ref(implicit)($t2) + 66: $t34 := 0 + 67: $t32 := vector::borrow($t33, $t34) + 68: $t0 := read_ref($t32) + 69: return $t0 +} + +============ after LiveVarAnalysisProcessor: ================ + +[variant baseline] +fun m::foo(): u64 { + var $t0: u64 + var $t1: vector + var $t2: &mut vector + var $t3: u64 + var $t4: &mut vector + var $t5: u64 + var $t6: u64 + var $t7: &vector + var $t8: bool + var $t9: bool + var $t10: bool + var $t11: &u64 + var $t12: &u64 + var $t13: &vector + var $t14: u64 + var $t15: u64 + var $t16: u64 + var $t17: u64 + var $t18: u64 + var $t19: u64 + var $t20: u64 + var $t21: bool + var $t22: bool + var $t23: &u64 + var $t24: &u64 + var $t25: &vector + var $t26: u64 + var $t27: u64 + var $t28: u64 + var $t29: u64 + var $t30: u64 + var $t31: u64 + var $t32: &u64 + var $t33: &vector + var $t34: u64 + # live vars: + 0: $t1 := ["1", "2", "3"] + # live vars: $t1 + 1: $t2 := borrow_local($t1) + # live vars: $t2 + 2: $t4 := infer($t2) + # live vars: $t2, $t4 + 3: $t5 := 0 + # live vars: $t2, $t4, $t5 + 4: $t7 := freeze_ref(implicit)($t4) + # live vars: $t2, $t4, $t5, $t7 + 5: $t6 := vector::length($t7) + # live vars: $t2, $t4, $t5, $t6 + 6: label L0 + # live vars: $t2, $t4, $t5, $t6 + 7: $t8 := <($t5, $t6) + # live vars: $t2, $t4, $t5, $t6, $t8 + 8: if ($t8) goto 9 else goto 27 + # live vars: $t2, $t4, $t5, $t6 + 9: label L2 + # live vars: $t2, $t4, $t5, $t6 + 10: $t13 := freeze_ref(implicit)($t4) + # live vars: $t2, $t4, $t5, $t6, $t13 + 11: $t12 := vector::borrow($t13, $t5) + # live vars: $t2, $t4, $t5, $t6, $t12 + 12: $t11 := infer($t12) + # live vars: $t2, $t4, $t5, $t6, $t11 + 13: $t14 := read_ref($t11) + # live vars: $t2, $t4, $t5, $t6, $t14 + 14: $t15 := 1 + # live vars: $t2, $t4, $t5, $t6, $t14, $t15 + 15: $t10 := >($t14, $t15) + # live vars: $t2, $t4, $t5, $t6, $t10 + 16: $t9 := !($t10) + # live vars: $t2, $t4, $t5, $t6, $t9 + 17: if ($t9) goto 18 else goto 21 + # live vars: $t2, $t4, $t5, $t6 + 18: label L5 + # live vars: $t2, $t4, $t5, $t6 + 19: goto 31 + # live vars: $t2, $t4, $t5, $t6 + 20: goto 22 + # live vars: $t2, $t4, $t5, $t6 + 21: label L6 + # live vars: $t2, $t4, $t5, $t6 + 22: label L7 + # live vars: $t2, $t4, $t5, $t6 + 23: $t17 := 1 + # live vars: $t2, $t4, $t5, $t6, $t17 + 24: $t16 := +($t5, $t17) + # live vars: $t2, $t4, $t6, $t16 + 25: $t5 := infer($t16) + # live vars: $t2, $t4, $t5, $t6 + 26: goto 29 + # live vars: $t2, $t4, $t5, $t6 + 27: label L3 + # live vars: $t2, $t4, $t5, $t6 + 28: goto 31 + # live vars: $t2, $t4, $t5, $t6 + 29: label L4 + # live vars: $t2, $t4, $t5, $t6 + 30: goto 6 + # live vars: $t2, $t4, $t5, $t6 + 31: label L1 + # live vars: $t2, $t4, $t5, $t6 + 32: $t18 := infer($t5) + # live vars: $t2, $t4, $t5, $t6, $t18 + 33: $t20 := 1 + # live vars: $t2, $t4, $t5, $t6, $t18, $t20 + 34: $t19 := +($t5, $t20) + # live vars: $t2, $t4, $t6, $t18, $t19 + 35: $t5 := infer($t19) + # live vars: $t2, $t4, $t5, $t6, $t18 + 36: label L8 + # live vars: $t2, $t4, $t5, $t6, $t18 + 37: $t21 := <($t5, $t6) + # live vars: $t2, $t4, $t5, $t6, $t18, $t21 + 38: if ($t21) goto 39 else goto 59 + # live vars: $t2, $t4, $t5, $t6, $t18 + 39: label L10 + # live vars: $t2, $t4, $t5, $t6, $t18 + 40: $t25 := freeze_ref(implicit)($t4) + # live vars: $t2, $t4, $t5, $t6, $t18, $t25 + 41: $t24 := vector::borrow($t25, $t5) + # live vars: $t2, $t4, $t5, $t6, $t18, $t24 + 42: $t23 := infer($t24) + # live vars: $t2, $t4, $t5, $t6, $t18, $t23 + 43: $t26 := read_ref($t23) + # live vars: $t2, $t4, $t5, $t6, $t18, $t26 + 44: $t27 := 1 + # live vars: $t2, $t4, $t5, $t6, $t18, $t26, $t27 + 45: $t22 := >($t26, $t27) + # live vars: $t2, $t4, $t5, $t6, $t18, $t22 + 46: if ($t22) goto 47 else goto 53 + # live vars: $t2, $t4, $t5, $t6, $t18 + 47: label L13 + # live vars: $t2, $t4, $t5, $t6, $t18 + 48: vector::swap($t4, $t18, $t5) + # live vars: $t2, $t4, $t5, $t6, $t18 + 49: $t29 := 1 + # live vars: $t2, $t4, $t5, $t6, $t18, $t29 + 50: $t28 := +($t18, $t29) + # live vars: $t2, $t4, $t5, $t6, $t28 + 51: $t18 := infer($t28) + # live vars: $t2, $t4, $t5, $t6, $t18 + 52: goto 54 + # live vars: $t2, $t4, $t5, $t6, $t18 + 53: label L14 + # live vars: $t2, $t4, $t5, $t6, $t18 + 54: label L15 + # live vars: $t2, $t4, $t5, $t6, $t18 + 55: $t31 := 1 + # live vars: $t2, $t4, $t5, $t6, $t18, $t31 + 56: $t30 := +($t5, $t31) + # live vars: $t2, $t4, $t6, $t18, $t30 + 57: $t5 := infer($t30) + # live vars: $t2, $t4, $t5, $t6, $t18 + 58: goto 61 + # live vars: $t2, $t4, $t5, $t6, $t18 + 59: label L11 + # live vars: $t2, $t18 + 60: goto 63 + # live vars: $t2, $t4, $t5, $t6, $t18 + 61: label L12 + # live vars: $t2, $t4, $t5, $t6, $t18 + 62: goto 36 + # live vars: $t2, $t18 + 63: label L9 + # live vars: $t2, $t18 + 64: $t3 := infer($t18) + # live vars: $t2 + 65: $t33 := freeze_ref(implicit)($t2) + # live vars: $t33 + 66: $t34 := 0 + # live vars: $t33, $t34 + 67: $t32 := vector::borrow($t33, $t34) + # live vars: $t32 + 68: $t0 := read_ref($t32) + # live vars: $t0 + 69: return $t0 +} diff --git a/third_party/move/move-compiler-v2/tests/live-var/mut_inline_typed.move b/third_party/move/move-compiler-v2/tests/live-var/mut_inline_typed.move new file mode 100644 index 0000000000000..89bc2d57d9728 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/live-var/mut_inline_typed.move @@ -0,0 +1,34 @@ +module 0x42::m { + + use 0x1::vector; + + inline fun partition( + v: &mut vector, + pred: |&Element|bool + ): u64 { + let i = 0; + let len = vector::length(v); + while (i < len) { + if (!pred(vector::borrow(v, i))) break; + i = i + 1; + }; + let p = i; + i = i + 1; + while (i < len) { + if (pred(vector::borrow(v, i))) { + vector::swap(v, p, i); + p = p + 1; + }; + i = i + 1; + }; + p + } + + fun foo(): u64 { + let v = vector[1,2,3]; + let r = &mut v; + partition(r, |e: &u64| *e > 1); + *vector::borrow(r, 0) + } + +} diff --git a/third_party/move/move-compiler-v2/tests/variable-coalescing/inlining1_typed.exp b/third_party/move/move-compiler-v2/tests/variable-coalescing/inlining1_typed.exp new file mode 100644 index 0000000000000..39832e3a20b40 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/variable-coalescing/inlining1_typed.exp @@ -0,0 +1,80 @@ +============ initial bytecode ================ + +[variant baseline] +public fun Test::test(): u64 { + var $t0: u64 + var $t1: u64 + var $t2: u64 + var $t3: u64 + 0: $t2 := 10 + 1: $t1 := infer($t2) + 2: $t3 := infer($t1) + 3: $t0 := 3 + 4: return $t0 +} + +============ after DeadStoreElimination: ================ + +[variant baseline] +public fun Test::test(): u64 { + var $t0: u64 + var $t1: u64 [unused] + var $t2: u64 [unused] + var $t3: u64 [unused] + 0: $t0 := 3 + 1: return $t0 +} + +============ after VariableCoalescingAnnotator: ================ + +[variant baseline] +public fun Test::test(): u64 { + var $t0: u64 + var $t1: u64 [unused] + var $t2: u64 [unused] + var $t3: u64 [unused] + # live vars: + # events: b:$t0 + 0: $t0 := 3 + # live vars: $t0 + # events: e:$t0 + 1: return $t0 +} + +============ after VariableCoalescingTransformer: ================ + +[variant baseline] +public fun Test::test(): u64 { + var $t0: u64 + var $t1: u64 [unused] + var $t2: u64 [unused] + var $t3: u64 [unused] + 0: $t0 := 3 + 1: return $t0 +} + +============ after DeadStoreElimination: ================ + +[variant baseline] +public fun Test::test(): u64 { + var $t0: u64 + var $t1: u64 [unused] + var $t2: u64 [unused] + var $t3: u64 [unused] + 0: $t0 := 3 + 1: return $t0 +} + + +============ disassembled file-format ================== +// Move bytecode v7 +module 42.Test { + + +public test(): u64 /* def_idx: 0 */ { +B0: + 0: LdU64(3) + 1: Ret +} +} +============ bytecode verification succeeded ======== diff --git a/third_party/move/move-compiler-v2/tests/variable-coalescing/inlining1_typed.move b/third_party/move/move-compiler-v2/tests/variable-coalescing/inlining1_typed.move new file mode 100644 index 0000000000000..9d529bc3acaab --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/variable-coalescing/inlining1_typed.move @@ -0,0 +1,9 @@ +module 0x42::Test { + inline fun foo(f:|u64| u64, x: u64): u64 { + f(x) + } + + public fun test(): u64 { + foo(|_: u64| 3, 10) + } +} diff --git a/third_party/move/move-compiler-v2/tests/variable-coalescing/inlining1_typed.opt.exp b/third_party/move/move-compiler-v2/tests/variable-coalescing/inlining1_typed.opt.exp new file mode 100644 index 0000000000000..fdf29d55e2bf7 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/variable-coalescing/inlining1_typed.opt.exp @@ -0,0 +1,62 @@ +============ initial bytecode ================ + +[variant baseline] +public fun Test::test(): u64 { + var $t0: u64 + 0: $t0 := 3 + 1: return $t0 +} + +============ after DeadStoreElimination: ================ + +[variant baseline] +public fun Test::test(): u64 { + var $t0: u64 + 0: $t0 := 3 + 1: return $t0 +} + +============ after VariableCoalescingAnnotator: ================ + +[variant baseline] +public fun Test::test(): u64 { + var $t0: u64 + # live vars: + # events: b:$t0 + 0: $t0 := 3 + # live vars: $t0 + # events: e:$t0 + 1: return $t0 +} + +============ after VariableCoalescingTransformer: ================ + +[variant baseline] +public fun Test::test(): u64 { + var $t0: u64 + 0: $t0 := 3 + 1: return $t0 +} + +============ after DeadStoreElimination: ================ + +[variant baseline] +public fun Test::test(): u64 { + var $t0: u64 + 0: $t0 := 3 + 1: return $t0 +} + + +============ disassembled file-format ================== +// Move bytecode v7 +module 42.Test { + + +public test(): u64 /* def_idx: 0 */ { +B0: + 0: LdU64(3) + 1: Ret +} +} +============ bytecode verification succeeded ======== diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991_noparam2_typed.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991_noparam2_typed.exp new file mode 100644 index 0000000000000..9387f12a2dcb1 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991_noparam2_typed.exp @@ -0,0 +1,29 @@ +comparison between v1 and v2 failed: +- processed 2 tasks +- +- task 0 'publish'. lines 1-10: +- Error: error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:22 +- │ +- 7 │ assert!(foo(|_: u64| 3, |_: u64| 10, 10, 100) == 13, 0); +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:34 +- │ +- 7 │ assert!(foo(|_: u64| 3, |_: u64| 10, 10, 100) == 13, 0); +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- +- +- task 1 'run'. lines 12-12: +- Error: Function execution failed with VMError: { +- major_status: LINKER_ERROR, +- sub_status: None, +- location: undefined, +- indices: redacted, +- offsets: redacted, +- } +- ++ processed 2 tasks ++ diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991_noparam2_typed.move b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991_noparam2_typed.move new file mode 100644 index 0000000000000..6ef383a7b98a8 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991_noparam2_typed.move @@ -0,0 +1,12 @@ +//# publish +module 0x42::Test { + inline fun foo(f:|u64| u64, g: |u64| u64, x: u64, _: u64): u64 { + f(x) + g(x) + } + + public fun test() { + assert!(foo(|_: u64| 3, |_: u64| 10, 10, 100) == 13, 0); + } +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991_noparam_typed.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991_noparam_typed.exp new file mode 100644 index 0000000000000..6b250eae787df --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991_noparam_typed.exp @@ -0,0 +1,41 @@ +comparison between v1 and v2 failed: +- processed 2 tasks +- +- task 0 'publish'. lines 1-10: +- Error: error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:22 +- │ +- 7 │ assert!(foo(|_: u64, _: u64| 3, |_: u64, _: u64| 10, 10, 100) == 13, 0); +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:30 +- │ +- 7 │ assert!(foo(|_: u64, _: u64| 3, |_: u64, _: u64| 10, 10, 100) == 13, 0); +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:42 +- │ +- 7 │ assert!(foo(|_: u64, _: u64| 3, |_: u64, _: u64| 10, 10, 100) == 13, 0); +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:50 +- │ +- 7 │ assert!(foo(|_: u64, _: u64| 3, |_: u64, _: u64| 10, 10, 100) == 13, 0); +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- +- +- task 1 'run'. lines 12-12: +- Error: Function execution failed with VMError: { +- major_status: LINKER_ERROR, +- sub_status: None, +- location: undefined, +- indices: redacted, +- offsets: redacted, +- } +- ++ processed 2 tasks ++ diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991_noparam_typed.move b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991_noparam_typed.move new file mode 100644 index 0000000000000..72091d0cdfb9c --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991_noparam_typed.move @@ -0,0 +1,12 @@ +//# publish +module 0x42::Test { + inline fun foo(f:|u64, u64| u64, g: |u64, u64| u64, x: u64, _y: u64): u64 { + f(x, _y) + g(x, _y) + } + + public fun test() { + assert!(foo(|_: u64, _: u64| 3, |_: u64, _: u64| 10, 10, 100) == 13, 0); + } +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991_typed.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991_typed.exp new file mode 100644 index 0000000000000..f74668967d29c --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991_typed.exp @@ -0,0 +1,41 @@ +comparison between v1 and v2 failed: +- processed 2 tasks +- +- task 0 'publish'. lines 1-10: +- Error: error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:22 +- │ +- 7 │ assert!(foo(|x: u64, _: u64| x, |_: u64, y: u64| y, 10, 100) == 110, 0); +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:30 +- │ +- 7 │ assert!(foo(|x: u64, _: u64| x, |_: u64, y: u64| y, 10, 100) == 110, 0); +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:42 +- │ +- 7 │ assert!(foo(|x: u64, _: u64| x, |_: u64, y: u64| y, 10, 100) == 110, 0); +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:50 +- │ +- 7 │ assert!(foo(|x: u64, _: u64| x, |_: u64, y: u64| y, 10, 100) == 110, 0); +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- +- +- task 1 'run'. lines 12-12: +- Error: Function execution failed with VMError: { +- major_status: LINKER_ERROR, +- sub_status: None, +- location: undefined, +- indices: redacted, +- offsets: redacted, +- } +- ++ processed 2 tasks ++ diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991_typed.move b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991_typed.move new file mode 100644 index 0000000000000..da836f0f58d51 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991_typed.move @@ -0,0 +1,12 @@ +//# publish +module 0x42::Test { + inline fun foo(f:|u64, u64| u64, g: |u64, u64| u64, x: u64, _y: u64): u64 { + f(x, _y) + g(x, _y) + } + + public fun test() { + assert!(foo(|x: u64, _: u64| x, |_: u64, y: u64| y, 10, 100) == 110, 0); + } +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991a_typed.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991a_typed.exp new file mode 100644 index 0000000000000..7539b24f5e319 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991a_typed.exp @@ -0,0 +1,65 @@ +comparison between v1 and v2 failed: +- processed 2 tasks +- +- task 0 'publish'. lines 1-14: +- Error: error[E01013]: unsupported language construct +- ┌─ TEMPFILE:9:22 +- │ +- 9 │ assert!(foo(|x: u64, _: u64| x, |_: u64, y: u64| y, +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:9:30 +- │ +- 9 │ assert!(foo(|x: u64, _: u64| x, |_: u64, y: u64| y, +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:9:42 +- │ +- 9 │ assert!(foo(|x: u64, _: u64| x, |_: u64, y: u64| y, +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:9:50 +- │ +- 9 │ assert!(foo(|x: u64, _: u64| x, |_: u64, y: u64| y, +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:10:7 +- │ +- 10 │ |a: u64, _b: u64| a, |_c: u64, d: u64| d, +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:10:15 +- │ +- 10 │ |a: u64, _b: u64| a, |_c: u64, d: u64| d, +- │ ^^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:10:28 +- │ +- 10 │ |a: u64, _b: u64| a, |_c: u64, d: u64| d, +- │ ^^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:10:37 +- │ +- 10 │ |a: u64, _b: u64| a, |_c: u64, d: u64| d, +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- +- +- task 1 'run'. lines 16-16: +- Error: Function execution failed with VMError: { +- major_status: LINKER_ERROR, +- sub_status: None, +- location: undefined, +- indices: redacted, +- offsets: redacted, +- } +- ++ processed 2 tasks ++ diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991a_typed.move b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991a_typed.move new file mode 100644 index 0000000000000..28f6de500dc78 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991a_typed.move @@ -0,0 +1,16 @@ +//# publish +module 0x42::Test { + inline fun foo(f:|u64, u64| u64, g: |u64, u64| u64, + h:|u64, u64| u64, i: |u64, u64| u64, + x: u64, y: u64): u64 { + f(x, y) + g(x, y) + h(x, y) + i(x, y) + } + + public fun test() { + assert!(foo(|x: u64, _: u64| x, |_: u64, y: u64| y, + |a: u64, _b: u64| a, |_c: u64, d: u64| d, + 10, 100) == 220, 0); + } +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991b_typed.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991b_typed.exp new file mode 100644 index 0000000000000..9c60f12f7e43e --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991b_typed.exp @@ -0,0 +1,29 @@ +comparison between v1 and v2 failed: +- processed 2 tasks +- +- task 0 'publish'. lines 1-11: +- Error: error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:22 +- │ +- 7 │ assert!(foo(|_: u64, y: u64| y, +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:30 +- │ +- 7 │ assert!(foo(|_: u64, y: u64| y, +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- +- +- task 1 'run'. lines 13-13: +- Error: Function execution failed with VMError: { +- major_status: LINKER_ERROR, +- sub_status: None, +- location: undefined, +- indices: redacted, +- offsets: redacted, +- } +- ++ processed 2 tasks ++ diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991b_typed.move b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991b_typed.move new file mode 100644 index 0000000000000..29521a95ac5c6 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991b_typed.move @@ -0,0 +1,13 @@ +//# publish +module 0x42::Test { + inline fun foo(g: |u64, u64| u64, x: u64, _y: u64): u64 { + g(x, _y) + } + + public fun test() { + assert!(foo(|_: u64, y: u64| y, + 10, 100) == 100, 0); + } +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991c_typed.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991c_typed.exp new file mode 100644 index 0000000000000..49eacd34742fd --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991c_typed.exp @@ -0,0 +1,41 @@ +comparison between v1 and v2 failed: +- processed 2 tasks +- +- task 0 'publish'. lines 1-11: +- Error: error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:22 +- │ +- 7 │ assert!(foo(|_: u64, y: u64, _: u64, q: u64| y + q, +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:30 +- │ +- 7 │ assert!(foo(|_: u64, y: u64, _: u64, q: u64| y + q, +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:38 +- │ +- 7 │ assert!(foo(|_: u64, y: u64, _: u64, q: u64| y + q, +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:46 +- │ +- 7 │ assert!(foo(|_: u64, y: u64, _: u64, q: u64| y + q, +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- +- +- task 1 'run'. lines 13-13: +- Error: Function execution failed with VMError: { +- major_status: LINKER_ERROR, +- sub_status: None, +- location: undefined, +- indices: redacted, +- offsets: redacted, +- } +- ++ processed 2 tasks ++ diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991c_typed.move b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991c_typed.move new file mode 100644 index 0000000000000..71ff4b6e6ebc7 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/bug_10991c_typed.move @@ -0,0 +1,13 @@ +//# publish +module 0x42::Test { + inline fun foo(g: |u64, u64, u64, u64| u64, x: u64, y: u64, z: u64, q:u64): u64 { + g(x, y, z, q) + } + + public fun test() { + assert!(foo(|_: u64, y: u64, _: u64, q: u64| y + q, + 10, 100, 1000, 10000) == 10100, 0); + } +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/eval_ignored_param_some_typed.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/eval_ignored_param_some_typed.exp new file mode 100644 index 0000000000000..11c5e581bd202 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/eval_ignored_param_some_typed.exp @@ -0,0 +1,35 @@ +comparison between v1 and v2 failed: +- processed 2 tasks +- +- task 0 'publish'. lines 1-13: +- Error: error[E01013]: unsupported language construct +- ┌─ TEMPFILE:9:15 +- │ +- 9 │ let r = foo(|x: u64, _: u64, z| x*z, |_, y: u64, _| y, 1, 10, 100, 1000); +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:9:23 +- │ +- 9 │ let r = foo(|x: u64, _: u64, z| x*z, |_, y: u64, _| y, 1, 10, 100, 1000); +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:9:43 +- │ +- 9 │ let r = foo(|x: u64, _: u64, z| x*z, |_, y: u64, _| y, 1, 10, 100, 1000); +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- +- +- task 1 'run'. lines 15-15: +- Error: Function execution failed with VMError: { +- major_status: LINKER_ERROR, +- sub_status: None, +- location: undefined, +- indices: redacted, +- offsets: redacted, +- } +- ++ processed 2 tasks ++ diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/eval_ignored_param_some_typed.move b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/eval_ignored_param_some_typed.move new file mode 100644 index 0000000000000..ed65160f1f2b6 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/eval_ignored_param_some_typed.move @@ -0,0 +1,15 @@ +//# publish +module 0x42::Test { + inline fun foo(f:|u64, u64, u64| u64, g: |u64, u64, u64| u64, x: u64, _: u64, y: u64, z: u64): u64 { + let r1 = f({x = x + 1; x}, {y = y + 1; y}, {z = z + 1; z}); + let r2 = g({x = x + 1; x}, {y = y + 1; y}, {z = z + 1 ; z}); + r1 + r2 + 3*x + 5*y + 7*z + } + + public fun test() { + let r = foo(|x: u64, _: u64, z| x*z, |_, y: u64, _| y, 1, 10, 100, 1000); + assert!(r == 9637, r); + } +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/eval_ignored_param_typed.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/eval_ignored_param_typed.exp new file mode 100644 index 0000000000000..8059ac92a5e46 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/eval_ignored_param_typed.exp @@ -0,0 +1,53 @@ +comparison between v1 and v2 failed: +- processed 2 tasks +- +- task 0 'publish'. lines 1-13: +- Error: error[E01013]: unsupported language construct +- ┌─ TEMPFILE:9:15 +- │ +- 9 │ let r = foo(|x: u64, _: u64, z: u64| x*z, |_: u64, y: u64, _: u64| y, 1, 10, 100, 1000); +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:9:23 +- │ +- 9 │ let r = foo(|x: u64, _: u64, z: u64| x*z, |_: u64, y: u64, _: u64| y, 1, 10, 100, 1000); +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:9:31 +- │ +- 9 │ let r = foo(|x: u64, _: u64, z: u64| x*z, |_: u64, y: u64, _: u64| y, 1, 10, 100, 1000); +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:9:45 +- │ +- 9 │ let r = foo(|x: u64, _: u64, z: u64| x*z, |_: u64, y: u64, _: u64| y, 1, 10, 100, 1000); +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:9:53 +- │ +- 9 │ let r = foo(|x: u64, _: u64, z: u64| x*z, |_: u64, y: u64, _: u64| y, 1, 10, 100, 1000); +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:9:61 +- │ +- 9 │ let r = foo(|x: u64, _: u64, z: u64| x*z, |_: u64, y: u64, _: u64| y, 1, 10, 100, 1000); +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- +- +- task 1 'run'. lines 15-15: +- Error: Function execution failed with VMError: { +- major_status: LINKER_ERROR, +- sub_status: None, +- location: undefined, +- indices: redacted, +- offsets: redacted, +- } +- ++ processed 2 tasks ++ diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/eval_ignored_param_typed.move b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/eval_ignored_param_typed.move new file mode 100644 index 0000000000000..d3f74b0d6d903 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/eval_ignored_param_typed.move @@ -0,0 +1,15 @@ +//# publish +module 0x42::Test { + inline fun foo(f:|u64, u64, u64| u64, g: |u64, u64, u64| u64, x: u64, _: u64, y: u64, z: u64): u64 { + let r1 = f({x = x + 1; x}, {y = y + 1; y}, {z = z + 1; z}); + let r2 = g({x = x + 1; x}, {y = y + 1; y}, {z = z + 1 ; z}); + r1 + r2 + 3*x + 5*y + 7*z + } + + public fun test() { + let r = foo(|x: u64, _: u64, z: u64| x*z, |_: u64, y: u64, _: u64| y, 1, 10, 100, 1000); + assert!(r == 9637, r); + } +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/generics_typed.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/generics_typed.exp new file mode 100644 index 0000000000000..af1df06d30d62 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/generics_typed.exp @@ -0,0 +1,23 @@ +comparison between v1 and v2 failed: +- processed 2 tasks ++ processed 2 tasks += +- task 0 'publish'. lines 1-20: +- Error: error[E01013]: unsupported language construct +- ┌─ TEMPFILE:14:27 +- │ +- 14 │ foreach(&v, |e: &u64| sum = sum + *e); +- │ ^^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- +- += task 1 'run'. lines 22-22: +- Error: Function execution failed with VMError: { +- major_status: LINKER_ERROR, +- sub_status: None, +- location: undefined, +- indices: redacted, +- offsets: redacted, +- } ++ return values: 6 += diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/generics_typed.move b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/generics_typed.move new file mode 100644 index 0000000000000..15d9a5f191409 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/generics_typed.move @@ -0,0 +1,22 @@ +//# publish +module 0x42::Test { + use std::vector; + + public inline fun foreach(v: &vector, action: |&X|) { + let i = 0; + while (i < vector::length(v)) { + action(vector::borrow(v, i)); + i = i + 1; + } + } + + public fun test(): u64 { + let v = vector[1u64, 2, 3]; + let sum = 0; + foreach(&v, |e: &u64| sum = sum + *e); + sum + } + +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/lambda_typed.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/lambda_typed.exp new file mode 100644 index 0000000000000..b1f5feed168f0 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/lambda_typed.exp @@ -0,0 +1,29 @@ +comparison between v1 and v2 failed: +- processed 2 tasks ++ processed 2 tasks += +- task 0 'publish'. lines 1-11: +- Error: error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:16 +- │ +- 7 │ apply(|x: u64, y: u64| x + y, 1, 2) +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:24 +- │ +- 7 │ apply(|x: u64, y: u64| x + y, 1, 2) +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- +- += task 1 'run'. lines 13-13: +- Error: Function execution failed with VMError: { +- major_status: LINKER_ERROR, +- sub_status: None, +- location: undefined, +- indices: redacted, +- offsets: redacted, +- } ++ return values: 3 += diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/lambda_typed.move b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/lambda_typed.move new file mode 100644 index 0000000000000..6d28935c398ff --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/lambda_typed.move @@ -0,0 +1,13 @@ +//# publish +module 0x42::Test { + + public inline fun apply(f: |u64, u64|u64, x: u64, y: u64): u64 { + f(x, y) + } + + public fun test(): u64 { + apply(|x: u64, y: u64| x + y, 1, 2) + } +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/masking_typed.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/masking_typed.exp new file mode 100644 index 0000000000000..0c99da555042f --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/masking_typed.exp @@ -0,0 +1,41 @@ +comparison between v1 and v2 failed: +- processed 2 tasks ++ processed 2 tasks += +- task 0 'publish'. lines 1-10: +- Error: error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:14 +- │ +- 7 │ foo(|x: u64, _: u64| x, |_: u64, y: u64| y, 10, 100) +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:22 +- │ +- 7 │ foo(|x: u64, _: u64| x, |_: u64, y: u64| y, 10, 100) +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:34 +- │ +- 7 │ foo(|x: u64, _: u64| x, |_: u64, y: u64| y, 10, 100) +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:42 +- │ +- 7 │ foo(|x: u64, _: u64| x, |_: u64, y: u64| y, 10, 100) +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- +- += task 1 'run'. lines 12-12: +- Error: Function execution failed with VMError: { +- major_status: LINKER_ERROR, +- sub_status: None, +- location: undefined, +- indices: redacted, +- offsets: redacted, +- } ++ return values: 110 += diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/masking_typed.move b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/masking_typed.move new file mode 100644 index 0000000000000..5681fa39b26b1 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/masking_typed.move @@ -0,0 +1,12 @@ +//# publish +module 0x42::Test { + inline fun foo(f:|u64, u64| u64, g: |u64, u64| u64, x: u64, _y: u64): u64 { + f(x, _y) + g(x, _y) + } + + public fun main(): u64 { + foo(|x: u64, _: u64| x, |_: u64, y: u64| y, 10, 100) + } +} + +//# run 0x42::Test::main diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/multi_param_typed.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/multi_param_typed.exp new file mode 100644 index 0000000000000..a4bb458cc6f57 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/multi_param_typed.exp @@ -0,0 +1,44 @@ +comparison between v1 and v2 failed: += processed 2 tasks += += task 0 'publish'. lines 1-29: +- Error: error[E01013]: unsupported language construct +- ┌─ TEMPFILE:17:30 ++ Error: compilation errors: ++ error: a reference is expected but `_` was provided ++ ┌─ TEMPFILE:24:82 += │ +- 17 │ for_each_ref_mut(v, |elem: &mut Elem| { +- │ ^^^^^^^^^^^^^^^^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond ++ 24 │ assert!(elem_for_each_ref(&mut vector[Elem{k:1, v:2}], |x: u64, y: u64| *x + *y) == 3, 0) ++ │ ^ += +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:24:65 ++ error: a reference is expected but `_` was provided ++ ┌─ TEMPFILE:24:87 += │ += 24 │ assert!(elem_for_each_ref(&mut vector[Elem{k:1, v:2}], |x: u64, y: u64| *x + *y) == 3, 0) +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond ++ │ ^ += +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:24:73 ++ error: cannot pass `|(u64, u64)|integer` to a function which expects argument of type `|(&integer, &mut integer)|u64` ++ ┌─ TEMPFILE:24:64 += │ += 24 │ assert!(elem_for_each_ref(&mut vector[Elem{k:1, v:2}], |x: u64, y: u64| *x + *y) == 3, 0) +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond ++ │ ^^^^^^^^^^^^^^^^^^^^^^^^ += += += += task 1 'run'. lines 31-31: += Error: Function execution failed with VMError: { += major_status: LINKER_ERROR, += sub_status: None, += location: undefined, += indices: redacted, += offsets: redacted, += } += diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/multi_param_typed.move b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/multi_param_typed.move new file mode 100644 index 0000000000000..425abd583731f --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/multi_param_typed.move @@ -0,0 +1,31 @@ +//# publish +module 0x42::Test { + use 0x1::vector as V; + + // Can't use that from V because of precompiled import in transactional tests + // TODO: we need to fix this + public inline fun for_each_ref_mut(v: &mut vector, f: |&mut Element|) { + let i = 0; + while (i < V::length(v)) { + f(V::borrow_mut(v, i)); + i = i + 1 + } + } + struct Elem has drop { k: K, v: V } + + // Checks a multi-mutality scenario. + public inline fun elem_for_each_ref(v: &mut vector>, f: |&K, &mut V|u64): u64 { + let result = 0; + for_each_ref_mut(v, |elem: &mut Elem| { + let elem: &mut Elem = elem; // Checks whether scoping is fine + result = result + f(&elem.k, &mut elem.v); + }); + result + } + + public fun test() { + assert!(elem_for_each_ref(&mut vector[Elem{k:1, v:2}], |x: u64, y: u64| *x + *y) == 3, 0) + } +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/nested_lambda_module_typed.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/nested_lambda_module_typed.exp new file mode 100644 index 0000000000000..c32e5f2c5983d --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/nested_lambda_module_typed.exp @@ -0,0 +1,41 @@ +comparison between v1 and v2 failed: +- processed 3 tasks ++ processed 3 tasks += +- task 1 'publish'. lines 8-15: +- Error: error[E01013]: unsupported language construct +- ┌─ TEMPFILE1:12:23 +- │ +- 12 │ Test1::apply(|x: u64, y: u64| x + y, 1, Test1::apply(|x: u64, y: u64| x * y, 2, 1)) +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE1:12:31 +- │ +- 12 │ Test1::apply(|x: u64, y: u64| x + y, 1, Test1::apply(|x: u64, y: u64| x * y, 2, 1)) +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE1:12:63 +- │ +- 12 │ Test1::apply(|x: u64, y: u64| x + y, 1, Test1::apply(|x: u64, y: u64| x * y, 2, 1)) +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE1:12:71 +- │ +- 12 │ Test1::apply(|x: u64, y: u64| x + y, 1, Test1::apply(|x: u64, y: u64| x * y, 2, 1)) +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- +- += task 2 'run'. lines 17-17: +- Error: Function execution failed with VMError: { +- major_status: LINKER_ERROR, +- sub_status: None, +- location: undefined, +- indices: redacted, +- offsets: redacted, +- } ++ return values: 3 += diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/nested_lambda_module_typed.move b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/nested_lambda_module_typed.move new file mode 100644 index 0000000000000..857dec4843233 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/nested_lambda_module_typed.move @@ -0,0 +1,17 @@ +//# publish +module 0x42::Test1 { + public inline fun apply(f: |u64, u64|u64, x: u64, y: u64): u64 { + f(x, y) + } +} + +//# publish +module 0x42::Test { + use 0x42::Test1; + + public fun test(): u64 { + Test1::apply(|x: u64, y: u64| x + y, 1, Test1::apply(|x: u64, y: u64| x * y, 2, 1)) + } +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/nested_lambda_typed.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/nested_lambda_typed.exp new file mode 100644 index 0000000000000..fec36834b3846 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/nested_lambda_typed.exp @@ -0,0 +1,41 @@ +comparison between v1 and v2 failed: +- processed 2 tasks ++ processed 2 tasks += +- task 0 'publish'. lines 1-11: +- Error: error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:16 +- │ +- 7 │ apply(|x: u64, y: u64| x + y, 1, apply(|x: u64, y: u64| x * y, 2, 1)) +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:24 +- │ +- 7 │ apply(|x: u64, y: u64| x + y, 1, apply(|x: u64, y: u64| x * y, 2, 1)) +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:49 +- │ +- 7 │ apply(|x: u64, y: u64| x + y, 1, apply(|x: u64, y: u64| x * y, 2, 1)) +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:57 +- │ +- 7 │ apply(|x: u64, y: u64| x + y, 1, apply(|x: u64, y: u64| x * y, 2, 1)) +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- +- += task 1 'run'. lines 13-13: +- Error: Function execution failed with VMError: { +- major_status: LINKER_ERROR, +- sub_status: None, +- location: undefined, +- indices: redacted, +- offsets: redacted, +- } ++ return values: 3 += diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/nested_lambda_typed.move b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/nested_lambda_typed.move new file mode 100644 index 0000000000000..e31696ac9e662 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/nested_lambda_typed.move @@ -0,0 +1,13 @@ +//# publish +module 0x42::Test { + + public inline fun apply(f: |u64, u64|u64, x: u64, y: u64): u64 { + f(x, y) + } + + public fun test(): u64 { + apply(|x: u64, y: u64| x + y, 1, apply(|x: u64, y: u64| x * y, 2, 1)) + } +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/options_typed.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/options_typed.exp new file mode 100644 index 0000000000000..73a1637536f2e --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/options_typed.exp @@ -0,0 +1,23 @@ +comparison between v1 and v2 failed: +- processed 3 tasks ++ processed 3 tasks += +- task 1 'publish'. lines 15-25: +- Error: error[E01013]: unsupported language construct +- ┌─ TEMPFILE1:21:34 +- │ +- 21 │ let x = map_opt::map(t, |e: u64| e + 1); +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- +- += task 2 'run'. lines 27-27: +- Error: Function execution failed with VMError: { +- major_status: LINKER_ERROR, +- sub_status: None, +- location: undefined, +- indices: redacted, +- offsets: redacted, +- } ++ return values: 2 += diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/options_typed.move b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/options_typed.move new file mode 100644 index 0000000000000..943b85da6dff2 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/options_typed.move @@ -0,0 +1,27 @@ +//# publish +module 0x42::map_opt { + use std::option; + /// Maps the content of an option + public inline fun map(t: option::Option, f: |Element|OtherElement): option::Option { + if (option::is_some(&t)) { + option::some(f(option::extract(&mut t))) + } else { + option::none() + } + } + +} + +//# publish +module 0x42::Test { + use std::option; + use 0x42::map_opt; + + public fun test(): u64 { + let t = option::some(1); + let x = map_opt::map(t, |e: u64| e + 1); + option::extract(&mut x) + } +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/shadowing_renamed_param_typed.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/shadowing_renamed_param_typed.exp new file mode 100644 index 0000000000000..d14795838f0db --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/shadowing_renamed_param_typed.exp @@ -0,0 +1,43 @@ +comparison between v1 and v2 failed: += processed 2 tasks += += task 0 'publish'. lines 1-46: +- Error: error[E01013]: unsupported language construct +- ┌─ TEMPFILE:11:14 ++ warning: Unused assignment to `x`. Consider removing or prefixing with an underscore: `_x` ++ ┌─ TEMPFILE:23:17 += │ +- 11 │ foo(|y: u64| { +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond ++ 23 │ let x = q; ++ │ ^ += +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:16:15 +- │ +- 16 │ foo2(|y: u64| { +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond += +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:24:14 +- │ +- 24 │ foo(|y: u64| { +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond += +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:29:15 +- │ +- 29 │ foo2(|y: u64| { +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- +- +- task 1 'run'. lines 48-48: +- Error: Function execution failed with VMError: { +- major_status: LINKER_ERROR, +- sub_status: None, +- location: undefined, +- indices: redacted, +- offsets: redacted, +- } +- diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/shadowing_renamed_param_typed.move b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/shadowing_renamed_param_typed.move new file mode 100644 index 0000000000000..1ef82d15fcb89 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/shadowing_renamed_param_typed.move @@ -0,0 +1,48 @@ +//# publish +module 0x42::Test { + + public inline fun foo(f:|u64|, x:u64) { + f(x); + } + + public inline fun foo2(f:|u64|, x:u64) { + let x = x; + f(x); + } + + public fun test_shadowing(x: u64) { + foo(|y: u64| { + x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would + // have the value 1. + }, 3); + assert!(x == 3, 0); + + foo2(|y: u64| { + x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would + // have the value 1. + }, 5); + assert!(x == 5, 0) + } + + public fun test_shadowing2(q: u64) { + let x = q; + foo(|y: u64| { + x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would + // have the value 1. + }, 3); + assert!(x == 3, 0); + + foo2(|y: u64| { + x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would + // have the value 1. + }, 5); + assert!(x == 5, 0) + } + + fun test_shadowing_entry() { + test_shadowing(1); + test_shadowing2(1) + } +} + +//# run 0x42::Test::test_shadowing_entry diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/shadowing_renamed_typed.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/shadowing_renamed_typed.exp new file mode 100644 index 0000000000000..8eeb84f42bddb --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/shadowing_renamed_typed.exp @@ -0,0 +1,25 @@ +comparison between v1 and v2 failed: += processed 2 tasks += += task 0 'publish'. lines 1-19: +- Error: error[E01013]: unsupported language construct +- ┌─ TEMPFILE:9:14 ++ warning: Unused assignment to `x`. Consider removing or prefixing with an underscore: `_x` ++ ┌─ TEMPFILE:8:17 += │ +- 9 │ foo(|y: u64| { +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond ++ 8 │ let x = 1; ++ │ ^ += += += +- task 1 'run'. lines 21-21: +- Error: Function execution failed with VMError: { +- major_status: LINKER_ERROR, +- sub_status: None, +- location: undefined, +- indices: redacted, +- offsets: redacted, +- } +- diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/shadowing_renamed_typed.move b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/shadowing_renamed_typed.move new file mode 100644 index 0000000000000..37a421b27f40f --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/shadowing_renamed_typed.move @@ -0,0 +1,21 @@ +//# publish +module 0x42::Test { + + public inline fun foo(f:|u64|) { + let x = 3; + f(x); + } + + public fun test_shadowing() { + let x = 1; + foo(|y: u64| { + x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would + // have the value 1. + }); + assert!(x == 3, 0) + } + + +} + +//# run 0x42::Test::test_shadowing diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/shadowing_typed.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/shadowing_typed.exp new file mode 100644 index 0000000000000..880f900af4c5d --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/shadowing_typed.exp @@ -0,0 +1,23 @@ +comparison between v1 and v2 failed: +- processed 2 tasks +- +- task 0 'publish'. lines 1-19: +- Error: error[E01013]: unsupported language construct +- ┌─ TEMPFILE:9:14 +- │ +- 9 │ foo(|y: u64| { +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- +- +- task 1 'run'. lines 21-21: +- Error: Function execution failed with VMError: { +- major_status: LINKER_ERROR, +- sub_status: None, +- location: undefined, +- indices: redacted, +- offsets: redacted, +- } +- ++ processed 2 tasks ++ diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/shadowing_typed.move b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/shadowing_typed.move new file mode 100644 index 0000000000000..4490f8ee8b68b --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/shadowing_typed.move @@ -0,0 +1,21 @@ +//# publish +module 0x42::Test { + + public inline fun foo(f:|u64|) { + let _x = 3; + f(_x); + } + + public fun test_shadowing() { + let _x = 1; + foo(|y: u64| { + _x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would + // have the value 1. + }); + assert!(_x == 3, 0) + } + + +} + +//# run 0x42::Test::test_shadowing diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/misc/simple_map_keys_typed.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/misc/simple_map_keys_typed.exp new file mode 100644 index 0000000000000..4cd3899eb2420 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/misc/simple_map_keys_typed.exp @@ -0,0 +1,37 @@ +comparison between v1 and v2 failed: +- processed 2 tasks +- +- task 0 'publish'. lines 1-47: +- Error: error[E01013]: unsupported language construct +- ┌─ TEMPFILE:13:29 +- │ +- 13 │ map_ref(&map.data, |e: &Element| { +- │ ^^^^^^^^^^^^^^^^^^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E04010]: cannot infer type +- ┌─ TEMPFILE:14:13 +- │ +- 13 │ map_ref(&map.data, |e: &Element| { +- │ - Could not infer the type before field access. Try annotating here +- 14 │ e.key +- │ ^^^^^ Unbound field 'key' +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:22:26 +- │ +- 22 │ for_each_ref(v, |elem: &Element| vector::push_back(&mut result, f(elem))); +- │ ^^^^^^^^^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- +- +- task 1 'run'. lines 49-49: +- Error: Function execution failed with VMError: { +- major_status: LINKER_ERROR, +- sub_status: None, +- location: undefined, +- indices: redacted, +- offsets: redacted, +- } +- ++ processed 2 tasks ++ diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/misc/simple_map_keys_typed.move b/third_party/move/move-compiler-v2/transactional-tests/tests/misc/simple_map_keys_typed.move new file mode 100644 index 0000000000000..9c6d4449d6e93 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/misc/simple_map_keys_typed.move @@ -0,0 +1,49 @@ +//# publish +module 0x42::simple_map { + use 0x1::vector; + + struct SimpleMap has copy, drop, store { + data: vector>, + } + + struct Element has copy, drop, store { + key: Key, + value: Value, + } + + + /// Return all keys in the map. This requires keys to be copyable. + public fun keys(map: &SimpleMap): vector { + map_ref(&map.data, |e: &Element| { + e.key + }) + } + + public inline fun map_ref( + v: &vector, + f: |&Element|NewElement + ): vector { + let result = vector[]; + for_each_ref(v, |elem: &Element| vector::push_back(&mut result, f(elem))); + result + } + + public inline fun for_each_ref(v: &vector, f: |&Element|) { + let i = 0; + let len = vector::length(v); + while (i < len) { + f(vector::borrow(v, i)); + i = i + 1 + } + } + + public fun run() { + let entry = Element{key: 1, value: 2}; + let data = vector[entry, entry, entry]; + let map = SimpleMap{data}; + let keys = keys(&map); + assert!(keys == vector[1, 1, 1], 33); + } +} + +//# run 0x42::simple_map::run diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/operator_eval/op_with_side_effect_49_typed.move b/third_party/move/move-compiler-v2/transactional-tests/tests/operator_eval/op_with_side_effect_49_typed.move new file mode 100644 index 0000000000000..d3893ad8b24fc --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/operator_eval/op_with_side_effect_49_typed.move @@ -0,0 +1,13 @@ +//# publish +module 0xc0ffee::m { + inline fun call(f: |u64|u64): u64 { + f(2) + } + + public fun test(): u64 { + let x = 1; + x + call(|_x: u64| {x = x + 1; x}) + call(|_x: u64| {x = x + 7; x}) + } +} + +//# run 0xc0ffee::m::test diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/operator_eval/op_with_side_effect_49_typed.operator-eval-lang-1.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/operator_eval/op_with_side_effect_49_typed.operator-eval-lang-1.exp new file mode 100644 index 0000000000000..4c99c8a28e797 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/operator_eval/op_with_side_effect_49_typed.operator-eval-lang-1.exp @@ -0,0 +1,52 @@ +comparison between v1 and v2 failed: += processed 2 tasks += += task 0 'publish'. lines 1-11: +- Error: error[E01013]: unsupported language construct +- ┌─ TEMPFILE:8:19 ++ Error: compilation errors: ++ error: A sequence within an operand of binary operation `+` can obscure program logic and is not allowed by this compiler. ++ ┌─ TEMPFILE:8:9 += │ += 8 │ x + call(|_x: u64| {x = x + 1; x}) + call(|_x: u64| {x = x + 7; x}) +- │ ^^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond ++ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ │ │ │ ++ │ │ non-empty sequence ++ │ binary operation `+` ++ │ ++ = To compile this code, either: ++ = 1. upgrade to language version 2.0 or later (which uses strict left-to-right evaluation order), ++ = 2. rewrite the code to remove sequences from directly within binary operations, ++ = e.g., save intermediate results providing explicit order. ++ = In either of these cases, please ensure to check the code does what you expect it to, because of changed semantics. += +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:8:52 ++ error: A sequence within an operand of binary operation `+` can obscure program logic and is not allowed by this compiler. ++ ┌─ TEMPFILE:8:9 += │ += 8 │ x + call(|_x: u64| {x = x + 1; x}) + call(|_x: u64| {x = x + 7; x}) +- │ ^^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond ++ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ │ │ │ ++ │ │ non-empty sequence ++ │ binary operation `+` ++ │ ++ = To compile this code, either: ++ = 1. upgrade to language version 2.0 or later (which uses strict left-to-right evaluation order), ++ = 2. rewrite the code to remove sequences from directly within binary operations, ++ = e.g., save intermediate results providing explicit order. ++ = In either of these cases, please ensure to check the code does what you expect it to, because of changed semantics. += += += += task 1 'run'. lines 13-13: += Error: Function execution failed with VMError: { += major_status: LINKER_ERROR, += sub_status: None, += location: undefined, += indices: redacted, += offsets: redacted, += } += diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/operator_eval/op_with_side_effect_49_typed.operator-eval-lang-2.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/operator_eval/op_with_side_effect_49_typed.operator-eval-lang-2.exp new file mode 100644 index 0000000000000..42fb9148cc13a --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/operator_eval/op_with_side_effect_49_typed.operator-eval-lang-2.exp @@ -0,0 +1,29 @@ +comparison between v1 and v2 failed: +- processed 2 tasks ++ processed 2 tasks += +- task 0 'publish'. lines 1-11: +- Error: error[E01013]: unsupported language construct +- ┌─ TEMPFILE:8:19 +- │ +- 8 │ x + call(|_x: u64| {x = x + 1; x}) + call(|_x: u64| {x = x + 7; x}) +- │ ^^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- error[E01013]: unsupported language construct +- ┌─ TEMPFILE:8:52 +- │ +- 8 │ x + call(|_x: u64| {x = x + 1; x}) + call(|_x: u64| {x = x + 7; x}) +- │ ^^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- +- += task 1 'run'. lines 13-13: +- Error: Function execution failed with VMError: { +- major_status: LINKER_ERROR, +- sub_status: None, +- location: undefined, +- indices: redacted, +- offsets: redacted, +- } ++ return values: 12 += diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/optimization/inlining1_typed.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/optimization/inlining1_typed.exp new file mode 100644 index 0000000000000..c9058684fa8ba --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/optimization/inlining1_typed.exp @@ -0,0 +1,23 @@ +comparison between v1 and v2 failed: +- processed 2 tasks +- +- task 0 'publish'. lines 1-14: +- Error: error[E01013]: unsupported language construct +- ┌─ TEMPFILE:7:14 +- │ +- 7 │ foo(|_: u64| 3, 10) +- │ ^^^^^^ Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond +- +- +- +- task 1 'run'. lines 16-16: +- Error: Function execution failed with VMError: { +- major_status: LINKER_ERROR, +- sub_status: None, +- location: undefined, +- indices: redacted, +- offsets: redacted, +- } +- ++ processed 2 tasks ++ diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/optimization/inlining1_typed.move b/third_party/move/move-compiler-v2/transactional-tests/tests/optimization/inlining1_typed.move new file mode 100644 index 0000000000000..e22c531b09c4f --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/optimization/inlining1_typed.move @@ -0,0 +1,16 @@ +//# publish +module 0x42::Test { + inline fun foo(f:|u64| u64, x: u64): u64 { + f(x) + } + + public fun test(): u64 { + foo(|_: u64| 3, 10) + } + + public fun main() { + assert!(test() == 3, 5); + } +} + +//# run 0x42::Test::main diff --git a/third_party/move/move-compiler/src/expansion/ast.rs b/third_party/move/move-compiler/src/expansion/ast.rs index 257306fbd608b..50cf0b63da498 100644 --- a/third_party/move/move-compiler/src/expansion/ast.rs +++ b/third_party/move/move-compiler/src/expansion/ast.rs @@ -426,6 +426,13 @@ pub type LValue = Spanned; pub type LValueList_ = Vec; pub type LValueList = Spanned; +/// These represent LValues with user-specified explicit types. +#[derive(Debug, Clone, PartialEq)] +pub struct TypedLValue_(pub LValue, pub Option); +pub type TypedLValue = Spanned; +pub type TypedLValueList_ = Vec; +pub type TypedLValueList = Spanned; + pub fn wild_card(loc: Loc) -> LValue { let wildcard = sp(loc, Symbol::from("_")); let lvalue_ = LValue_::Var(sp(loc, ModuleAccess_::Name(wildcard)), None); @@ -500,7 +507,7 @@ pub enum Exp_ { While(Box, Box), Loop(Box), Block(Sequence), - Lambda(LValueList, Box), + Lambda(TypedLValueList, Box), Quant( QuantKind, LValueWithRangeList, @@ -1800,6 +1807,23 @@ impl AstDebug for ExpDotted_ { } } +impl AstDebug for Vec { + fn ast_debug(&self, w: &mut AstWriter) { + w.comma(self, |w, b| b.ast_debug(w)); + } +} + +impl AstDebug for TypedLValue_ { + fn ast_debug(&self, w: &mut AstWriter) { + let TypedLValue_(lv, opt_ty) = self; + lv.ast_debug(w); + if let Some(ty) = opt_ty { + w.write(":"); + ty.ast_debug(w); + } + } +} + impl AstDebug for Vec { fn ast_debug(&self, w: &mut AstWriter) { let parens = self.len() != 1; diff --git a/third_party/move/move-compiler/src/expansion/dependency_ordering.rs b/third_party/move/move-compiler/src/expansion/dependency_ordering.rs index 92cb3ed239168..9912bd62634ff 100644 --- a/third_party/move/move-compiler/src/expansion/dependency_ordering.rs +++ b/third_party/move/move-compiler/src/expansion/dependency_ordering.rs @@ -513,7 +513,9 @@ fn exp(context: &mut Context, sp!(_loc, e_): &E::Exp) { }, E::Lambda(ll, e) => { - lvalues(context, &ll.value); + use crate::expansion::ast::TypedLValue_; + let mapped = ll.value.iter().map(|sp!(_, TypedLValue_(lv, _opt_ty))| lv); + lvalues(context, mapped); exp(context, e) }, E::Quant(_, binds, es_vec, eopt, e) => { diff --git a/third_party/move/move-compiler/src/expansion/translate.rs b/third_party/move/move-compiler/src/expansion/translate.rs index c7ea02c5e7f6a..4fec7ef662b1f 100644 --- a/third_party/move/move-compiler/src/expansion/translate.rs +++ b/third_party/move/move-compiler/src/expansion/translate.rs @@ -2615,10 +2615,10 @@ fn exp_(context: &mut Context, sp!(loc, pe_): P::Exp) -> E::Exp { PE::Loop(ploop) => EE::Loop(exp(context, *ploop)), PE::Block(seq) => EE::Block(sequence(context, loc, seq)), PE::Lambda(pbs, pe) => { - let bs_opt = bind_list(context, pbs); + let tbs_opt = typed_bind_list(context, pbs); let e = exp_(context, *pe); - match bs_opt { - Some(bs) => EE::Lambda(bs, Box::new(e)), + match tbs_opt { + Some(tbs) => EE::Lambda(tbs, Box::new(e)), None => { assert!(context.env.has_errors()); EE::UnresolvedError @@ -2886,6 +2886,24 @@ fn fields( // LValues //************************************************************************************************** +fn typed_bind_list( + context: &mut Context, + sp!(loc, pbs_): P::TypedBindList, +) -> Option { + let bs_: Option> = pbs_ + .into_iter() + .map(|tpb| typed_bind(context, tpb)) + .collect(); + Some(sp(loc, bs_?)) +} + +fn typed_bind(context: &mut Context, sp!(loc, tpb_): P::TypedBind) -> Option { + let P::TypedBind_(pb, opt_type) = tpb_; + let b = bind(context, pb)?; + let ot = opt_type.map(|ty| type_(context, ty)); + Some(sp(loc, E::TypedLValue_(b, ot))) +} + fn bind_list(context: &mut Context, sp!(loc, pbs_): P::BindList) -> Option { let bs_: Option> = pbs_.into_iter().map(|pb| bind(context, pb)).collect(); Some(sp(loc, bs_?)) @@ -3234,7 +3252,7 @@ fn unbound_names_exp(unbound: &mut UnboundNames, sp!(_, e_): &E::Exp) { EE::Lambda(ls, er) => { unbound_names_exp(unbound, er); // remove anything in `ls` - unbound_names_binds(unbound, ls); + unbound_names_typed_binds(unbound, ls); }, EE::Quant(_, rs, trs, cr_opt, er) => { unbound_names_exp(unbound, er); @@ -3311,6 +3329,12 @@ fn unbound_names_binds(unbound: &mut UnboundNames, sp!(_, ls_): &E::LValueList) .for_each(|l| unbound_names_bind(unbound, l)) } +fn unbound_names_typed_binds(unbound: &mut UnboundNames, sp!(_, ls_): &E::TypedLValueList) { + ls_.iter() + .rev() + .for_each(|sp!(_loc, E::TypedLValue_(l, _opt_ty))| unbound_names_bind(unbound, l)) +} + fn unbound_names_binds_with_range( unbound: &mut UnboundNames, sp!(_, rs_): &E::LValueWithRangeList, diff --git a/third_party/move/move-compiler/src/naming/translate.rs b/third_party/move/move-compiler/src/naming/translate.rs index 9080f025707f5..640e235b3605d 100644 --- a/third_party/move/move-compiler/src/naming/translate.rs +++ b/third_party/move/move-compiler/src/naming/translate.rs @@ -942,7 +942,7 @@ fn exp_(context: &mut Context, e: E::Exp) -> N::Exp { EE::Loop(el) => NE::Loop(exp(context, *el)), EE::Block(seq) => NE::Block(sequence(context, seq)), EE::Lambda(args, body) => { - let bind_opt = bind_list(context, args); + let bind_opt = bind_typed_list(context, args); match bind_opt { None => { assert!(context.env.has_errors()); @@ -1201,6 +1201,10 @@ fn bind_list(context: &mut Context, ls: E::LValueList) -> Option lvalue_list(context, LValueCase::Bind, ls) } +fn bind_typed_list(context: &mut Context, ls: E::TypedLValueList) -> Option { + typed_lvalue_list(context, ls) +} + fn assign_list(context: &mut Context, ls: E::LValueList) -> Option { lvalue_list(context, LValueCase::Assign, ls) } @@ -1218,6 +1222,30 @@ fn lvalue_list( )) } +fn typed_lvalue_list( + context: &mut Context, + sp!(loc, b_): E::TypedLValueList, +) -> Option { + let case = LValueCase::Bind; + Some(sp( + loc, + b_.into_iter() + .map(|sp!(loc, E::TypedLValue_(inner, opt_ty))| { + if opt_ty.is_some() { + context.env.add_diag(diag!( + Syntax::UnsupportedLanguageItem, + ( + loc, + "Explicit type annotations for lambda parameters are only allowed in Move 2 and beyond" + ) + )) + } + lvalue(context, case, inner) + }) + .collect::>()?, + )) +} + fn resolve_builtin_function( context: &mut Context, loc: Loc, diff --git a/third_party/move/move-compiler/src/parser/ast.rs b/third_party/move/move-compiler/src/parser/ast.rs index 1bc388c914eb5..bd22eca723c27 100644 --- a/third_party/move/move-compiler/src/parser/ast.rs +++ b/third_party/move/move-compiler/src/parser/ast.rs @@ -523,6 +523,13 @@ pub type Bind = Spanned; // b1, ..., bn pub type BindList = Spanned>; +#[derive(Debug, Clone, PartialEq)] +pub struct TypedBind_(pub Bind, pub Option); +pub type TypedBind = Spanned; + +// b1 [":" ], ..., bn [":" ] +pub type TypedBindList = Spanned>; + #[derive(Debug, Clone, PartialEq)] pub enum BindFieldOrDotDot_ { // f : b @@ -680,8 +687,8 @@ pub enum Exp_ { // { seq } Block(Sequence), - // |x1, ..., xn| e - Lambda(BindList, Box), // spec only + // | x1 [: t1], ..., xn [: tn] | e + Lambda(TypedBindList, Box), // forall/exists x1 : e1, ..., xn [{ t1, .., tk } *] [where cond]: en. Quant( QuantKind, @@ -1780,6 +1787,7 @@ impl AstDebug for SequenceItem_ { w.write("let "); bs.ast_debug(w); if let Some(ty) = ty_opt { + w.write(":"); ty.ast_debug(w) } }, @@ -1787,6 +1795,7 @@ impl AstDebug for SequenceItem_ { w.write("let "); bs.ast_debug(w); if let Some(ty) = ty_opt { + w.write(":"); ty.ast_debug(w) } w.write(" = "); @@ -1884,9 +1893,9 @@ impl AstDebug for Exp_ { e.ast_debug(w); }, E::Block(seq) => w.block(|w| seq.ast_debug(w)), - E::Lambda(sp!(_, bs), e) => { + E::Lambda(sp!(_, tbs), e) => { w.write("|"); - bs.ast_debug(w); + tbs.ast_debug(w); w.write("|"); e.ast_debug(w); }, @@ -2127,3 +2136,20 @@ impl AstDebug for Bind_ { } } } + +impl AstDebug for Vec { + fn ast_debug(&self, w: &mut AstWriter) { + w.comma(self, |w, b| b.ast_debug(w)); + } +} + +impl AstDebug for TypedBind_ { + fn ast_debug(&self, w: &mut AstWriter) { + let TypedBind_(b, ty_opt) = self; + b.ast_debug(w); + if let Some(ty) = ty_opt { + w.write(":"); + ty.ast_debug(w) + } + } +} diff --git a/third_party/move/move-compiler/src/parser/syntax.rs b/third_party/move/move-compiler/src/parser/syntax.rs index e969ac5268a74..1c4aee7141204 100644 --- a/third_party/move/move-compiler/src/parser/syntax.rs +++ b/third_party/move/move-compiler/src/parser/syntax.rs @@ -781,6 +781,26 @@ fn parse_bind_field(context: &mut Context) -> Result<(Field, Bind), Box )? +fn parse_typed_bind(context: &mut Context) -> Result> { + let start_loc = context.tokens.start_loc(); + let bind = parse_bind(context)?; + let ty_opt = if match_token(context.tokens, Tok::Colon)? { + Some(parse_type(context)?) + } else { + None + }; + let end_loc = context.tokens.previous_end_loc(); + let typed_bind_ = TypedBind_(bind, ty_opt); + Ok(spanned( + context.tokens.file_hash(), + start_loc, + end_loc, + typed_bind_, + )) +} + // Parse a binding: // Bind = // @@ -895,14 +915,14 @@ fn parse_bind_or_dotdot(context: &mut Context) -> Result "|" -fn parse_lambda_bind_list(context: &mut Context) -> Result> { +// "|" Comma "|" +fn parse_lambda_bind_list(context: &mut Context) -> Result> { let start_loc = context.tokens.start_loc(); let b = parse_comma_list( context, Tok::Pipe, Tok::Pipe, - parse_bind, + parse_typed_bind, "a variable or structure binding", )?; let end_loc = context.tokens.previous_end_loc(); diff --git a/third_party/move/move-model/src/builder/exp_builder.rs b/third_party/move/move-model/src/builder/exp_builder.rs index adf8c6c828fbd..21e7e4369562c 100644 --- a/third_party/move/move-model/src/builder/exp_builder.rs +++ b/third_party/move/move-model/src/builder/exp_builder.rs @@ -2262,6 +2262,61 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo ExpData::Match(id, discr_exp.into_exp(), translate_arms) } + fn translate_typed_lvalue_list( + &mut self, + list: &EA::TypedLValueList, + expected_type: &Type, + expected_order: WideningOrder, + match_locals: bool, + context: &ErrorMessageContext, + ) -> Pattern { + // Shortcut for single element case + if list.value.len() == 1 { + return self.translate_typed_lvalue( + list.value.first().unwrap(), + expected_type, + expected_order, + match_locals, + context, + ); + } + let loc = self.to_loc(&list.loc); + // Ensure to maximize precision of expected type for elements + let expected_type = self.subs.specialize(expected_type); + let elem_expected_types = if let Type::Tuple(tys) = expected_type { + tys + } else { + let vars = self.fresh_type_vars(list.value.len()); + // Just bind the variables + self.check_type_with_order( + expected_order, + &loc, + &Type::Tuple(vars.clone()), + &expected_type, + context, + ); + vars + }; + if elem_expected_types.len() != list.value.len() { + self.error( + &loc, + &context.arity_mismatch(false, elem_expected_types.len(), list.value.len()), + ); + return self.new_error_pat(&loc); + } + let mut args = vec![]; + let mut elem_types = vec![]; + for (lv, expected) in list.value.iter().zip(elem_expected_types.iter()) { + let value = + self.translate_typed_lvalue(lv, expected, expected_order, match_locals, context); + elem_types.push(self.get_node_type(value.node_id())); + args.push(value) + } + let ty = Type::Tuple(elem_types); + let id = self.new_node_id_with_type_loc(&ty, &loc); + Pattern::Tuple(id, args) + } + fn translate_lvalue_list( &mut self, list: &EA::LValueList, @@ -2332,6 +2387,33 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo } } + fn translate_typed_lvalue( + &mut self, + tlv: &EA::TypedLValue, + expected_type: &Type, + expected_order: WideningOrder, + match_locals: bool, + context: &ErrorMessageContext, + ) -> Pattern { + use move_ir_types::sp; + let sp!(loc, EA::TypedLValue_(lv, opt_ty)) = tlv; + match opt_ty { + Some(ty) => { + let loc = self.to_loc(loc); + let bound_type = self.translate_type(ty); + self.check_type_with_order( + expected_order, + &loc, + &bound_type, // is this arg ordering right? + expected_type, + context, + ); + self.translate_lvalue(lv, &bound_type, expected_order, match_locals, context) + }, + None => self.translate_lvalue(lv, expected_type, expected_order, match_locals, context), + } + } + fn translate_lvalue( &mut self, lv: &EA::LValue, @@ -4946,14 +5028,14 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo fn translate_lambda( &mut self, loc: &Loc, - args: &EA::LValueList, + args: &EA::TypedLValueList, body: &EA::Exp, expected_type: &Type, context: &ErrorMessageContext, ) -> ExpData { // Translate the argument list let arg_type = self.fresh_type_var(); - let pat = self.translate_lvalue_list( + let pat = self.translate_typed_lvalue_list( args, &arg_type, WideningOrder::LeftToRight,