diff --git a/third_party/move/move-compiler-v2/tests/lambda-lifting/basic.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda-lifting/basic.lambda.exp new file mode 100644 index 00000000000000..aecce2d0e90593 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda-lifting/basic.lambda.exp @@ -0,0 +1,336 @@ +// -- Model dump before env processor pipeline: +module 0xcafe::m { + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun no_name_clash(x: u64,c: u64): u64 { + m::map(x, |y: u64| Add(y, c)) + } + private fun with_name_clash1(x: u64,c: u64): u64 { + m::map(x, |x: u64| Add(x, c)) + } + private fun with_name_clash2(x: u64,c: u64): u64 { + m::map(x, |x: u64| Add({ + let x: u64 = Add(c, 1); + x + }, x)) + } +} // end 0xcafe::m + + +// -- Model dump after env processor unused checks: +module 0xcafe::m { + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun no_name_clash(x: u64,c: u64): u64 { + m::map(x, |y: u64| Add(y, c)) + } + private fun with_name_clash1(x: u64,c: u64): u64 { + m::map(x, |x: u64| Add(x, c)) + } + private fun with_name_clash2(x: u64,c: u64): u64 { + m::map(x, |x: u64| Add({ + let x: u64 = Add(c, 1); + x + }, x)) + } +} // end 0xcafe::m + + +// -- Model dump after env processor type parameter check: +module 0xcafe::m { + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun no_name_clash(x: u64,c: u64): u64 { + m::map(x, |y: u64| Add(y, c)) + } + private fun with_name_clash1(x: u64,c: u64): u64 { + m::map(x, |x: u64| Add(x, c)) + } + private fun with_name_clash2(x: u64,c: u64): u64 { + m::map(x, |x: u64| Add({ + let x: u64 = Add(c, 1); + x + }, x)) + } +} // end 0xcafe::m + + +// -- Model dump after env processor check recursive struct definition: +module 0xcafe::m { + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun no_name_clash(x: u64,c: u64): u64 { + m::map(x, |y: u64| Add(y, c)) + } + private fun with_name_clash1(x: u64,c: u64): u64 { + m::map(x, |x: u64| Add(x, c)) + } + private fun with_name_clash2(x: u64,c: u64): u64 { + m::map(x, |x: u64| Add({ + let x: u64 = Add(c, 1); + x + }, x)) + } +} // end 0xcafe::m + + +// -- Model dump after env processor check cyclic type instantiation: +module 0xcafe::m { + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun no_name_clash(x: u64,c: u64): u64 { + m::map(x, |y: u64| Add(y, c)) + } + private fun with_name_clash1(x: u64,c: u64): u64 { + m::map(x, |x: u64| Add(x, c)) + } + private fun with_name_clash2(x: u64,c: u64): u64 { + m::map(x, |x: u64| Add({ + let x: u64 = Add(c, 1); + x + }, x)) + } +} // end 0xcafe::m + + +// -- Model dump after env processor unused struct params check: +module 0xcafe::m { + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun no_name_clash(x: u64,c: u64): u64 { + m::map(x, |y: u64| Add(y, c)) + } + private fun with_name_clash1(x: u64,c: u64): u64 { + m::map(x, |x: u64| Add(x, c)) + } + private fun with_name_clash2(x: u64,c: u64): u64 { + m::map(x, |x: u64| Add({ + let x: u64 = Add(c, 1); + x + }, x)) + } +} // end 0xcafe::m + + +// -- Model dump after env processor access and use check before inlining: +module 0xcafe::m { + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun no_name_clash(x: u64,c: u64): u64 { + m::map(x, |y: u64| Add(y, c)) + } + private fun with_name_clash1(x: u64,c: u64): u64 { + m::map(x, |x: u64| Add(x, c)) + } + private fun with_name_clash2(x: u64,c: u64): u64 { + m::map(x, |x: u64| Add({ + let x: u64 = Add(c, 1); + x + }, x)) + } +} // end 0xcafe::m + + +// -- Model dump after env processor inlining: +module 0xcafe::m { + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun no_name_clash(x: u64,c: u64): u64 { + m::map(x, |y: u64| Add(y, c)) + } + private fun with_name_clash1(x: u64,c: u64): u64 { + m::map(x, |x: u64| Add(x, c)) + } + private fun with_name_clash2(x: u64,c: u64): u64 { + m::map(x, |x: u64| Add({ + let x: u64 = Add(c, 1); + x + }, x)) + } +} // end 0xcafe::m + + +// -- Model dump after env processor access and use check after inlining: +module 0xcafe::m { + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun no_name_clash(x: u64,c: u64): u64 { + m::map(x, |y: u64| Add(y, c)) + } + private fun with_name_clash1(x: u64,c: u64): u64 { + m::map(x, |x: u64| Add(x, c)) + } + private fun with_name_clash2(x: u64,c: u64): u64 { + m::map(x, |x: u64| Add({ + let x: u64 = Add(c, 1); + x + }, x)) + } +} // end 0xcafe::m + + +// -- Model dump after env processor acquires check: +module 0xcafe::m { + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun no_name_clash(x: u64,c: u64): u64 { + m::map(x, |y: u64| Add(y, c)) + } + private fun with_name_clash1(x: u64,c: u64): u64 { + m::map(x, |x: u64| Add(x, c)) + } + private fun with_name_clash2(x: u64,c: u64): u64 { + m::map(x, |x: u64| Add({ + let x: u64 = Add(c, 1); + x + }, x)) + } +} // end 0xcafe::m + + +// -- Model dump after env processor simplifier: +module 0xcafe::m { + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun no_name_clash(x: u64,c: u64): u64 { + m::map(x, |y: u64| Add(y, c)) + } + private fun with_name_clash1(x: u64,c: u64): u64 { + m::map(x, |x: u64| Add(x, c)) + } + private fun with_name_clash2(x: u64,c: u64): u64 { + m::map(x, |x: u64| Add({ + let x: u64 = Add(c, 1); + x + }, x)) + } +} // end 0xcafe::m + + +// -- Model dump after env processor lambda-lifting: +module 0xcafe::m { + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun no_name_clash(x: u64,c: u64): u64 { + m::map(x, closure m::no_name_clash$lambda$1(c)) + } + private fun with_name_clash1(x: u64,c: u64): u64 { + m::map(x, closure m::with_name_clash1$lambda$1(c)) + } + private fun with_name_clash2(x: u64,c: u64): u64 { + m::map(x, closure m::with_name_clash2$lambda$1(c)) + } + private fun no_name_clash$lambda$1(c: u64,y: u64): u64 { + Add(y, c) + } + private fun with_name_clash1$lambda$1(c: u64,x: u64): u64 { + Add(x, c) + } + private fun with_name_clash2$lambda$1(c: u64,x: u64): u64 { + Add({ + let x: u64 = Add(c, 1); + x + }, x) + } +} // end 0xcafe::m + + +// -- Model dump after env processor specification checker: +module 0xcafe::m { + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun no_name_clash(x: u64,c: u64): u64 { + m::map(x, closure m::no_name_clash$lambda$1(c)) + } + private fun with_name_clash1(x: u64,c: u64): u64 { + m::map(x, closure m::with_name_clash1$lambda$1(c)) + } + private fun with_name_clash2(x: u64,c: u64): u64 { + m::map(x, closure m::with_name_clash2$lambda$1(c)) + } + private fun no_name_clash$lambda$1(c: u64,y: u64): u64 { + Add(y, c) + } + private fun with_name_clash1$lambda$1(c: u64,x: u64): u64 { + Add(x, c) + } + private fun with_name_clash2$lambda$1(c: u64,x: u64): u64 { + Add({ + let x: u64 = Add(c, 1); + x + }, x) + } +} // end 0xcafe::m + + +// -- Model dump after env processor specification rewriter: +module 0xcafe::m { + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun no_name_clash(x: u64,c: u64): u64 { + m::map(x, closure m::no_name_clash$lambda$1(c)) + } + private fun with_name_clash1(x: u64,c: u64): u64 { + m::map(x, closure m::with_name_clash1$lambda$1(c)) + } + private fun with_name_clash2(x: u64,c: u64): u64 { + m::map(x, closure m::with_name_clash2$lambda$1(c)) + } + private fun no_name_clash$lambda$1(c: u64,y: u64): u64 { + Add(y, c) + } + private fun with_name_clash1$lambda$1(c: u64,x: u64): u64 { + Add(x, c) + } + private fun with_name_clash2$lambda$1(c: u64,x: u64): u64 { + Add({ + let x: u64 = Add(c, 1); + x + }, x) + } +} // end 0xcafe::m + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda-lifting/basic.move:5:9 + │ +5 │ f(x) + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda-lifting/basic.move:10:16 + │ +10 │ map(x, |y| y + c) + │ ^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda-lifting/basic.move:15:16 + │ +15 │ map(x, |x| x + c) + │ ^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda-lifting/basic.move:20:16 + │ +20 │ map(x, |x| { + │ ╭────────────────^ +21 │ │ let x = c + 1; +22 │ │ x +23 │ │ } + x) + │ ╰─────────────^ diff --git a/third_party/move/move-compiler-v2/tests/lambda-lifting/modify.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda-lifting/modify.lambda.exp new file mode 100644 index 00000000000000..3664bd2e163bbe --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda-lifting/modify.lambda.exp @@ -0,0 +1,528 @@ +// -- Model dump before env processor pipeline: +module 0xcafe::m { + struct S { + x: u64, + } + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun assigns_local(x: u64,c: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| z: u64 = 2; + Add(y, c)) + } + } + private fun assigns_param(x: u64,c: u64): u64 { + m::map(x, |y: u64| x: u64 = 2; + Add(y, c)) + } + private fun borrows_local(x: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| { + let r: &mut u64 = Borrow(Mutable)(z); + Add(y, Deref(r)) + }) + } + } + private fun borrows_param(x: u64,c: u64): u64 { + m::map(x, |y: u64| { + let r: &mut u64 = Borrow(Mutable)(c); + Add(y, Deref(r)) + }) + } + private fun immutable_borrow_ok(x: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| { + let r: &u64 = Borrow(Immutable)(z); + Add(y, Deref(r)) + }) + } + } +} // end 0xcafe::m + + +// -- Model dump after env processor unused checks: +module 0xcafe::m { + struct S { + x: u64, + } + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun assigns_local(x: u64,c: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| z: u64 = 2; + Add(y, c)) + } + } + private fun assigns_param(x: u64,c: u64): u64 { + m::map(x, |y: u64| x: u64 = 2; + Add(y, c)) + } + private fun borrows_local(x: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| { + let r: &mut u64 = Borrow(Mutable)(z); + Add(y, Deref(r)) + }) + } + } + private fun borrows_param(x: u64,c: u64): u64 { + m::map(x, |y: u64| { + let r: &mut u64 = Borrow(Mutable)(c); + Add(y, Deref(r)) + }) + } + private fun immutable_borrow_ok(x: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| { + let r: &u64 = Borrow(Immutable)(z); + Add(y, Deref(r)) + }) + } + } +} // end 0xcafe::m + + +// -- Model dump after env processor type parameter check: +module 0xcafe::m { + struct S { + x: u64, + } + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun assigns_local(x: u64,c: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| z: u64 = 2; + Add(y, c)) + } + } + private fun assigns_param(x: u64,c: u64): u64 { + m::map(x, |y: u64| x: u64 = 2; + Add(y, c)) + } + private fun borrows_local(x: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| { + let r: &mut u64 = Borrow(Mutable)(z); + Add(y, Deref(r)) + }) + } + } + private fun borrows_param(x: u64,c: u64): u64 { + m::map(x, |y: u64| { + let r: &mut u64 = Borrow(Mutable)(c); + Add(y, Deref(r)) + }) + } + private fun immutable_borrow_ok(x: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| { + let r: &u64 = Borrow(Immutable)(z); + Add(y, Deref(r)) + }) + } + } +} // end 0xcafe::m + + +// -- Model dump after env processor check recursive struct definition: +module 0xcafe::m { + struct S { + x: u64, + } + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun assigns_local(x: u64,c: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| z: u64 = 2; + Add(y, c)) + } + } + private fun assigns_param(x: u64,c: u64): u64 { + m::map(x, |y: u64| x: u64 = 2; + Add(y, c)) + } + private fun borrows_local(x: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| { + let r: &mut u64 = Borrow(Mutable)(z); + Add(y, Deref(r)) + }) + } + } + private fun borrows_param(x: u64,c: u64): u64 { + m::map(x, |y: u64| { + let r: &mut u64 = Borrow(Mutable)(c); + Add(y, Deref(r)) + }) + } + private fun immutable_borrow_ok(x: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| { + let r: &u64 = Borrow(Immutable)(z); + Add(y, Deref(r)) + }) + } + } +} // end 0xcafe::m + + +// -- Model dump after env processor check cyclic type instantiation: +module 0xcafe::m { + struct S { + x: u64, + } + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun assigns_local(x: u64,c: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| z: u64 = 2; + Add(y, c)) + } + } + private fun assigns_param(x: u64,c: u64): u64 { + m::map(x, |y: u64| x: u64 = 2; + Add(y, c)) + } + private fun borrows_local(x: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| { + let r: &mut u64 = Borrow(Mutable)(z); + Add(y, Deref(r)) + }) + } + } + private fun borrows_param(x: u64,c: u64): u64 { + m::map(x, |y: u64| { + let r: &mut u64 = Borrow(Mutable)(c); + Add(y, Deref(r)) + }) + } + private fun immutable_borrow_ok(x: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| { + let r: &u64 = Borrow(Immutable)(z); + Add(y, Deref(r)) + }) + } + } +} // end 0xcafe::m + + +// -- Model dump after env processor unused struct params check: +module 0xcafe::m { + struct S { + x: u64, + } + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun assigns_local(x: u64,c: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| z: u64 = 2; + Add(y, c)) + } + } + private fun assigns_param(x: u64,c: u64): u64 { + m::map(x, |y: u64| x: u64 = 2; + Add(y, c)) + } + private fun borrows_local(x: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| { + let r: &mut u64 = Borrow(Mutable)(z); + Add(y, Deref(r)) + }) + } + } + private fun borrows_param(x: u64,c: u64): u64 { + m::map(x, |y: u64| { + let r: &mut u64 = Borrow(Mutable)(c); + Add(y, Deref(r)) + }) + } + private fun immutable_borrow_ok(x: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| { + let r: &u64 = Borrow(Immutable)(z); + Add(y, Deref(r)) + }) + } + } +} // end 0xcafe::m + + +// -- Model dump after env processor access and use check before inlining: +module 0xcafe::m { + struct S { + x: u64, + } + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun assigns_local(x: u64,c: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| z: u64 = 2; + Add(y, c)) + } + } + private fun assigns_param(x: u64,c: u64): u64 { + m::map(x, |y: u64| x: u64 = 2; + Add(y, c)) + } + private fun borrows_local(x: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| { + let r: &mut u64 = Borrow(Mutable)(z); + Add(y, Deref(r)) + }) + } + } + private fun borrows_param(x: u64,c: u64): u64 { + m::map(x, |y: u64| { + let r: &mut u64 = Borrow(Mutable)(c); + Add(y, Deref(r)) + }) + } + private fun immutable_borrow_ok(x: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| { + let r: &u64 = Borrow(Immutable)(z); + Add(y, Deref(r)) + }) + } + } +} // end 0xcafe::m + + +// -- Model dump after env processor inlining: +module 0xcafe::m { + struct S { + x: u64, + } + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun assigns_local(x: u64,c: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| z: u64 = 2; + Add(y, c)) + } + } + private fun assigns_param(x: u64,c: u64): u64 { + m::map(x, |y: u64| x: u64 = 2; + Add(y, c)) + } + private fun borrows_local(x: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| { + let r: &mut u64 = Borrow(Mutable)(z); + Add(y, Deref(r)) + }) + } + } + private fun borrows_param(x: u64,c: u64): u64 { + m::map(x, |y: u64| { + let r: &mut u64 = Borrow(Mutable)(c); + Add(y, Deref(r)) + }) + } + private fun immutable_borrow_ok(x: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| { + let r: &u64 = Borrow(Immutable)(z); + Add(y, Deref(r)) + }) + } + } +} // end 0xcafe::m + + +// -- Model dump after env processor access and use check after inlining: +module 0xcafe::m { + struct S { + x: u64, + } + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun assigns_local(x: u64,c: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| z: u64 = 2; + Add(y, c)) + } + } + private fun assigns_param(x: u64,c: u64): u64 { + m::map(x, |y: u64| x: u64 = 2; + Add(y, c)) + } + private fun borrows_local(x: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| { + let r: &mut u64 = Borrow(Mutable)(z); + Add(y, Deref(r)) + }) + } + } + private fun borrows_param(x: u64,c: u64): u64 { + m::map(x, |y: u64| { + let r: &mut u64 = Borrow(Mutable)(c); + Add(y, Deref(r)) + }) + } + private fun immutable_borrow_ok(x: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| { + let r: &u64 = Borrow(Immutable)(z); + Add(y, Deref(r)) + }) + } + } +} // end 0xcafe::m + + +// -- Model dump after env processor acquires check: +module 0xcafe::m { + struct S { + x: u64, + } + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun assigns_local(x: u64,c: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| z: u64 = 2; + Add(y, c)) + } + } + private fun assigns_param(x: u64,c: u64): u64 { + m::map(x, |y: u64| x: u64 = 2; + Add(y, c)) + } + private fun borrows_local(x: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| { + let r: &mut u64 = Borrow(Mutable)(z); + Add(y, Deref(r)) + }) + } + } + private fun borrows_param(x: u64,c: u64): u64 { + m::map(x, |y: u64| { + let r: &mut u64 = Borrow(Mutable)(c); + Add(y, Deref(r)) + }) + } + private fun immutable_borrow_ok(x: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| { + let r: &u64 = Borrow(Immutable)(z); + Add(y, Deref(r)) + }) + } + } +} // end 0xcafe::m + + +// -- Model dump after env processor simplifier: +module 0xcafe::m { + struct S { + x: u64, + } + private fun map(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun assigns_local(x: u64,c: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| z: u64 = 2; + Add(y, c)) + } + } + private fun assigns_param(x: u64,c: u64): u64 { + m::map(x, |y: u64| x: u64 = 2; + Add(y, c)) + } + private fun borrows_local(x: u64): u64 { + { + let z: u64 = 1; + m::map(x, |y: u64| { + let r: &mut u64 = Borrow(Mutable)(z); + Add(y, Deref(r)) + }) + } + } + private fun borrows_param(x: u64,c: u64): u64 { + m::map(x, |y: u64| { + let r: &mut u64 = Borrow(Mutable)(c); + Add(y, Deref(r)) + }) + } + private fun immutable_borrow_ok(x: u64): u64 { + m::map(x, |y: u64| { + let r: &u64 = Borrow(Immutable)(1); + Add(y, Deref(r)) + }) + } +} // end 0xcafe::m + + + +Diagnostics: +error: captured variable `x` cannot be modified inside of a lambda + ┌─ tests/lambda-lifting/modify.move:14:13 + │ +14 │ x = 2; + │ ^ + +error: captured variable `c` cannot be modified inside of a lambda + ┌─ tests/lambda-lifting/modify.move:21:26 + │ +21 │ let r = &mut c; + │ ^ + +error: captured variable `z` cannot be modified inside of a lambda + ┌─ tests/lambda-lifting/modify.move:29:13 + │ +29 │ z = 2; + │ ^ + +error: captured variable `z` cannot be modified inside of a lambda + ┌─ tests/lambda-lifting/modify.move:37:26 + │ +37 │ let r = &mut z; + │ ^ diff --git a/third_party/move/move-compiler-v2/tests/lambda-lifting/nested.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda-lifting/nested.lambda.exp new file mode 100644 index 00000000000000..cb00e1c4256e81 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda-lifting/nested.lambda.exp @@ -0,0 +1,239 @@ +// -- Model dump before env processor pipeline: +module 0xcafe::m { + private fun map1(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun map2(x: u8,f: |u8|u8): u8 { + (f)(x) + } + private fun nested(x: u64,c: u64): u64 { + m::map1(x, |y: u64| Cast(m::map2(Cast(Sub(y, c)), |y: u8| Add(y, Cast(c))))) + } +} // end 0xcafe::m + + +// -- Model dump after env processor unused checks: +module 0xcafe::m { + private fun map1(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun map2(x: u8,f: |u8|u8): u8 { + (f)(x) + } + private fun nested(x: u64,c: u64): u64 { + m::map1(x, |y: u64| Cast(m::map2(Cast(Sub(y, c)), |y: u8| Add(y, Cast(c))))) + } +} // end 0xcafe::m + + +// -- Model dump after env processor type parameter check: +module 0xcafe::m { + private fun map1(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun map2(x: u8,f: |u8|u8): u8 { + (f)(x) + } + private fun nested(x: u64,c: u64): u64 { + m::map1(x, |y: u64| Cast(m::map2(Cast(Sub(y, c)), |y: u8| Add(y, Cast(c))))) + } +} // end 0xcafe::m + + +// -- Model dump after env processor check recursive struct definition: +module 0xcafe::m { + private fun map1(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun map2(x: u8,f: |u8|u8): u8 { + (f)(x) + } + private fun nested(x: u64,c: u64): u64 { + m::map1(x, |y: u64| Cast(m::map2(Cast(Sub(y, c)), |y: u8| Add(y, Cast(c))))) + } +} // end 0xcafe::m + + +// -- Model dump after env processor check cyclic type instantiation: +module 0xcafe::m { + private fun map1(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun map2(x: u8,f: |u8|u8): u8 { + (f)(x) + } + private fun nested(x: u64,c: u64): u64 { + m::map1(x, |y: u64| Cast(m::map2(Cast(Sub(y, c)), |y: u8| Add(y, Cast(c))))) + } +} // end 0xcafe::m + + +// -- Model dump after env processor unused struct params check: +module 0xcafe::m { + private fun map1(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun map2(x: u8,f: |u8|u8): u8 { + (f)(x) + } + private fun nested(x: u64,c: u64): u64 { + m::map1(x, |y: u64| Cast(m::map2(Cast(Sub(y, c)), |y: u8| Add(y, Cast(c))))) + } +} // end 0xcafe::m + + +// -- Model dump after env processor access and use check before inlining: +module 0xcafe::m { + private fun map1(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun map2(x: u8,f: |u8|u8): u8 { + (f)(x) + } + private fun nested(x: u64,c: u64): u64 { + m::map1(x, |y: u64| Cast(m::map2(Cast(Sub(y, c)), |y: u8| Add(y, Cast(c))))) + } +} // end 0xcafe::m + + +// -- Model dump after env processor inlining: +module 0xcafe::m { + private fun map1(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun map2(x: u8,f: |u8|u8): u8 { + (f)(x) + } + private fun nested(x: u64,c: u64): u64 { + m::map1(x, |y: u64| Cast(m::map2(Cast(Sub(y, c)), |y: u8| Add(y, Cast(c))))) + } +} // end 0xcafe::m + + +// -- Model dump after env processor access and use check after inlining: +module 0xcafe::m { + private fun map1(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun map2(x: u8,f: |u8|u8): u8 { + (f)(x) + } + private fun nested(x: u64,c: u64): u64 { + m::map1(x, |y: u64| Cast(m::map2(Cast(Sub(y, c)), |y: u8| Add(y, Cast(c))))) + } +} // end 0xcafe::m + + +// -- Model dump after env processor acquires check: +module 0xcafe::m { + private fun map1(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun map2(x: u8,f: |u8|u8): u8 { + (f)(x) + } + private fun nested(x: u64,c: u64): u64 { + m::map1(x, |y: u64| Cast(m::map2(Cast(Sub(y, c)), |y: u8| Add(y, Cast(c))))) + } +} // end 0xcafe::m + + +// -- Model dump after env processor simplifier: +module 0xcafe::m { + private fun map1(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun map2(x: u8,f: |u8|u8): u8 { + (f)(x) + } + private fun nested(x: u64,c: u64): u64 { + m::map1(x, |y: u64| Cast(m::map2(Cast(Sub(y, c)), |y: u8| Add(y, Cast(c))))) + } +} // end 0xcafe::m + + +// -- Model dump after env processor lambda-lifting: +module 0xcafe::m { + private fun map1(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun map2(x: u8,f: |u8|u8): u8 { + (f)(x) + } + private fun nested(x: u64,c: u64): u64 { + m::map1(x, closure m::nested$lambda$2(c)) + } + private fun nested$lambda$1(c: u64,y: u8): u8 { + Add(y, Cast(c)) + } + private fun nested$lambda$2(c: u64,y: u64): u64 { + Cast(m::map2(Cast(Sub(y, c)), closure m::nested$lambda$1(c))) + } +} // end 0xcafe::m + + +// -- Model dump after env processor specification checker: +module 0xcafe::m { + private fun map1(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun map2(x: u8,f: |u8|u8): u8 { + (f)(x) + } + private fun nested(x: u64,c: u64): u64 { + m::map1(x, closure m::nested$lambda$2(c)) + } + private fun nested$lambda$1(c: u64,y: u8): u8 { + Add(y, Cast(c)) + } + private fun nested$lambda$2(c: u64,y: u64): u64 { + Cast(m::map2(Cast(Sub(y, c)), closure m::nested$lambda$1(c))) + } +} // end 0xcafe::m + + +// -- Model dump after env processor specification rewriter: +module 0xcafe::m { + private fun map1(x: u64,f: |u64|u64): u64 { + (f)(x) + } + private fun map2(x: u8,f: |u8|u8): u8 { + (f)(x) + } + private fun nested(x: u64,c: u64): u64 { + m::map1(x, closure m::nested$lambda$2(c)) + } + private fun nested$lambda$1(c: u64,y: u8): u8 { + Add(y, Cast(c)) + } + private fun nested$lambda$2(c: u64,y: u64): u64 { + Cast(m::map2(Cast(Sub(y, c)), closure m::nested$lambda$1(c))) + } +} // end 0xcafe::m + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda-lifting/nested.move:5:9 + │ +5 │ f(x) + │ ^ + +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda-lifting/nested.move:10:9 + │ +10 │ f(x) + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda-lifting/nested.move:15:42 + │ +15 │ map1(x, |y| (map2((y - c as u8), |y| y + (c as u8)) as u64)) + │ ^^^^^^^^^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda-lifting/nested.move:15:17 + │ +15 │ map1(x, |y| (map2((y - c as u8), |y| y + (c as u8)) as u64)) + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda-lifting/pattern.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda-lifting/pattern.lambda.exp new file mode 100644 index 00000000000000..83b5c3b1b9710b --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda-lifting/pattern.lambda.exp @@ -0,0 +1,269 @@ +// -- Model dump before env processor pipeline: +module 0xcafe::m { + struct S { + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (m::S, u64)| { + let y: u64 = x; + Add(x, y) + }) + } +} // end 0xcafe::m + + +// -- Model dump after env processor unused checks: +module 0xcafe::m { + struct S { + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (m::S, u64)| { + let y: u64 = x; + Add(x, y) + }) + } +} // end 0xcafe::m + + +// -- Model dump after env processor type parameter check: +module 0xcafe::m { + struct S { + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (m::S, u64)| { + let y: u64 = x; + Add(x, y) + }) + } +} // end 0xcafe::m + + +// -- Model dump after env processor check recursive struct definition: +module 0xcafe::m { + struct S { + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (m::S, u64)| { + let y: u64 = x; + Add(x, y) + }) + } +} // end 0xcafe::m + + +// -- Model dump after env processor check cyclic type instantiation: +module 0xcafe::m { + struct S { + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (m::S, u64)| { + let y: u64 = x; + Add(x, y) + }) + } +} // end 0xcafe::m + + +// -- Model dump after env processor unused struct params check: +module 0xcafe::m { + struct S { + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (m::S, u64)| { + let y: u64 = x; + Add(x, y) + }) + } +} // end 0xcafe::m + + +// -- Model dump after env processor access and use check before inlining: +module 0xcafe::m { + struct S { + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (m::S, u64)| { + let y: u64 = x; + Add(x, y) + }) + } +} // end 0xcafe::m + + +// -- Model dump after env processor inlining: +module 0xcafe::m { + struct S { + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (m::S, u64)| { + let y: u64 = x; + Add(x, y) + }) + } +} // end 0xcafe::m + + +// -- Model dump after env processor access and use check after inlining: +module 0xcafe::m { + struct S { + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (m::S, u64)| { + let y: u64 = x; + Add(x, y) + }) + } +} // end 0xcafe::m + + +// -- Model dump after env processor acquires check: +module 0xcafe::m { + struct S { + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (m::S, u64)| { + let y: u64 = x; + Add(x, y) + }) + } +} // end 0xcafe::m + + +// -- Model dump after env processor simplifier: +module 0xcafe::m { + struct S { + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (m::S, u64)| { + let y: u64 = x; + Add(x, y) + }) + } +} // end 0xcafe::m + + +// -- Model dump after env processor lambda-lifting: +module 0xcafe::m { + struct S { + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, closure m::pattern$lambda$1()) + } + private fun pattern$lambda$1(param$0: m::S,_y: u64): u64 { + { + let m::S{ x } = param$0; + { + let y: u64 = x; + Add(x, y) + } + } + } +} // end 0xcafe::m + + +// -- Model dump after env processor specification checker: +module 0xcafe::m { + struct S { + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, closure m::pattern$lambda$1()) + } + private fun pattern$lambda$1(param$0: m::S,_y: u64): u64 { + { + let m::S{ x } = param$0; + { + let y: u64 = x; + Add(x, y) + } + } + } +} // end 0xcafe::m + + +// -- Model dump after env processor specification rewriter: +module 0xcafe::m { + struct S { + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, closure m::pattern$lambda$1()) + } + private fun pattern$lambda$1(param$0: m::S,_y: u64): u64 { + { + let m::S{ x } = param$0; + { + let y: u64 = x; + Add(x, y) + } + } + } +} // end 0xcafe::m + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda-lifting/pattern.move:10:9 + │ +10 │ f(s, x) + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda-lifting/pattern.move:15:23 + │ +15 │ consume(s, x, |S{x}, _y| { let y = x; x + y}) + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda.exp new file mode 100644 index 00000000000000..966c62450e7192 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `m::brk2` has a function parameter: + ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:6:9 + │ +6 │ fun brk2(f: | |) { + │ ^^^^ - Parameter `f` has function-valued type `|()|`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda.lambda.exp new file mode 100644 index 00000000000000..356f716bf10762 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda.lambda.exp @@ -0,0 +1,1406 @@ +// -- Model dump before env processor pipeline: +module 0xc0ffee::m { + public fun bar(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk2(|(): ()| break); + m::brk2(|(): ()| loop { + if true { + break + } else { + break + } + }); + m::brk2(|(): ()| loop { + if true { + continue + } else { + break + } + }); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } + private fun brk() { + break; + Tuple() + } + private fun brk2(f: |()|) { + (f)(); + Tuple() + } + private fun brk3() { + loop { + if true { + break; + Tuple() + } else { + break + } + } + } + private fun brk4() { + loop { + if true { + continue; + Tuple() + } else { + break + } + } + } + private fun broken() { + break; + Tuple() + } + private fun continued() { + continue; + Tuple() + } + public fun foo(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk(); + m::brk3(); + m::brk4(); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor unused checks: +module 0xc0ffee::m { + public fun bar(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk2(|(): ()| break); + m::brk2(|(): ()| loop { + if true { + break + } else { + break + } + }); + m::brk2(|(): ()| loop { + if true { + continue + } else { + break + } + }); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } + private fun brk() { + break; + Tuple() + } + private fun brk2(f: |()|) { + (f)(); + Tuple() + } + private fun brk3() { + loop { + if true { + break; + Tuple() + } else { + break + } + } + } + private fun brk4() { + loop { + if true { + continue; + Tuple() + } else { + break + } + } + } + private fun broken() { + break; + Tuple() + } + private fun continued() { + continue; + Tuple() + } + public fun foo(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk(); + m::brk3(); + m::brk4(); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor type parameter check: +module 0xc0ffee::m { + public fun bar(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk2(|(): ()| break); + m::brk2(|(): ()| loop { + if true { + break + } else { + break + } + }); + m::brk2(|(): ()| loop { + if true { + continue + } else { + break + } + }); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } + private fun brk() { + break; + Tuple() + } + private fun brk2(f: |()|) { + (f)(); + Tuple() + } + private fun brk3() { + loop { + if true { + break; + Tuple() + } else { + break + } + } + } + private fun brk4() { + loop { + if true { + continue; + Tuple() + } else { + break + } + } + } + private fun broken() { + break; + Tuple() + } + private fun continued() { + continue; + Tuple() + } + public fun foo(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk(); + m::brk3(); + m::brk4(); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor check recursive struct definition: +module 0xc0ffee::m { + public fun bar(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk2(|(): ()| break); + m::brk2(|(): ()| loop { + if true { + break + } else { + break + } + }); + m::brk2(|(): ()| loop { + if true { + continue + } else { + break + } + }); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } + private fun brk() { + break; + Tuple() + } + private fun brk2(f: |()|) { + (f)(); + Tuple() + } + private fun brk3() { + loop { + if true { + break; + Tuple() + } else { + break + } + } + } + private fun brk4() { + loop { + if true { + continue; + Tuple() + } else { + break + } + } + } + private fun broken() { + break; + Tuple() + } + private fun continued() { + continue; + Tuple() + } + public fun foo(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk(); + m::brk3(); + m::brk4(); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor check cyclic type instantiation: +module 0xc0ffee::m { + public fun bar(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk2(|(): ()| break); + m::brk2(|(): ()| loop { + if true { + break + } else { + break + } + }); + m::brk2(|(): ()| loop { + if true { + continue + } else { + break + } + }); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } + private fun brk() { + break; + Tuple() + } + private fun brk2(f: |()|) { + (f)(); + Tuple() + } + private fun brk3() { + loop { + if true { + break; + Tuple() + } else { + break + } + } + } + private fun brk4() { + loop { + if true { + continue; + Tuple() + } else { + break + } + } + } + private fun broken() { + break; + Tuple() + } + private fun continued() { + continue; + Tuple() + } + public fun foo(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk(); + m::brk3(); + m::brk4(); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor unused struct params check: +module 0xc0ffee::m { + public fun bar(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk2(|(): ()| break); + m::brk2(|(): ()| loop { + if true { + break + } else { + break + } + }); + m::brk2(|(): ()| loop { + if true { + continue + } else { + break + } + }); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } + private fun brk() { + break; + Tuple() + } + private fun brk2(f: |()|) { + (f)(); + Tuple() + } + private fun brk3() { + loop { + if true { + break; + Tuple() + } else { + break + } + } + } + private fun brk4() { + loop { + if true { + continue; + Tuple() + } else { + break + } + } + } + private fun broken() { + break; + Tuple() + } + private fun continued() { + continue; + Tuple() + } + public fun foo(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk(); + m::brk3(); + m::brk4(); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor access and use check before inlining: +module 0xc0ffee::m { + public fun bar(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk2(|(): ()| break); + m::brk2(|(): ()| loop { + if true { + break + } else { + break + } + }); + m::brk2(|(): ()| loop { + if true { + continue + } else { + break + } + }); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } + private fun brk() { + break; + Tuple() + } + private fun brk2(f: |()|) { + (f)(); + Tuple() + } + private fun brk3() { + loop { + if true { + break; + Tuple() + } else { + break + } + } + } + private fun brk4() { + loop { + if true { + continue; + Tuple() + } else { + break + } + } + } + private fun broken() { + break; + Tuple() + } + private fun continued() { + continue; + Tuple() + } + public fun foo(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk(); + m::brk3(); + m::brk4(); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor inlining: +module 0xc0ffee::m { + public fun bar(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk2(|(): ()| break); + m::brk2(|(): ()| loop { + if true { + break + } else { + break + } + }); + m::brk2(|(): ()| loop { + if true { + continue + } else { + break + } + }); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } + private fun brk() { + break; + Tuple() + } + private fun brk2(f: |()|) { + (f)(); + Tuple() + } + private fun brk3() { + loop { + if true { + break; + Tuple() + } else { + break + } + } + } + private fun brk4() { + loop { + if true { + continue; + Tuple() + } else { + break + } + } + } + private fun broken() { + break; + Tuple() + } + private fun continued() { + continue; + Tuple() + } + public fun foo(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk(); + m::brk3(); + m::brk4(); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor access and use check after inlining: +module 0xc0ffee::m { + public fun bar(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk2(|(): ()| break); + m::brk2(|(): ()| loop { + if true { + break + } else { + break + } + }); + m::brk2(|(): ()| loop { + if true { + continue + } else { + break + } + }); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } + private fun brk() { + break; + Tuple() + } + private fun brk2(f: |()|) { + (f)(); + Tuple() + } + private fun brk3() { + loop { + if true { + break; + Tuple() + } else { + break + } + } + } + private fun brk4() { + loop { + if true { + continue; + Tuple() + } else { + break + } + } + } + private fun broken() { + break; + Tuple() + } + private fun continued() { + continue; + Tuple() + } + public fun foo(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk(); + m::brk3(); + m::brk4(); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor acquires check: +module 0xc0ffee::m { + public fun bar(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk2(|(): ()| break); + m::brk2(|(): ()| loop { + if true { + break + } else { + break + } + }); + m::brk2(|(): ()| loop { + if true { + continue + } else { + break + } + }); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } + private fun brk() { + break; + Tuple() + } + private fun brk2(f: |()|) { + (f)(); + Tuple() + } + private fun brk3() { + loop { + if true { + break; + Tuple() + } else { + break + } + } + } + private fun brk4() { + loop { + if true { + continue; + Tuple() + } else { + break + } + } + } + private fun broken() { + break; + Tuple() + } + private fun continued() { + continue; + Tuple() + } + public fun foo(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk(); + m::brk3(); + m::brk4(); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor simplifier: +module 0xc0ffee::m { + public fun bar(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk2(|(): ()| break); + m::brk2(|(): ()| loop { + if true { + break + } else { + break + } + }); + m::brk2(|(): ()| loop { + if true { + continue + } else { + break + } + }); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } + private fun brk() { + break; + Tuple() + } + private fun brk2(f: |()|) { + (f)(); + Tuple() + } + private fun brk3() { + loop { + if true { + break; + Tuple() + } else { + break + } + } + } + private fun brk4() { + loop { + if true { + continue; + Tuple() + } else { + break + } + } + } + private fun broken() { + break; + Tuple() + } + private fun continued() { + continue; + Tuple() + } + public fun foo(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk(); + m::brk3(); + m::brk4(); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor lambda-lifting: +module 0xc0ffee::m { + public fun bar(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk2(closure m::bar$lambda$1()); + m::brk2(closure m::bar$lambda$2()); + m::brk2(closure m::bar$lambda$3()); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } + private fun brk() { + break; + Tuple() + } + private fun brk2(f: |()|) { + (f)(); + Tuple() + } + private fun brk3() { + loop { + if true { + break; + Tuple() + } else { + break + } + } + } + private fun brk4() { + loop { + if true { + continue; + Tuple() + } else { + break + } + } + } + private fun broken() { + break; + Tuple() + } + private fun continued() { + continue; + Tuple() + } + public fun foo(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk(); + m::brk3(); + m::brk4(); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } + private fun bar$lambda$1() { + break + } + private fun bar$lambda$2() { + loop { + if true { + break + } else { + break + } + } + } + private fun bar$lambda$3() { + loop { + if true { + continue + } else { + break + } + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor specification checker: +module 0xc0ffee::m { + public fun bar(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk2(closure m::bar$lambda$1()); + m::brk2(closure m::bar$lambda$2()); + m::brk2(closure m::bar$lambda$3()); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } + private fun brk() { + break; + Tuple() + } + private fun brk2(f: |()|) { + (f)(); + Tuple() + } + private fun brk3() { + loop { + if true { + break; + Tuple() + } else { + break + } + } + } + private fun brk4() { + loop { + if true { + continue; + Tuple() + } else { + break + } + } + } + private fun broken() { + break; + Tuple() + } + private fun continued() { + continue; + Tuple() + } + public fun foo(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk(); + m::brk3(); + m::brk4(); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } + private fun bar$lambda$1() { + break + } + private fun bar$lambda$2() { + loop { + if true { + break + } else { + break + } + } + } + private fun bar$lambda$3() { + loop { + if true { + continue + } else { + break + } + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor specification rewriter: +module 0xc0ffee::m { + public fun bar(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk2(closure m::bar$lambda$1()); + m::brk2(closure m::bar$lambda$2()); + m::brk2(closure m::bar$lambda$3()); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } + private fun brk() { + break; + Tuple() + } + private fun brk2(f: |()|) { + (f)(); + Tuple() + } + private fun brk3() { + loop { + if true { + break; + Tuple() + } else { + break + } + } + } + private fun brk4() { + loop { + if true { + continue; + Tuple() + } else { + break + } + } + } + private fun broken() { + break; + Tuple() + } + private fun continued() { + continue; + Tuple() + } + public fun foo(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk(); + m::brk3(); + m::brk4(); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } + private fun bar$lambda$1() { + break + } + private fun bar$lambda$2() { + loop { + if true { + break + } else { + break + } + } + } + private fun bar$lambda$3() { + loop { + if true { + continue + } else { + break + } + } + } +} // end 0xc0ffee::m + + + +Diagnostics: +error: missing enclosing loop statement + ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:3:9 + │ +3 │ break; + │ ^^^^^ + +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:7:9 + │ +7 │ f(); + │ ^ + +error: missing enclosing loop statement + ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:40:26 + │ +40 │ brk2(| | break); + │ ^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:40:22 + │ +40 │ brk2(| | break); + │ ^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:41:8 + │ +41 │ brk2(| | while (true) { break }); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:42:8 + │ +42 │ brk2(| | while (true) { continue }); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing enclosing loop statement + ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:49:2 + │ +49 │ break; + │ ^^^^^ + +error: missing enclosing loop statement + ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:53:2 + │ +53 │ continue; + │ ^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda.move new file mode 100644 index 00000000000000..b09cb706d65e63 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda.move @@ -0,0 +1,55 @@ +module 0xc0ffee::m { + fun brk() { + break; + } + + fun brk2(f: | |) { + f(); + } + + fun brk3() { + while (true) { + break; + } + } + + 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(| | break); + brk2(| | while (true) { break }); + brk2(| | while (true) { continue }); + } + }; + i + } + + fun broken() { + break; + } + + fun continued() { + continue; + } +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda_typed.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda_typed.exp new file mode 100644 index 00000000000000..586b4d1ad9d4aa --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda_typed.exp @@ -0,0 +1,13 @@ + +Diagnostics: +error: Break outside of a loop not currently supported in inline functions + ┌─ tests/lambda/inline-parity/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/lambda/inline-parity/break_continue_in_lambda_typed.move:40:32 + │ +40 │ brk2(|_x: u64| break); + │ ^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda_typed.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda_typed.lambda.exp new file mode 100644 index 00000000000000..84ae1f814873ff --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda_typed.lambda.exp @@ -0,0 +1,678 @@ +// -- Model dump before env processor pipeline: +module 0xc0ffee::m { + public fun bar(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk2(|_x: u64| break); + m::brk2(|_x: u64| loop { + if true { + break + } else { + break + } + }); + m::brk2(|_x: u64| loop { + if true { + continue + } else { + break + } + }); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } + private inline fun brk() { + break; + Tuple() + } + private inline fun brk2(f: |u64|) { + (f)(2); + Tuple() + } + private inline fun brk3() { + loop { + if true { + break; + Tuple() + } else { + break + } + } + } + private inline fun brk4() { + loop { + if true { + continue; + Tuple() + } else { + break + } + } + } + private fun broken() { + break; + Tuple() + } + private fun continued() { + continue; + Tuple() + } + public fun foo(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk(); + m::brk3(); + m::brk4(); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor unused checks: +module 0xc0ffee::m { + public fun bar(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk2(|_x: u64| break); + m::brk2(|_x: u64| loop { + if true { + break + } else { + break + } + }); + m::brk2(|_x: u64| loop { + if true { + continue + } else { + break + } + }); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } + private inline fun brk() { + break; + Tuple() + } + private inline fun brk2(f: |u64|) { + (f)(2); + Tuple() + } + private inline fun brk3() { + loop { + if true { + break; + Tuple() + } else { + break + } + } + } + private inline fun brk4() { + loop { + if true { + continue; + Tuple() + } else { + break + } + } + } + private fun broken() { + break; + Tuple() + } + private fun continued() { + continue; + Tuple() + } + public fun foo(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk(); + m::brk3(); + m::brk4(); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor type parameter check: +module 0xc0ffee::m { + public fun bar(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk2(|_x: u64| break); + m::brk2(|_x: u64| loop { + if true { + break + } else { + break + } + }); + m::brk2(|_x: u64| loop { + if true { + continue + } else { + break + } + }); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } + private inline fun brk() { + break; + Tuple() + } + private inline fun brk2(f: |u64|) { + (f)(2); + Tuple() + } + private inline fun brk3() { + loop { + if true { + break; + Tuple() + } else { + break + } + } + } + private inline fun brk4() { + loop { + if true { + continue; + Tuple() + } else { + break + } + } + } + private fun broken() { + break; + Tuple() + } + private fun continued() { + continue; + Tuple() + } + public fun foo(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk(); + m::brk3(); + m::brk4(); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor check recursive struct definition: +module 0xc0ffee::m { + public fun bar(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk2(|_x: u64| break); + m::brk2(|_x: u64| loop { + if true { + break + } else { + break + } + }); + m::brk2(|_x: u64| loop { + if true { + continue + } else { + break + } + }); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } + private inline fun brk() { + break; + Tuple() + } + private inline fun brk2(f: |u64|) { + (f)(2); + Tuple() + } + private inline fun brk3() { + loop { + if true { + break; + Tuple() + } else { + break + } + } + } + private inline fun brk4() { + loop { + if true { + continue; + Tuple() + } else { + break + } + } + } + private fun broken() { + break; + Tuple() + } + private fun continued() { + continue; + Tuple() + } + public fun foo(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk(); + m::brk3(); + m::brk4(); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor check cyclic type instantiation: +module 0xc0ffee::m { + public fun bar(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk2(|_x: u64| break); + m::brk2(|_x: u64| loop { + if true { + break + } else { + break + } + }); + m::brk2(|_x: u64| loop { + if true { + continue + } else { + break + } + }); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } + private inline fun brk() { + break; + Tuple() + } + private inline fun brk2(f: |u64|) { + (f)(2); + Tuple() + } + private inline fun brk3() { + loop { + if true { + break; + Tuple() + } else { + break + } + } + } + private inline fun brk4() { + loop { + if true { + continue; + Tuple() + } else { + break + } + } + } + private fun broken() { + break; + Tuple() + } + private fun continued() { + continue; + Tuple() + } + public fun foo(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk(); + m::brk3(); + m::brk4(); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor unused struct params check: +module 0xc0ffee::m { + public fun bar(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk2(|_x: u64| break); + m::brk2(|_x: u64| loop { + if true { + break + } else { + break + } + }); + m::brk2(|_x: u64| loop { + if true { + continue + } else { + break + } + }); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } + private inline fun brk() { + break; + Tuple() + } + private inline fun brk2(f: |u64|) { + (f)(2); + Tuple() + } + private inline fun brk3() { + loop { + if true { + break; + Tuple() + } else { + break + } + } + } + private inline fun brk4() { + loop { + if true { + continue; + Tuple() + } else { + break + } + } + } + private fun broken() { + break; + Tuple() + } + private fun continued() { + continue; + Tuple() + } + public fun foo(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk(); + m::brk3(); + m::brk4(); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor access and use check before inlining: +module 0xc0ffee::m { + public fun bar(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk2(|_x: u64| break); + m::brk2(|_x: u64| loop { + if true { + break + } else { + break + } + }); + m::brk2(|_x: u64| loop { + if true { + continue + } else { + break + } + }); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } + private inline fun brk() { + break; + Tuple() + } + private inline fun brk2(f: |u64|) { + (f)(2); + Tuple() + } + private inline fun brk3() { + loop { + if true { + break; + Tuple() + } else { + break + } + } + } + private inline fun brk4() { + loop { + if true { + continue; + Tuple() + } else { + break + } + } + } + private fun broken() { + break; + Tuple() + } + private fun continued() { + continue; + Tuple() + } + public fun foo(): u64 { + { + let i: u64 = 0; + loop { + if Lt(i, 10) { + i: u64 = Add(i, 1); + if Eq(i, 5) { + m::brk(); + m::brk3(); + m::brk4(); + Tuple() + } else { + Tuple() + } + } else { + break + } + }; + i + } + } +} // end 0xc0ffee::m + + + +Diagnostics: +error: Break outside of a loop not currently supported in inline functions + ┌─ tests/lambda/inline-parity/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/lambda/inline-parity/break_continue_in_lambda_typed.move:40:32 + │ +40 │ brk2(|_x: u64| break); + │ ^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda_typed.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda_typed.move new file mode 100644 index 00000000000000..52d85e21563394 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/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/lambda/inline-parity/bug_10991.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991.exp new file mode 100644 index 00000000000000..f9a4d4a9ed4d94 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991.exp @@ -0,0 +1,9 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `Test::foo` has function parameters: + ┌─ tests/lambda/inline-parity/bug_10991.move:3:9 + │ +3 │ fun foo(f:|u64, u64| u64, g: |u64, u64| u64, x: u64, _y: u64): u64 { + │ ^^^ - - Parameter `g` has function-valued type `|(u64, u64)|u64`. + │ │ + │ Parameter `f` has function-valued type `|(u64, u64)|u64`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991.lambda.exp new file mode 100644 index 00000000000000..fea2410cdc948d --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991.lambda.exp @@ -0,0 +1,285 @@ +// -- Model dump before env processor pipeline: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, 10, 100), 110) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor unused checks: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, 10, 100), 110) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor type parameter check: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, 10, 100), 110) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, 10, 100), 110) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, 10, 100), 110) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor unused struct params check: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, 10, 100), 110) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, 10, 100), 110) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor inlining: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, 10, 100), 110) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, 10, 100), 110) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor acquires check: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, 10, 100), 110) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor simplifier: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, 10, 100), 110) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor lambda-lifting: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 110) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + private fun test$lambda$1(x: u64,param$1: u64): u64 { + { + let _: u64 = param$1; + x + } + } + private fun test$lambda$2(param$0: u64,y: u64): u64 { + { + let _: u64 = param$0; + y + } + } +} // end 0x42::Test + + +// -- Model dump after env processor specification checker: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 110) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + private fun test$lambda$1(x: u64,param$1: u64): u64 { + { + let _: u64 = param$1; + x + } + } + private fun test$lambda$2(param$0: u64,y: u64): u64 { + { + let _: u64 = param$0; + y + } + } +} // end 0x42::Test + + +// -- Model dump after env processor specification rewriter: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 110) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + private fun test$lambda$1(x: u64,param$1: u64): u64 { + { + let _: u64 = param$1; + x + } + } + private fun test$lambda$2(param$0: u64,y: u64): u64 { + { + let _: u64 = param$0; + y + } + } +} // end 0x42::Test + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/bug_10991.move:4:9 + │ +4 │ f(x, _y) + g(x, _y) + │ ^ + +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/bug_10991.move:4:20 + │ +4 │ f(x, _y) + g(x, _y) + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/bug_10991.move:8:21 + │ +8 │ assert!(foo(|x, _| x, |_, y| y, 10, 100) == 110, 0); + │ ^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/bug_10991.move:8:31 + │ +8 │ assert!(foo(|x, _| x, |_, y| y, 10, 100) == 110, 0); + │ ^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991.move new file mode 100644 index 00000000000000..9831b7eb02eb11 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991.move @@ -0,0 +1,12 @@ +//# publish +module 0x42::Test { + 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, _| x, |_, y| y, 10, 100) == 110, 0); + } +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam.exp new file mode 100644 index 00000000000000..80e2c8d92ef3b9 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam.exp @@ -0,0 +1,9 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `Test::foo` has function parameters: + ┌─ tests/lambda/inline-parity/bug_10991_noparam.move:3:9 + │ +3 │ fun foo(f:|u64, u64| u64, g: |u64, u64| u64, x: u64, _y: u64): u64 { + │ ^^^ - - Parameter `g` has function-valued type `|(u64, u64)|u64`. + │ │ + │ Parameter `f` has function-valued type `|(u64, u64)|u64`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam.lambda.exp new file mode 100644 index 00000000000000..b1ce2d980a7d76 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam.lambda.exp @@ -0,0 +1,303 @@ +// -- Model dump before env processor pipeline: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(|(_: u64, _: u64): (u64, u64)| 3, |(_: u64, _: u64): (u64, u64)| 10, 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor unused checks: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(|(_: u64, _: u64): (u64, u64)| 3, |(_: u64, _: u64): (u64, u64)| 10, 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor type parameter check: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(|(_: u64, _: u64): (u64, u64)| 3, |(_: u64, _: u64): (u64, u64)| 10, 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(|(_: u64, _: u64): (u64, u64)| 3, |(_: u64, _: u64): (u64, u64)| 10, 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(|(_: u64, _: u64): (u64, u64)| 3, |(_: u64, _: u64): (u64, u64)| 10, 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor unused struct params check: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(|(_: u64, _: u64): (u64, u64)| 3, |(_: u64, _: u64): (u64, u64)| 10, 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(|(_: u64, _: u64): (u64, u64)| 3, |(_: u64, _: u64): (u64, u64)| 10, 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor inlining: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(|(_: u64, _: u64): (u64, u64)| 3, |(_: u64, _: u64): (u64, u64)| 10, 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(|(_: u64, _: u64): (u64, u64)| 3, |(_: u64, _: u64): (u64, u64)| 10, 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor acquires check: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(|(_: u64, _: u64): (u64, u64)| 3, |(_: u64, _: u64): (u64, u64)| 10, 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor simplifier: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(|(_: u64, _: u64): (u64, u64)| 3, |(_: u64, _: u64): (u64, u64)| 10, 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor lambda-lifting: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + private fun test$lambda$1(param$0: u64,param$1: u64): u64 { + { + let _: u64 = param$1; + { + let _: u64 = param$0; + 3 + } + } + } + private fun test$lambda$2(param$0: u64,param$1: u64): u64 { + { + let _: u64 = param$1; + { + let _: u64 = param$0; + 10 + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor specification checker: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + private fun test$lambda$1(param$0: u64,param$1: u64): u64 { + { + let _: u64 = param$1; + { + let _: u64 = param$0; + 3 + } + } + } + private fun test$lambda$2(param$0: u64,param$1: u64): u64 { + { + let _: u64 = param$1; + { + let _: u64 = param$0; + 10 + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor specification rewriter: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun test() { + if Eq(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + private fun test$lambda$1(param$0: u64,param$1: u64): u64 { + { + let _: u64 = param$1; + { + let _: u64 = param$0; + 3 + } + } + } + private fun test$lambda$2(param$0: u64,param$1: u64): u64 { + { + let _: u64 = param$1; + { + let _: u64 = param$0; + 10 + } + } + } +} // end 0x42::Test + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/bug_10991_noparam.move:4:9 + │ +4 │ f(x, _y) + g(x, _y) + │ ^ + +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/bug_10991_noparam.move:4:20 + │ +4 │ f(x, _y) + g(x, _y) + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/bug_10991_noparam.move:8:21 + │ +8 │ assert!(foo(|_, _| 3, |_, _| 10, 10, 100) == 13, 0); + │ ^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/bug_10991_noparam.move:8:31 + │ +8 │ assert!(foo(|_, _| 3, |_, _| 10, 10, 100) == 13, 0); + │ ^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam.move new file mode 100644 index 00000000000000..c2189f2b23de74 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam.move @@ -0,0 +1,12 @@ +//# publish +module 0x42::Test { + 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(|_, _| 3, |_, _| 10, 10, 100) == 13, 0); + } +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam2.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam2.exp new file mode 100644 index 00000000000000..8f8041970a908d --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam2.exp @@ -0,0 +1,9 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `Test::foo` has function parameters: + ┌─ tests/lambda/inline-parity/bug_10991_noparam2.move:3:9 + │ +3 │ fun foo(f:|u64| u64, g: |u64| u64, x: u64, _: u64): u64 { + │ ^^^ - - Parameter `g` has function-valued type `|u64|u64`. + │ │ + │ Parameter `f` has function-valued type `|u64|u64`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam2.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam2.lambda.exp new file mode 100644 index 00000000000000..f0eec150641eb9 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam2.lambda.exp @@ -0,0 +1,285 @@ +// -- Model dump before env processor pipeline: +module 0x42::Test { + private fun foo(f: |u64|u64,g: |u64|u64,x: u64,_: u64): u64 { + Add((f)(x), (g)(x)) + } + public fun test() { + if Eq(Test::foo(|_: u64| 3, |_: u64| 10, 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor unused checks: +module 0x42::Test { + private fun foo(f: |u64|u64,g: |u64|u64,x: u64,_: u64): u64 { + Add((f)(x), (g)(x)) + } + public fun test() { + if Eq(Test::foo(|_: u64| 3, |_: u64| 10, 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor type parameter check: +module 0x42::Test { + private fun foo(f: |u64|u64,g: |u64|u64,x: u64,_: u64): u64 { + Add((f)(x), (g)(x)) + } + public fun test() { + if Eq(Test::foo(|_: u64| 3, |_: u64| 10, 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::Test { + private fun foo(f: |u64|u64,g: |u64|u64,x: u64,_: u64): u64 { + Add((f)(x), (g)(x)) + } + public fun test() { + if Eq(Test::foo(|_: u64| 3, |_: u64| 10, 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::Test { + private fun foo(f: |u64|u64,g: |u64|u64,x: u64,_: u64): u64 { + Add((f)(x), (g)(x)) + } + public fun test() { + if Eq(Test::foo(|_: u64| 3, |_: u64| 10, 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor unused struct params check: +module 0x42::Test { + private fun foo(f: |u64|u64,g: |u64|u64,x: u64,_: u64): u64 { + Add((f)(x), (g)(x)) + } + public fun test() { + if Eq(Test::foo(|_: u64| 3, |_: u64| 10, 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::Test { + private fun foo(f: |u64|u64,g: |u64|u64,x: u64,_: u64): u64 { + Add((f)(x), (g)(x)) + } + public fun test() { + if Eq(Test::foo(|_: u64| 3, |_: u64| 10, 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor inlining: +module 0x42::Test { + private fun foo(f: |u64|u64,g: |u64|u64,x: u64,_: u64): u64 { + Add((f)(x), (g)(x)) + } + public fun test() { + if Eq(Test::foo(|_: u64| 3, |_: u64| 10, 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::Test { + private fun foo(f: |u64|u64,g: |u64|u64,x: u64,_: u64): u64 { + Add((f)(x), (g)(x)) + } + public fun test() { + if Eq(Test::foo(|_: u64| 3, |_: u64| 10, 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor acquires check: +module 0x42::Test { + private fun foo(f: |u64|u64,g: |u64|u64,x: u64,_: u64): u64 { + Add((f)(x), (g)(x)) + } + public fun test() { + if Eq(Test::foo(|_: u64| 3, |_: u64| 10, 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor simplifier: +module 0x42::Test { + private fun foo(f: |u64|u64,g: |u64|u64,x: u64,_: u64): u64 { + Add((f)(x), (g)(x)) + } + public fun test() { + if Eq(Test::foo(|_: u64| 3, |_: u64| 10, 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor lambda-lifting: +module 0x42::Test { + private fun foo(f: |u64|u64,g: |u64|u64,x: u64,_: u64): u64 { + Add((f)(x), (g)(x)) + } + public fun test() { + if Eq(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + private fun test$lambda$1(param$0: u64): u64 { + { + let _: u64 = param$0; + 3 + } + } + private fun test$lambda$2(param$0: u64): u64 { + { + let _: u64 = param$0; + 10 + } + } +} // end 0x42::Test + + +// -- Model dump after env processor specification checker: +module 0x42::Test { + private fun foo(f: |u64|u64,g: |u64|u64,x: u64,_: u64): u64 { + Add((f)(x), (g)(x)) + } + public fun test() { + if Eq(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + private fun test$lambda$1(param$0: u64): u64 { + { + let _: u64 = param$0; + 3 + } + } + private fun test$lambda$2(param$0: u64): u64 { + { + let _: u64 = param$0; + 10 + } + } +} // end 0x42::Test + + +// -- Model dump after env processor specification rewriter: +module 0x42::Test { + private fun foo(f: |u64|u64,g: |u64|u64,x: u64,_: u64): u64 { + Add((f)(x), (g)(x)) + } + public fun test() { + if Eq(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 13) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + private fun test$lambda$1(param$0: u64): u64 { + { + let _: u64 = param$0; + 3 + } + } + private fun test$lambda$2(param$0: u64): u64 { + { + let _: u64 = param$0; + 10 + } + } +} // end 0x42::Test + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/bug_10991_noparam2.move:4:9 + │ +4 │ f(x) + g(x) + │ ^ + +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/bug_10991_noparam2.move:4:16 + │ +4 │ f(x) + g(x) + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/bug_10991_noparam2.move:8:21 + │ +8 │ assert!(foo(|_| 3, |_| 10, 10, 100) == 13, 0); + │ ^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/bug_10991_noparam2.move:8:28 + │ +8 │ assert!(foo(|_| 3, |_| 10, 10, 100) == 13, 0); + │ ^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam2.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam2.move new file mode 100644 index 00000000000000..0d857ffe2cfc9d --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam2.move @@ -0,0 +1,12 @@ +//# publish +module 0x42::Test { + fun foo(f:|u64| u64, g: |u64| u64, x: u64, _: u64): u64 { + f(x) + g(x) + } + + public fun test() { + assert!(foo(|_| 3, |_| 10, 10, 100) == 13, 0); + } +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991a.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991a.exp new file mode 100644 index 00000000000000..f52624078c3e08 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991a.exp @@ -0,0 +1,13 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `Test::foo` has function parameters: + ┌─ tests/lambda/inline-parity/bug_10991a.move:3:9 + │ +3 │ fun foo(f:|u64, u64| u64, g: |u64, u64| u64, + │ ^^^ - - Parameter `g` has function-valued type `|(u64, u64)|u64`. + │ │ + │ Parameter `f` has function-valued type `|(u64, u64)|u64`. +4 │ h:|u64, u64| u64, i: |u64, u64| u64, + │ - - Parameter `i` has function-valued type `|(u64, u64)|u64`. + │ │ + │ Parameter `h` has function-valued type `|(u64, u64)|u64`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991a.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991a.lambda.exp new file mode 100644 index 00000000000000..172a728293cdf6 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991a.lambda.exp @@ -0,0 +1,327 @@ +// -- Model dump before env processor pipeline: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,h: |(u64, u64)|u64,i: |(u64, u64)|u64,x: u64,y: u64): u64 { + Add(Add(Add((f)(x, y), (g)(x, y)), (h)(x, y)), (i)(x, y)) + } + public fun test() { + if Eq(Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, |(a: u64, _b: u64): (u64, u64)| a, |(_c: u64, d: u64): (u64, u64)| d, 10, 100), 220) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor unused checks: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,h: |(u64, u64)|u64,i: |(u64, u64)|u64,x: u64,y: u64): u64 { + Add(Add(Add((f)(x, y), (g)(x, y)), (h)(x, y)), (i)(x, y)) + } + public fun test() { + if Eq(Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, |(a: u64, _b: u64): (u64, u64)| a, |(_c: u64, d: u64): (u64, u64)| d, 10, 100), 220) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor type parameter check: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,h: |(u64, u64)|u64,i: |(u64, u64)|u64,x: u64,y: u64): u64 { + Add(Add(Add((f)(x, y), (g)(x, y)), (h)(x, y)), (i)(x, y)) + } + public fun test() { + if Eq(Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, |(a: u64, _b: u64): (u64, u64)| a, |(_c: u64, d: u64): (u64, u64)| d, 10, 100), 220) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,h: |(u64, u64)|u64,i: |(u64, u64)|u64,x: u64,y: u64): u64 { + Add(Add(Add((f)(x, y), (g)(x, y)), (h)(x, y)), (i)(x, y)) + } + public fun test() { + if Eq(Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, |(a: u64, _b: u64): (u64, u64)| a, |(_c: u64, d: u64): (u64, u64)| d, 10, 100), 220) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,h: |(u64, u64)|u64,i: |(u64, u64)|u64,x: u64,y: u64): u64 { + Add(Add(Add((f)(x, y), (g)(x, y)), (h)(x, y)), (i)(x, y)) + } + public fun test() { + if Eq(Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, |(a: u64, _b: u64): (u64, u64)| a, |(_c: u64, d: u64): (u64, u64)| d, 10, 100), 220) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor unused struct params check: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,h: |(u64, u64)|u64,i: |(u64, u64)|u64,x: u64,y: u64): u64 { + Add(Add(Add((f)(x, y), (g)(x, y)), (h)(x, y)), (i)(x, y)) + } + public fun test() { + if Eq(Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, |(a: u64, _b: u64): (u64, u64)| a, |(_c: u64, d: u64): (u64, u64)| d, 10, 100), 220) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,h: |(u64, u64)|u64,i: |(u64, u64)|u64,x: u64,y: u64): u64 { + Add(Add(Add((f)(x, y), (g)(x, y)), (h)(x, y)), (i)(x, y)) + } + public fun test() { + if Eq(Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, |(a: u64, _b: u64): (u64, u64)| a, |(_c: u64, d: u64): (u64, u64)| d, 10, 100), 220) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor inlining: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,h: |(u64, u64)|u64,i: |(u64, u64)|u64,x: u64,y: u64): u64 { + Add(Add(Add((f)(x, y), (g)(x, y)), (h)(x, y)), (i)(x, y)) + } + public fun test() { + if Eq(Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, |(a: u64, _b: u64): (u64, u64)| a, |(_c: u64, d: u64): (u64, u64)| d, 10, 100), 220) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,h: |(u64, u64)|u64,i: |(u64, u64)|u64,x: u64,y: u64): u64 { + Add(Add(Add((f)(x, y), (g)(x, y)), (h)(x, y)), (i)(x, y)) + } + public fun test() { + if Eq(Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, |(a: u64, _b: u64): (u64, u64)| a, |(_c: u64, d: u64): (u64, u64)| d, 10, 100), 220) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor acquires check: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,h: |(u64, u64)|u64,i: |(u64, u64)|u64,x: u64,y: u64): u64 { + Add(Add(Add((f)(x, y), (g)(x, y)), (h)(x, y)), (i)(x, y)) + } + public fun test() { + if Eq(Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, |(a: u64, _b: u64): (u64, u64)| a, |(_c: u64, d: u64): (u64, u64)| d, 10, 100), 220) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor simplifier: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,h: |(u64, u64)|u64,i: |(u64, u64)|u64,x: u64,y: u64): u64 { + Add(Add(Add((f)(x, y), (g)(x, y)), (h)(x, y)), (i)(x, y)) + } + public fun test() { + if Eq(Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, |(a: u64, _b: u64): (u64, u64)| a, |(_c: u64, d: u64): (u64, u64)| d, 10, 100), 220) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor lambda-lifting: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,h: |(u64, u64)|u64,i: |(u64, u64)|u64,x: u64,y: u64): u64 { + Add(Add(Add((f)(x, y), (g)(x, y)), (h)(x, y)), (i)(x, y)) + } + public fun test() { + if Eq(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), closure Test::test$lambda$3(), closure Test::test$lambda$4(), 10, 100), 220) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + private fun test$lambda$1(x: u64,param$1: u64): u64 { + { + let _: u64 = param$1; + x + } + } + private fun test$lambda$2(param$0: u64,y: u64): u64 { + { + let _: u64 = param$0; + y + } + } + private fun test$lambda$3(a: u64,_b: u64): u64 { + a + } + private fun test$lambda$4(_c: u64,d: u64): u64 { + d + } +} // end 0x42::Test + + +// -- Model dump after env processor specification checker: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,h: |(u64, u64)|u64,i: |(u64, u64)|u64,x: u64,y: u64): u64 { + Add(Add(Add((f)(x, y), (g)(x, y)), (h)(x, y)), (i)(x, y)) + } + public fun test() { + if Eq(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), closure Test::test$lambda$3(), closure Test::test$lambda$4(), 10, 100), 220) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + private fun test$lambda$1(x: u64,param$1: u64): u64 { + { + let _: u64 = param$1; + x + } + } + private fun test$lambda$2(param$0: u64,y: u64): u64 { + { + let _: u64 = param$0; + y + } + } + private fun test$lambda$3(a: u64,_b: u64): u64 { + a + } + private fun test$lambda$4(_c: u64,d: u64): u64 { + d + } +} // end 0x42::Test + + +// -- Model dump after env processor specification rewriter: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,h: |(u64, u64)|u64,i: |(u64, u64)|u64,x: u64,y: u64): u64 { + Add(Add(Add((f)(x, y), (g)(x, y)), (h)(x, y)), (i)(x, y)) + } + public fun test() { + if Eq(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), closure Test::test$lambda$3(), closure Test::test$lambda$4(), 10, 100), 220) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + private fun test$lambda$1(x: u64,param$1: u64): u64 { + { + let _: u64 = param$1; + x + } + } + private fun test$lambda$2(param$0: u64,y: u64): u64 { + { + let _: u64 = param$0; + y + } + } + private fun test$lambda$3(a: u64,_b: u64): u64 { + a + } + private fun test$lambda$4(_c: u64,d: u64): u64 { + d + } +} // end 0x42::Test + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/bug_10991a.move:6:13 + │ +6 │ f(x, y) + g(x, y) + h(x, y) + i(x, y) + │ ^ + +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/bug_10991a.move:6:23 + │ +6 │ f(x, y) + g(x, y) + h(x, y) + i(x, y) + │ ^ + +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/bug_10991a.move:6:33 + │ +6 │ f(x, y) + g(x, y) + h(x, y) + i(x, y) + │ ^ + +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/bug_10991a.move:6:43 + │ +6 │ f(x, y) + g(x, y) + h(x, y) + i(x, y) + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/bug_10991a.move:10:21 + │ +10 │ assert!(foo(|x, _| x, |_, y| y, + │ ^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/bug_10991a.move:10:31 + │ +10 │ assert!(foo(|x, _| x, |_, y| y, + │ ^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/bug_10991a.move:11:6 + │ +11 │ |a, _b| a, |_c, d| d, + │ ^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/bug_10991a.move:11:17 + │ +11 │ |a, _b| a, |_c, d| d, + │ ^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991a.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991a.move new file mode 100644 index 00000000000000..0361ff51bd48c2 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991a.move @@ -0,0 +1,16 @@ +//# publish +module 0x42::Test { + 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, _| x, |_, y| y, + |a, _b| a, |_c, d| d, + 10, 100) == 220, 0); + } +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991b.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991b.exp new file mode 100644 index 00000000000000..762ffbe9736c71 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991b.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `Test::foo` has a function parameter: + ┌─ tests/lambda/inline-parity/bug_10991b.move:3:9 + │ +3 │ fun foo(g: |u64, u64| u64, x: u64, _y: u64): u64 { + │ ^^^ - Parameter `g` has function-valued type `|(u64, u64)|u64`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991b.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991b.lambda.exp new file mode 100644 index 00000000000000..4d75c19204ac0c --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991b.lambda.exp @@ -0,0 +1,255 @@ +// -- Model dump before env processor pipeline: +module 0x42::Test { + private fun foo(g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + (g)(x, _y) + } + public fun test() { + if Eq(Test::foo(|(_: u64, y: u64): (u64, u64)| y, 10, 100), 100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor unused checks: +module 0x42::Test { + private fun foo(g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + (g)(x, _y) + } + public fun test() { + if Eq(Test::foo(|(_: u64, y: u64): (u64, u64)| y, 10, 100), 100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor type parameter check: +module 0x42::Test { + private fun foo(g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + (g)(x, _y) + } + public fun test() { + if Eq(Test::foo(|(_: u64, y: u64): (u64, u64)| y, 10, 100), 100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::Test { + private fun foo(g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + (g)(x, _y) + } + public fun test() { + if Eq(Test::foo(|(_: u64, y: u64): (u64, u64)| y, 10, 100), 100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::Test { + private fun foo(g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + (g)(x, _y) + } + public fun test() { + if Eq(Test::foo(|(_: u64, y: u64): (u64, u64)| y, 10, 100), 100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor unused struct params check: +module 0x42::Test { + private fun foo(g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + (g)(x, _y) + } + public fun test() { + if Eq(Test::foo(|(_: u64, y: u64): (u64, u64)| y, 10, 100), 100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::Test { + private fun foo(g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + (g)(x, _y) + } + public fun test() { + if Eq(Test::foo(|(_: u64, y: u64): (u64, u64)| y, 10, 100), 100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor inlining: +module 0x42::Test { + private fun foo(g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + (g)(x, _y) + } + public fun test() { + if Eq(Test::foo(|(_: u64, y: u64): (u64, u64)| y, 10, 100), 100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::Test { + private fun foo(g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + (g)(x, _y) + } + public fun test() { + if Eq(Test::foo(|(_: u64, y: u64): (u64, u64)| y, 10, 100), 100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor acquires check: +module 0x42::Test { + private fun foo(g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + (g)(x, _y) + } + public fun test() { + if Eq(Test::foo(|(_: u64, y: u64): (u64, u64)| y, 10, 100), 100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor simplifier: +module 0x42::Test { + private fun foo(g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + (g)(x, _y) + } + public fun test() { + if Eq(Test::foo(|(_: u64, y: u64): (u64, u64)| y, 10, 100), 100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor lambda-lifting: +module 0x42::Test { + private fun foo(g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + (g)(x, _y) + } + public fun test() { + if Eq(Test::foo(closure Test::test$lambda$1(), 10, 100), 100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + private fun test$lambda$1(param$0: u64,y: u64): u64 { + { + let _: u64 = param$0; + y + } + } +} // end 0x42::Test + + +// -- Model dump after env processor specification checker: +module 0x42::Test { + private fun foo(g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + (g)(x, _y) + } + public fun test() { + if Eq(Test::foo(closure Test::test$lambda$1(), 10, 100), 100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + private fun test$lambda$1(param$0: u64,y: u64): u64 { + { + let _: u64 = param$0; + y + } + } +} // end 0x42::Test + + +// -- Model dump after env processor specification rewriter: +module 0x42::Test { + private fun foo(g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + (g)(x, _y) + } + public fun test() { + if Eq(Test::foo(closure Test::test$lambda$1(), 10, 100), 100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + private fun test$lambda$1(param$0: u64,y: u64): u64 { + { + let _: u64 = param$0; + y + } + } +} // end 0x42::Test + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/bug_10991b.move:4:9 + │ +4 │ g(x, _y) + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/bug_10991b.move:8:21 + │ +8 │ assert!(foo(|_, y| y, + │ ^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991b.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991b.move new file mode 100644 index 00000000000000..c70f346425d4be --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991b.move @@ -0,0 +1,13 @@ +//# publish +module 0x42::Test { + fun foo(g: |u64, u64| u64, x: u64, _y: u64): u64 { + g(x, _y) + } + + public fun test() { + assert!(foo(|_, y| y, + 10, 100) == 100, 0); + } +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991c.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991c.exp new file mode 100644 index 00000000000000..986bb2a02ab4b8 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991c.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `Test::foo` has a function parameter: + ┌─ tests/lambda/inline-parity/bug_10991c.move:3:9 + │ +3 │ fun foo(g: |u64, u64, u64, u64| u64, x: u64, y: u64, z: u64, q:u64): u64 { + │ ^^^ - Parameter `g` has function-valued type `|(u64, u64, u64, u64)|u64`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991c.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991c.lambda.exp new file mode 100644 index 00000000000000..486526cead33be --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991c.lambda.exp @@ -0,0 +1,264 @@ +// -- Model dump before env processor pipeline: +module 0x42::Test { + private 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() { + if Eq(Test::foo(|(_: u64, y: u64, _: u64, q: u64): (u64, u64, u64, u64)| Add(y, q), 10, 100, 1000, 10000), 10100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor unused checks: +module 0x42::Test { + private 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() { + if Eq(Test::foo(|(_: u64, y: u64, _: u64, q: u64): (u64, u64, u64, u64)| Add(y, q), 10, 100, 1000, 10000), 10100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor type parameter check: +module 0x42::Test { + private 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() { + if Eq(Test::foo(|(_: u64, y: u64, _: u64, q: u64): (u64, u64, u64, u64)| Add(y, q), 10, 100, 1000, 10000), 10100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::Test { + private 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() { + if Eq(Test::foo(|(_: u64, y: u64, _: u64, q: u64): (u64, u64, u64, u64)| Add(y, q), 10, 100, 1000, 10000), 10100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::Test { + private 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() { + if Eq(Test::foo(|(_: u64, y: u64, _: u64, q: u64): (u64, u64, u64, u64)| Add(y, q), 10, 100, 1000, 10000), 10100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor unused struct params check: +module 0x42::Test { + private 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() { + if Eq(Test::foo(|(_: u64, y: u64, _: u64, q: u64): (u64, u64, u64, u64)| Add(y, q), 10, 100, 1000, 10000), 10100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::Test { + private 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() { + if Eq(Test::foo(|(_: u64, y: u64, _: u64, q: u64): (u64, u64, u64, u64)| Add(y, q), 10, 100, 1000, 10000), 10100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor inlining: +module 0x42::Test { + private 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() { + if Eq(Test::foo(|(_: u64, y: u64, _: u64, q: u64): (u64, u64, u64, u64)| Add(y, q), 10, 100, 1000, 10000), 10100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::Test { + private 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() { + if Eq(Test::foo(|(_: u64, y: u64, _: u64, q: u64): (u64, u64, u64, u64)| Add(y, q), 10, 100, 1000, 10000), 10100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor acquires check: +module 0x42::Test { + private 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() { + if Eq(Test::foo(|(_: u64, y: u64, _: u64, q: u64): (u64, u64, u64, u64)| Add(y, q), 10, 100, 1000, 10000), 10100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor simplifier: +module 0x42::Test { + private 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() { + if Eq(Test::foo(|(_: u64, y: u64, _: u64, q: u64): (u64, u64, u64, u64)| Add(y, q), 10, 100, 1000, 10000), 10100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } +} // end 0x42::Test + + +// -- Model dump after env processor lambda-lifting: +module 0x42::Test { + private 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() { + if Eq(Test::foo(closure Test::test$lambda$1(), 10, 100, 1000, 10000), 10100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + private fun test$lambda$1(param$0: u64,y: u64,param$2: u64,q: u64): u64 { + { + let _: u64 = param$2; + { + let _: u64 = param$0; + Add(y, q) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor specification checker: +module 0x42::Test { + private 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() { + if Eq(Test::foo(closure Test::test$lambda$1(), 10, 100, 1000, 10000), 10100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + private fun test$lambda$1(param$0: u64,y: u64,param$2: u64,q: u64): u64 { + { + let _: u64 = param$2; + { + let _: u64 = param$0; + Add(y, q) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor specification rewriter: +module 0x42::Test { + private 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() { + if Eq(Test::foo(closure Test::test$lambda$1(), 10, 100, 1000, 10000), 10100) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + private fun test$lambda$1(param$0: u64,y: u64,param$2: u64,q: u64): u64 { + { + let _: u64 = param$2; + { + let _: u64 = param$0; + Add(y, q) + } + } + } +} // end 0x42::Test + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/bug_10991c.move:4:9 + │ +4 │ g(x, y, z, q) + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/bug_10991c.move:8:21 + │ +8 │ assert!(foo(|_, y, _, q| y + q, + │ ^^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991c.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991c.move new file mode 100644 index 00000000000000..f031fa6a6047ee --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991c.move @@ -0,0 +1,13 @@ +//# publish +module 0x42::Test { + 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(|_, y, _, q| y + q, + 10, 100, 1000, 10000) == 10100, 0); + } +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/cool_inlining_test.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/cool_inlining_test.exp new file mode 100644 index 00000000000000..cde09aa24c532b --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/cool_inlining_test.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: no function named `beans` found + ┌─ tests/lambda/inline-parity/cool_inlining_test.move:15:17 + │ +15 │ foo(| | beans()) + │ ^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/cool_inlining_test.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/cool_inlining_test.lambda.exp new file mode 100644 index 00000000000000..cde09aa24c532b --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/cool_inlining_test.lambda.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: no function named `beans` found + ┌─ tests/lambda/inline-parity/cool_inlining_test.move:15:17 + │ +15 │ foo(| | beans()) + │ ^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/cool_inlining_test.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/cool_inlining_test.move new file mode 100644 index 00000000000000..0a5fabeb9eb6a4 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/cool_inlining_test.move @@ -0,0 +1,17 @@ +module 0xc0ffee::cool { + public fun beans(): u64 { + 42 + } +} + +module 0xc0ffee::m { + fun foo(f: | | u64): u64 { + use 0xc0ffee::cool::beans; + beans(); // discharge unused use warning + f() + } + + public fun bar(): u64 { + foo(| | beans()) + } +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/dotdot_valid.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/dotdot_valid.exp new file mode 100644 index 00000000000000..68b554a2f03db1 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/dotdot_valid.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `test::lambda_param` has a function parameter: + ┌─ tests/lambda/inline-parity/dotdot_valid.move:175:9 + │ +175 │ fun lambda_param(f: |S2| bool): bool { + │ ^^^^^^^^^^^^ - Parameter `f` has function-valued type `|test::S2|bool`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/dotdot_valid.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/dotdot_valid.lambda.exp new file mode 100644 index 00000000000000..3056f26c17fb01 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/dotdot_valid.lambda.exp @@ -0,0 +1,4205 @@ +// -- Model dump before env processor pipeline: +module 0x42::test { + enum E1 { + A { + 0: u8, + 1: bool, + } + B { + 0: u8, + } + C { + x: u8, + y: test::S1, + } + } + struct S0 { + dummy_field: bool, + } + struct S1 { + 0: u8, + } + struct S2 { + 0: bool, + 1: test::S0, + } + struct S3 { + x: bool, + y: u8, + } + struct S4 { + x: T, + y: test::S3, + } + struct S5 { + 0: T, + 1: U, + } + struct S6 { + x: T, + y: U, + } + struct S7 { + 0: u8, + 1: u16, + 2: u32, + 3: u64, + } + private fun lambda_param(f: |test::S2|bool): bool { + { + let x: test::S2 = pack test::S2(true, pack test::S0(false)); + (f)(x) + } + } + private fun nested1(x: test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested1_ref(x: &test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested2(x: test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested2_ref(x: &test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested3(x: test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested3_ref(x: &test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested4(x: test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun nested4_ref(x: &test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun simple_0(x: test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_0_ref(x: &test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_1(x: test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_1_ref(x: &mut test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_2(x: test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_2_ref(x: &test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_3(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_3_ref(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_4(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x, y: _ } => { + x + } + } + + } + private fun simple_4_ref(x: &test::E1): &u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + } + + } + private fun simple_5(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: _, 1: y } => { + if y { + 1 + } else { + 0 + } + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x: _, y: test::S1{ 0: x } } => { + x + } + } + + } + private fun simple_6(x: &test::S7) { + { + let test::S7{ 0: _w, 1: _, 2: _, 3: _z } = x; + { + let test::S7{ 0: _w, 1: _x, 2: _y, 3: _z } = x; + Tuple() + } + } + } + private fun test_lambda_param(): bool { + test::lambda_param(|test::S2{ 0: x, 1: _ }| x) + } +} // end 0x42::test + + +// -- Model dump after env processor unused checks: +module 0x42::test { + enum E1 { + A { + 0: u8, + 1: bool, + } + B { + 0: u8, + } + C { + x: u8, + y: test::S1, + } + } + struct S0 { + dummy_field: bool, + } + struct S1 { + 0: u8, + } + struct S2 { + 0: bool, + 1: test::S0, + } + struct S3 { + x: bool, + y: u8, + } + struct S4 { + x: T, + y: test::S3, + } + struct S5 { + 0: T, + 1: U, + } + struct S6 { + x: T, + y: U, + } + struct S7 { + 0: u8, + 1: u16, + 2: u32, + 3: u64, + } + private fun lambda_param(f: |test::S2|bool): bool { + { + let x: test::S2 = pack test::S2(true, pack test::S0(false)); + (f)(x) + } + } + private fun nested1(x: test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested1_ref(x: &test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested2(x: test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested2_ref(x: &test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested3(x: test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested3_ref(x: &test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested4(x: test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun nested4_ref(x: &test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun simple_0(x: test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_0_ref(x: &test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_1(x: test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_1_ref(x: &mut test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_2(x: test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_2_ref(x: &test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_3(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_3_ref(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_4(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x, y: _ } => { + x + } + } + + } + private fun simple_4_ref(x: &test::E1): &u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + } + + } + private fun simple_5(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: _, 1: y } => { + if y { + 1 + } else { + 0 + } + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x: _, y: test::S1{ 0: x } } => { + x + } + } + + } + private fun simple_6(x: &test::S7) { + { + let test::S7{ 0: _w, 1: _, 2: _, 3: _z } = x; + { + let test::S7{ 0: _w, 1: _x, 2: _y, 3: _z } = x; + Tuple() + } + } + } + private fun test_lambda_param(): bool { + test::lambda_param(|test::S2{ 0: x, 1: _ }| x) + } +} // end 0x42::test + + +// -- Model dump after env processor type parameter check: +module 0x42::test { + enum E1 { + A { + 0: u8, + 1: bool, + } + B { + 0: u8, + } + C { + x: u8, + y: test::S1, + } + } + struct S0 { + dummy_field: bool, + } + struct S1 { + 0: u8, + } + struct S2 { + 0: bool, + 1: test::S0, + } + struct S3 { + x: bool, + y: u8, + } + struct S4 { + x: T, + y: test::S3, + } + struct S5 { + 0: T, + 1: U, + } + struct S6 { + x: T, + y: U, + } + struct S7 { + 0: u8, + 1: u16, + 2: u32, + 3: u64, + } + private fun lambda_param(f: |test::S2|bool): bool { + { + let x: test::S2 = pack test::S2(true, pack test::S0(false)); + (f)(x) + } + } + private fun nested1(x: test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested1_ref(x: &test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested2(x: test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested2_ref(x: &test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested3(x: test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested3_ref(x: &test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested4(x: test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun nested4_ref(x: &test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun simple_0(x: test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_0_ref(x: &test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_1(x: test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_1_ref(x: &mut test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_2(x: test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_2_ref(x: &test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_3(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_3_ref(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_4(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x, y: _ } => { + x + } + } + + } + private fun simple_4_ref(x: &test::E1): &u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + } + + } + private fun simple_5(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: _, 1: y } => { + if y { + 1 + } else { + 0 + } + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x: _, y: test::S1{ 0: x } } => { + x + } + } + + } + private fun simple_6(x: &test::S7) { + { + let test::S7{ 0: _w, 1: _, 2: _, 3: _z } = x; + { + let test::S7{ 0: _w, 1: _x, 2: _y, 3: _z } = x; + Tuple() + } + } + } + private fun test_lambda_param(): bool { + test::lambda_param(|test::S2{ 0: x, 1: _ }| x) + } +} // end 0x42::test + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::test { + enum E1 { + A { + 0: u8, + 1: bool, + } + B { + 0: u8, + } + C { + x: u8, + y: test::S1, + } + } + struct S0 { + dummy_field: bool, + } + struct S1 { + 0: u8, + } + struct S2 { + 0: bool, + 1: test::S0, + } + struct S3 { + x: bool, + y: u8, + } + struct S4 { + x: T, + y: test::S3, + } + struct S5 { + 0: T, + 1: U, + } + struct S6 { + x: T, + y: U, + } + struct S7 { + 0: u8, + 1: u16, + 2: u32, + 3: u64, + } + private fun lambda_param(f: |test::S2|bool): bool { + { + let x: test::S2 = pack test::S2(true, pack test::S0(false)); + (f)(x) + } + } + private fun nested1(x: test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested1_ref(x: &test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested2(x: test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested2_ref(x: &test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested3(x: test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested3_ref(x: &test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested4(x: test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun nested4_ref(x: &test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun simple_0(x: test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_0_ref(x: &test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_1(x: test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_1_ref(x: &mut test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_2(x: test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_2_ref(x: &test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_3(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_3_ref(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_4(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x, y: _ } => { + x + } + } + + } + private fun simple_4_ref(x: &test::E1): &u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + } + + } + private fun simple_5(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: _, 1: y } => { + if y { + 1 + } else { + 0 + } + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x: _, y: test::S1{ 0: x } } => { + x + } + } + + } + private fun simple_6(x: &test::S7) { + { + let test::S7{ 0: _w, 1: _, 2: _, 3: _z } = x; + { + let test::S7{ 0: _w, 1: _x, 2: _y, 3: _z } = x; + Tuple() + } + } + } + private fun test_lambda_param(): bool { + test::lambda_param(|test::S2{ 0: x, 1: _ }| x) + } +} // end 0x42::test + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::test { + enum E1 { + A { + 0: u8, + 1: bool, + } + B { + 0: u8, + } + C { + x: u8, + y: test::S1, + } + } + struct S0 { + dummy_field: bool, + } + struct S1 { + 0: u8, + } + struct S2 { + 0: bool, + 1: test::S0, + } + struct S3 { + x: bool, + y: u8, + } + struct S4 { + x: T, + y: test::S3, + } + struct S5 { + 0: T, + 1: U, + } + struct S6 { + x: T, + y: U, + } + struct S7 { + 0: u8, + 1: u16, + 2: u32, + 3: u64, + } + private fun lambda_param(f: |test::S2|bool): bool { + { + let x: test::S2 = pack test::S2(true, pack test::S0(false)); + (f)(x) + } + } + private fun nested1(x: test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested1_ref(x: &test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested2(x: test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested2_ref(x: &test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested3(x: test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested3_ref(x: &test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested4(x: test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun nested4_ref(x: &test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun simple_0(x: test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_0_ref(x: &test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_1(x: test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_1_ref(x: &mut test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_2(x: test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_2_ref(x: &test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_3(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_3_ref(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_4(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x, y: _ } => { + x + } + } + + } + private fun simple_4_ref(x: &test::E1): &u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + } + + } + private fun simple_5(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: _, 1: y } => { + if y { + 1 + } else { + 0 + } + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x: _, y: test::S1{ 0: x } } => { + x + } + } + + } + private fun simple_6(x: &test::S7) { + { + let test::S7{ 0: _w, 1: _, 2: _, 3: _z } = x; + { + let test::S7{ 0: _w, 1: _x, 2: _y, 3: _z } = x; + Tuple() + } + } + } + private fun test_lambda_param(): bool { + test::lambda_param(|test::S2{ 0: x, 1: _ }| x) + } +} // end 0x42::test + + +// -- Model dump after env processor unused struct params check: +module 0x42::test { + enum E1 { + A { + 0: u8, + 1: bool, + } + B { + 0: u8, + } + C { + x: u8, + y: test::S1, + } + } + struct S0 { + dummy_field: bool, + } + struct S1 { + 0: u8, + } + struct S2 { + 0: bool, + 1: test::S0, + } + struct S3 { + x: bool, + y: u8, + } + struct S4 { + x: T, + y: test::S3, + } + struct S5 { + 0: T, + 1: U, + } + struct S6 { + x: T, + y: U, + } + struct S7 { + 0: u8, + 1: u16, + 2: u32, + 3: u64, + } + private fun lambda_param(f: |test::S2|bool): bool { + { + let x: test::S2 = pack test::S2(true, pack test::S0(false)); + (f)(x) + } + } + private fun nested1(x: test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested1_ref(x: &test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested2(x: test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested2_ref(x: &test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested3(x: test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested3_ref(x: &test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested4(x: test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun nested4_ref(x: &test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun simple_0(x: test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_0_ref(x: &test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_1(x: test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_1_ref(x: &mut test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_2(x: test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_2_ref(x: &test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_3(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_3_ref(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_4(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x, y: _ } => { + x + } + } + + } + private fun simple_4_ref(x: &test::E1): &u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + } + + } + private fun simple_5(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: _, 1: y } => { + if y { + 1 + } else { + 0 + } + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x: _, y: test::S1{ 0: x } } => { + x + } + } + + } + private fun simple_6(x: &test::S7) { + { + let test::S7{ 0: _w, 1: _, 2: _, 3: _z } = x; + { + let test::S7{ 0: _w, 1: _x, 2: _y, 3: _z } = x; + Tuple() + } + } + } + private fun test_lambda_param(): bool { + test::lambda_param(|test::S2{ 0: x, 1: _ }| x) + } +} // end 0x42::test + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::test { + enum E1 { + A { + 0: u8, + 1: bool, + } + B { + 0: u8, + } + C { + x: u8, + y: test::S1, + } + } + struct S0 { + dummy_field: bool, + } + struct S1 { + 0: u8, + } + struct S2 { + 0: bool, + 1: test::S0, + } + struct S3 { + x: bool, + y: u8, + } + struct S4 { + x: T, + y: test::S3, + } + struct S5 { + 0: T, + 1: U, + } + struct S6 { + x: T, + y: U, + } + struct S7 { + 0: u8, + 1: u16, + 2: u32, + 3: u64, + } + private fun lambda_param(f: |test::S2|bool): bool { + { + let x: test::S2 = pack test::S2(true, pack test::S0(false)); + (f)(x) + } + } + private fun nested1(x: test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested1_ref(x: &test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested2(x: test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested2_ref(x: &test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested3(x: test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested3_ref(x: &test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested4(x: test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun nested4_ref(x: &test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun simple_0(x: test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_0_ref(x: &test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_1(x: test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_1_ref(x: &mut test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_2(x: test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_2_ref(x: &test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_3(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_3_ref(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_4(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x, y: _ } => { + x + } + } + + } + private fun simple_4_ref(x: &test::E1): &u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + } + + } + private fun simple_5(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: _, 1: y } => { + if y { + 1 + } else { + 0 + } + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x: _, y: test::S1{ 0: x } } => { + x + } + } + + } + private fun simple_6(x: &test::S7) { + { + let test::S7{ 0: _w, 1: _, 2: _, 3: _z } = x; + { + let test::S7{ 0: _w, 1: _x, 2: _y, 3: _z } = x; + Tuple() + } + } + } + private fun test_lambda_param(): bool { + test::lambda_param(|test::S2{ 0: x, 1: _ }| x) + } +} // end 0x42::test + + +// -- Model dump after env processor inlining: +module 0x42::test { + enum E1 { + A { + 0: u8, + 1: bool, + } + B { + 0: u8, + } + C { + x: u8, + y: test::S1, + } + } + struct S0 { + dummy_field: bool, + } + struct S1 { + 0: u8, + } + struct S2 { + 0: bool, + 1: test::S0, + } + struct S3 { + x: bool, + y: u8, + } + struct S4 { + x: T, + y: test::S3, + } + struct S5 { + 0: T, + 1: U, + } + struct S6 { + x: T, + y: U, + } + struct S7 { + 0: u8, + 1: u16, + 2: u32, + 3: u64, + } + private fun lambda_param(f: |test::S2|bool): bool { + { + let x: test::S2 = pack test::S2(true, pack test::S0(false)); + (f)(x) + } + } + private fun nested1(x: test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested1_ref(x: &test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested2(x: test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested2_ref(x: &test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested3(x: test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested3_ref(x: &test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested4(x: test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun nested4_ref(x: &test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun simple_0(x: test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_0_ref(x: &test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_1(x: test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_1_ref(x: &mut test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_2(x: test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_2_ref(x: &test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_3(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_3_ref(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_4(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x, y: _ } => { + x + } + } + + } + private fun simple_4_ref(x: &test::E1): &u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + } + + } + private fun simple_5(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: _, 1: y } => { + if y { + 1 + } else { + 0 + } + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x: _, y: test::S1{ 0: x } } => { + x + } + } + + } + private fun simple_6(x: &test::S7) { + { + let test::S7{ 0: _w, 1: _, 2: _, 3: _z } = x; + { + let test::S7{ 0: _w, 1: _x, 2: _y, 3: _z } = x; + Tuple() + } + } + } + private fun test_lambda_param(): bool { + test::lambda_param(|test::S2{ 0: x, 1: _ }| x) + } +} // end 0x42::test + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::test { + enum E1 { + A { + 0: u8, + 1: bool, + } + B { + 0: u8, + } + C { + x: u8, + y: test::S1, + } + } + struct S0 { + dummy_field: bool, + } + struct S1 { + 0: u8, + } + struct S2 { + 0: bool, + 1: test::S0, + } + struct S3 { + x: bool, + y: u8, + } + struct S4 { + x: T, + y: test::S3, + } + struct S5 { + 0: T, + 1: U, + } + struct S6 { + x: T, + y: U, + } + struct S7 { + 0: u8, + 1: u16, + 2: u32, + 3: u64, + } + private fun lambda_param(f: |test::S2|bool): bool { + { + let x: test::S2 = pack test::S2(true, pack test::S0(false)); + (f)(x) + } + } + private fun nested1(x: test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested1_ref(x: &test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested2(x: test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested2_ref(x: &test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested3(x: test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested3_ref(x: &test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested4(x: test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun nested4_ref(x: &test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun simple_0(x: test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_0_ref(x: &test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_1(x: test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_1_ref(x: &mut test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_2(x: test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_2_ref(x: &test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_3(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_3_ref(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_4(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x, y: _ } => { + x + } + } + + } + private fun simple_4_ref(x: &test::E1): &u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + } + + } + private fun simple_5(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: _, 1: y } => { + if y { + 1 + } else { + 0 + } + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x: _, y: test::S1{ 0: x } } => { + x + } + } + + } + private fun simple_6(x: &test::S7) { + { + let test::S7{ 0: _w, 1: _, 2: _, 3: _z } = x; + { + let test::S7{ 0: _w, 1: _x, 2: _y, 3: _z } = x; + Tuple() + } + } + } + private fun test_lambda_param(): bool { + test::lambda_param(|test::S2{ 0: x, 1: _ }| x) + } +} // end 0x42::test + + +// -- Model dump after env processor acquires check: +module 0x42::test { + enum E1 { + A { + 0: u8, + 1: bool, + } + B { + 0: u8, + } + C { + x: u8, + y: test::S1, + } + } + struct S0 { + dummy_field: bool, + } + struct S1 { + 0: u8, + } + struct S2 { + 0: bool, + 1: test::S0, + } + struct S3 { + x: bool, + y: u8, + } + struct S4 { + x: T, + y: test::S3, + } + struct S5 { + 0: T, + 1: U, + } + struct S6 { + x: T, + y: U, + } + struct S7 { + 0: u8, + 1: u16, + 2: u32, + 3: u64, + } + private fun lambda_param(f: |test::S2|bool): bool { + { + let x: test::S2 = pack test::S2(true, pack test::S0(false)); + (f)(x) + } + } + private fun nested1(x: test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested1_ref(x: &test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested2(x: test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested2_ref(x: &test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested3(x: test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested3_ref(x: &test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested4(x: test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun nested4_ref(x: &test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun simple_0(x: test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_0_ref(x: &test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_1(x: test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_1_ref(x: &mut test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_2(x: test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_2_ref(x: &test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_3(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_3_ref(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_4(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x, y: _ } => { + x + } + } + + } + private fun simple_4_ref(x: &test::E1): &u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + } + + } + private fun simple_5(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: _, 1: y } => { + if y { + 1 + } else { + 0 + } + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x: _, y: test::S1{ 0: x } } => { + x + } + } + + } + private fun simple_6(x: &test::S7) { + { + let test::S7{ 0: _w, 1: _, 2: _, 3: _z } = x; + { + let test::S7{ 0: _w, 1: _x, 2: _y, 3: _z } = x; + Tuple() + } + } + } + private fun test_lambda_param(): bool { + test::lambda_param(|test::S2{ 0: x, 1: _ }| x) + } +} // end 0x42::test + + +// -- Model dump after env processor simplifier: +module 0x42::test { + enum E1 { + A { + 0: u8, + 1: bool, + } + B { + 0: u8, + } + C { + x: u8, + y: test::S1, + } + } + struct S0 { + dummy_field: bool, + } + struct S1 { + 0: u8, + } + struct S2 { + 0: bool, + 1: test::S0, + } + struct S3 { + x: bool, + y: u8, + } + struct S4 { + x: T, + y: test::S3, + } + struct S5 { + 0: T, + 1: U, + } + struct S6 { + x: T, + y: U, + } + struct S7 { + 0: u8, + 1: u16, + 2: u32, + 3: u64, + } + private fun lambda_param(f: |test::S2|bool): bool { + { + let x: test::S2 = pack test::S2(true, pack test::S0(false)); + (f)(x) + } + } + private fun nested1(x: test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested1_ref(x: &test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested2(x: test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested2_ref(x: &test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested3(x: test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested3_ref(x: &test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested4(x: test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun nested4_ref(x: &test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun simple_0(x: test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_0_ref(x: &test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_1(x: test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_1_ref(x: &mut test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_2(x: test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_2_ref(x: &test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_3(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_3_ref(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_4(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x, y: _ } => { + x + } + } + + } + private fun simple_4_ref(x: &test::E1): &u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + } + + } + private fun simple_5(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: _, 1: y } => { + if y { + 1 + } else { + 0 + } + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x: _, y: test::S1{ 0: x } } => { + x + } + } + + } + private fun simple_6(x: &test::S7) { + { + let test::S7{ 0: _w, 1: _, 2: _, 3: _z } = x; + { + let test::S7{ 0: _w, 1: _x, 2: _y, 3: _z } = x; + Tuple() + } + } + } + private fun test_lambda_param(): bool { + test::lambda_param(|test::S2{ 0: x, 1: _ }| x) + } +} // end 0x42::test + + +// -- Model dump after env processor lambda-lifting: +module 0x42::test { + enum E1 { + A { + 0: u8, + 1: bool, + } + B { + 0: u8, + } + C { + x: u8, + y: test::S1, + } + } + struct S0 { + dummy_field: bool, + } + struct S1 { + 0: u8, + } + struct S2 { + 0: bool, + 1: test::S0, + } + struct S3 { + x: bool, + y: u8, + } + struct S4 { + x: T, + y: test::S3, + } + struct S5 { + 0: T, + 1: U, + } + struct S6 { + x: T, + y: U, + } + struct S7 { + 0: u8, + 1: u16, + 2: u32, + 3: u64, + } + private fun lambda_param(f: |test::S2|bool): bool { + { + let x: test::S2 = pack test::S2(true, pack test::S0(false)); + (f)(x) + } + } + private fun nested1(x: test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested1_ref(x: &test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested2(x: test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested2_ref(x: &test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested3(x: test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested3_ref(x: &test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested4(x: test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun nested4_ref(x: &test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun simple_0(x: test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_0_ref(x: &test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_1(x: test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_1_ref(x: &mut test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_2(x: test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_2_ref(x: &test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_3(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_3_ref(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_4(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x, y: _ } => { + x + } + } + + } + private fun simple_4_ref(x: &test::E1): &u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + } + + } + private fun simple_5(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: _, 1: y } => { + if y { + 1 + } else { + 0 + } + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x: _, y: test::S1{ 0: x } } => { + x + } + } + + } + private fun simple_6(x: &test::S7) { + { + let test::S7{ 0: _w, 1: _, 2: _, 3: _z } = x; + { + let test::S7{ 0: _w, 1: _x, 2: _y, 3: _z } = x; + Tuple() + } + } + } + private fun test_lambda_param(): bool { + test::lambda_param(closure test::test_lambda_param$lambda$1()) + } + private fun test_lambda_param$lambda$1(param$0: test::S2): bool { + { + let test::S2{ 0: x, 1: _ } = param$0; + x + } + } +} // end 0x42::test + + +// -- Model dump after env processor specification checker: +module 0x42::test { + enum E1 { + A { + 0: u8, + 1: bool, + } + B { + 0: u8, + } + C { + x: u8, + y: test::S1, + } + } + struct S0 { + dummy_field: bool, + } + struct S1 { + 0: u8, + } + struct S2 { + 0: bool, + 1: test::S0, + } + struct S3 { + x: bool, + y: u8, + } + struct S4 { + x: T, + y: test::S3, + } + struct S5 { + 0: T, + 1: U, + } + struct S6 { + x: T, + y: U, + } + struct S7 { + 0: u8, + 1: u16, + 2: u32, + 3: u64, + } + private fun lambda_param(f: |test::S2|bool): bool { + { + let x: test::S2 = pack test::S2(true, pack test::S0(false)); + (f)(x) + } + } + private fun nested1(x: test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested1_ref(x: &test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested2(x: test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested2_ref(x: &test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested3(x: test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested3_ref(x: &test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested4(x: test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun nested4_ref(x: &test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun simple_0(x: test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_0_ref(x: &test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_1(x: test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_1_ref(x: &mut test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_2(x: test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_2_ref(x: &test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_3(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_3_ref(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_4(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x, y: _ } => { + x + } + } + + } + private fun simple_4_ref(x: &test::E1): &u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + } + + } + private fun simple_5(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: _, 1: y } => { + if y { + 1 + } else { + 0 + } + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x: _, y: test::S1{ 0: x } } => { + x + } + } + + } + private fun simple_6(x: &test::S7) { + { + let test::S7{ 0: _w, 1: _, 2: _, 3: _z } = x; + { + let test::S7{ 0: _w, 1: _x, 2: _y, 3: _z } = x; + Tuple() + } + } + } + private fun test_lambda_param(): bool { + test::lambda_param(closure test::test_lambda_param$lambda$1()) + } + private fun test_lambda_param$lambda$1(param$0: test::S2): bool { + { + let test::S2{ 0: x, 1: _ } = param$0; + x + } + } +} // end 0x42::test + + +// -- Model dump after env processor specification rewriter: +module 0x42::test { + enum E1 { + A { + 0: u8, + 1: bool, + } + B { + 0: u8, + } + C { + x: u8, + y: test::S1, + } + } + struct S0 { + dummy_field: bool, + } + struct S1 { + 0: u8, + } + struct S2 { + 0: bool, + 1: test::S0, + } + struct S3 { + x: bool, + y: u8, + } + struct S4 { + x: T, + y: test::S3, + } + struct S5 { + 0: T, + 1: U, + } + struct S6 { + x: T, + y: U, + } + struct S7 { + 0: u8, + 1: u16, + 2: u32, + 3: u64, + } + private fun lambda_param(f: |test::S2|bool): bool { + { + let x: test::S2 = pack test::S2(true, pack test::S0(false)); + (f)(x) + } + } + private fun nested1(x: test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested1_ref(x: &test::S4) { + { + let test::S4{ x: _x, y: _ } = x; + { + let test::S4{ x: _, y: _y } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _x, y: _ } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + { + let test::S4{ x: _, y: test::S3{ x: _, y: _y } } = x; + { + let test::S4{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; + Tuple() + } + } + } + } + } + } + } + } + private fun nested2(x: test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested2_ref(x: &test::S5) { + { + let test::S5{ 0: _, 1: test::S1{ 0: _ } } = x; + Tuple() + } + } + private fun nested3(x: test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested3_ref(x: &test::S5>) { + { + let test::S5>{ 0: _, 1: test::S4{ x: _, y: _ } } = x; + Tuple() + } + } + private fun nested4(x: test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun nested4_ref(x: &test::S4) { + { + let test::S4{ x: test::S1{ 0: _ }, y: _ } = x; + Tuple() + } + } + private fun simple_0(x: test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_0_ref(x: &test::S0) { + { + let test::S0{ dummy_field: _ } = x; + Tuple() + } + } + private fun simple_1(x: test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_1_ref(x: &mut test::S1) { + { + let test::S1{ 0: _ } = x; + Tuple() + } + } + private fun simple_2(x: test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_2_ref(x: &test::S2) { + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _ } = x; + { + let test::S2{ 0: _, 1: _x } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _, 1: _ } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + { + let test::S2{ 0: _x, 1: _y } = x; + Tuple() + } + } + } + } + } + } + } + } + } + private fun simple_3(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_3_ref(x: test::S3) { + { + let test::S3{ x: _, y: _ } = x; + { + let test::S3{ x: _x, y: _ } = x; + { + let test::S3{ x: _, y: _y } = x; + Tuple() + } + } + } + } + private fun simple_4(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x, y: _ } => { + x + } + } + + } + private fun simple_4_ref(x: &test::E1): &u8 { + match (x) { + test::E1::A{ 0: x, 1: _ } => { + x + } + test::E1::B{ 0: x } => { + x + } + } + + } + private fun simple_5(x: test::E1): u8 { + match (x) { + test::E1::A{ 0: _, 1: y } => { + if y { + 1 + } else { + 0 + } + } + test::E1::B{ 0: x } => { + x + } + test::E1::C{ x: _, y: test::S1{ 0: x } } => { + x + } + } + + } + private fun simple_6(x: &test::S7) { + { + let test::S7{ 0: _w, 1: _, 2: _, 3: _z } = x; + { + let test::S7{ 0: _w, 1: _x, 2: _y, 3: _z } = x; + Tuple() + } + } + } + private fun test_lambda_param(): bool { + test::lambda_param(closure test::test_lambda_param$lambda$1()) + } + private fun test_lambda_param$lambda$1(param$0: test::S2): bool { + { + let test::S2{ 0: x, 1: _ } = param$0; + x + } + } +} // end 0x42::test + + + +Diagnostics: +error: match not exhaustive + ┌─ tests/lambda/inline-parity/dotdot_valid.move:142:16 + │ +142 │ match (x) { + │ ^ + │ + = missing `E1::C{..}` + +error: match not exhaustive + ┌─ tests/lambda/inline-parity/dotdot_valid.move:153:16 + │ +153 │ match (x) { + │ ^ + │ + = missing `E1::C{..}` + +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/dotdot_valid.move:177:9 + │ +177 │ f(x) + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/dotdot_valid.move:181:22 + │ +181 │ lambda_param(|S2(x, ..)| x) + │ ^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/dotdot_valid.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/dotdot_valid.move new file mode 100644 index 00000000000000..f5f20b6cee60c9 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/dotdot_valid.move @@ -0,0 +1,183 @@ +module 0x42::test { + struct S0() has copy; + + struct S1(u8) has copy, drop; + + struct S2(bool, S0) has copy; + + struct S3 has copy { + x: bool, + y: u8 + } + + struct S4 has copy { + x: T, + y: S3 + } + + struct S5(T, U); + + struct S6 { + x: T, + y: U + } + + struct S7(u8, u16, u32, u64); + + enum E1 has drop { + A(u8, bool), + B(u8), + C { x: u8, y: S1 }, + } + + fun simple_0(x: S0) { + let S0(..) = x; + } + + fun simple_0_ref(x: &S0) { + let S0(..) = x; + } + + fun simple_1(x: S1) { + let S1(..) = x; + } + + fun simple_1_ref(x: &mut S1) { + let S1(..) = x; + } + + fun simple_2(x: S2) { + let S2(..) = x; + let S2(_x, ..) = x; + let S2(.., _x) = x; + let S2(.., _) = x; + let S2(_, ..) = x; + let S2(_x, _y, ..) = x; + let S2(_x, .., _y) = x; + let S2(.., _x, _y) = x; + } + + fun simple_2_ref(x: &S2) { + let S2(..) = x; + let S2(_x, ..) = x; + let S2(.., _x) = x; + let S2(.., _) = x; + let S2(_, ..) = x; + let S2(_x, _y, ..) = x; + let S2(_x, .., _y) = x; + let S2(.., _x, _y) = x; + } + + fun simple_3(x: S3) { + let S3 { .. } = x; + let S3 { x: _x, .. } = x; + let S3 { y: _y, .. } = x; + } + + fun simple_3_ref(x: S3) { + let S3 { .. } = x; + let S3 { x: _x, .. } = x; + let S3 { y: _y, .. } = x; + } + + fun nested1(x: S4) { + let S4 { x: _x, .. } = x; + let S4 { y: _y, .. } = x; + let S4 { y: S3 { .. }, .. } = x; + let S4 { y: S3 { x: _x, .. }, .. } = x; + let S4 { y: S3 { x: _x1, .. }, x: _x2 } = x; + let S4 { y: S3 { y: _y, .. }, .. } = x; + let S4 { y: S3 { x: _x1, .. }, x: _x2 } = x; + } + + fun nested1_ref(x: &S4) { + let S4 { x: _x, .. } = x; + let S4 { y: _y, .. } = x; + let S4 { y: S3 { .. }, .. } = x; + let S4 { y: S3 { x: _x, .. }, .. } = x; + let S4 { y: S3 { x: _x1, .. }, x: _x2 } = x; + let S4 { y: S3 { y: _y, .. }, .. } = x; + let S4 { y: S3 { x: _x1, .. }, x: _x2 } = x; + } + + fun nested2(x: S5) { + let S5(.., S1(..)) = x; + } + + fun nested2_ref(x: &S5) { + let S5(.., S1(..)) = x; + } + + fun nested3(x: S5>) { + let S5(.., S4 { .. }) = x; + } + + fun nested3_ref(x: &S5>) { + let S5(.., S4 { .. }) = x; + } + + fun nested4(x: S4) { + let S4 { x: S1(..), .. } = x; + } + + fun nested4_ref(x: &S4) { + let S4 { x: S1(..), .. } = x; + } + + fun simple_4(x: E1): u8 { + match (x) { + E1::A(x, ..) => { + x + }, + E1::B(x) => { + x + }, + E1::C { x, .. } => { + x + } + } + } + + fun simple_4_ref(x: &E1): &u8 { + match (x) { + E1::A(x, ..) => { + x + } + E1::B(x) => { + x + } + } + } + + fun simple_5(x: E1): u8 { + match (x) { + E1::A(.., y) => { + if (y) { + 1 + } else { + 0 + } + }, + E1::B(x) => { + x + }, + E1::C { y: S1(x), .. } => { + x + } + } + } + + fun simple_6(x: &S7) { + let S7(_w, .., _z) = x; + let S7(_w, _x, .., _y, _z) = x; + } + + fun lambda_param(f: |S2| bool): bool { + let x = S2(true, S0()); + f(x) + } + + fun test_lambda_param(): bool { + lambda_param(|S2(x, ..)| x) + } +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eq_inline.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eq_inline.exp new file mode 100644 index 00000000000000..e3334671a36aa5 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eq_inline.exp @@ -0,0 +1,13 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `m::foo` has a function parameter: + ┌─ tests/lambda/inline-parity/eq_inline.move:3:9 + │ +3 │ fun foo(f: |&u64|) { + │ ^^^ - Parameter `f` has function-valued type `|&u64|`. + +warning: Unused parameter `f`. Consider removing or prefixing with an underscore: `_f` + ┌─ tests/lambda/inline-parity/eq_inline.move:3:13 + │ +3 │ fun foo(f: |&u64|) { + │ ^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eq_inline.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eq_inline.lambda.exp new file mode 100644 index 00000000000000..7fc83645200413 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eq_inline.lambda.exp @@ -0,0 +1,209 @@ +// -- Model dump before env processor pipeline: +module 0x42::m { + private fun foo(f: |&u64|) { + Tuple() + } + private fun g() { + m::foo(|v: &u64| Eq(v, Borrow(Immutable)(1)); + Tuple()); + Tuple() + } +} // end 0x42::m + + +// -- Model dump after env processor unused checks: +module 0x42::m { + private fun foo(f: |&u64|) { + Tuple() + } + private fun g() { + m::foo(|v: &u64| Eq(v, Borrow(Immutable)(1)); + Tuple()); + Tuple() + } +} // end 0x42::m + + +// -- Model dump after env processor type parameter check: +module 0x42::m { + private fun foo(f: |&u64|) { + Tuple() + } + private fun g() { + m::foo(|v: &u64| Eq(v, Borrow(Immutable)(1)); + Tuple()); + Tuple() + } +} // end 0x42::m + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::m { + private fun foo(f: |&u64|) { + Tuple() + } + private fun g() { + m::foo(|v: &u64| Eq(v, Borrow(Immutable)(1)); + Tuple()); + Tuple() + } +} // end 0x42::m + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::m { + private fun foo(f: |&u64|) { + Tuple() + } + private fun g() { + m::foo(|v: &u64| Eq(v, Borrow(Immutable)(1)); + Tuple()); + Tuple() + } +} // end 0x42::m + + +// -- Model dump after env processor unused struct params check: +module 0x42::m { + private fun foo(f: |&u64|) { + Tuple() + } + private fun g() { + m::foo(|v: &u64| Eq(v, Borrow(Immutable)(1)); + Tuple()); + Tuple() + } +} // end 0x42::m + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::m { + private fun foo(f: |&u64|) { + Tuple() + } + private fun g() { + m::foo(|v: &u64| Eq(v, Borrow(Immutable)(1)); + Tuple()); + Tuple() + } +} // end 0x42::m + + +// -- Model dump after env processor inlining: +module 0x42::m { + private fun foo(f: |&u64|) { + Tuple() + } + private fun g() { + m::foo(|v: &u64| Eq(v, Borrow(Immutable)(1)); + Tuple()); + Tuple() + } +} // end 0x42::m + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::m { + private fun foo(f: |&u64|) { + Tuple() + } + private fun g() { + m::foo(|v: &u64| Eq(v, Borrow(Immutable)(1)); + Tuple()); + Tuple() + } +} // end 0x42::m + + +// -- Model dump after env processor acquires check: +module 0x42::m { + private fun foo(f: |&u64|) { + Tuple() + } + private fun g() { + m::foo(|v: &u64| Eq(v, Borrow(Immutable)(1)); + Tuple()); + Tuple() + } +} // end 0x42::m + + +// -- Model dump after env processor simplifier: +module 0x42::m { + private fun foo(f: |&u64|) { + Tuple() + } + private fun g() { + m::foo(|v: &u64| Eq(v, Borrow(Immutable)(1)); + Tuple()); + Tuple() + } +} // end 0x42::m + + +// -- Model dump after env processor lambda-lifting: +module 0x42::m { + private fun foo(f: |&u64|) { + Tuple() + } + private fun g() { + m::foo(closure m::g$lambda$1()); + Tuple() + } + private fun g$lambda$1(v: &u64) { + Eq(v, Borrow(Immutable)(1)); + Tuple() + } +} // end 0x42::m + + +// -- Model dump after env processor specification checker: +module 0x42::m { + private fun foo(f: |&u64|) { + Tuple() + } + private fun g() { + m::foo(closure m::g$lambda$1()); + Tuple() + } + private fun g$lambda$1(v: &u64) { + Eq(v, Borrow(Immutable)(1)); + Tuple() + } +} // end 0x42::m + + +// -- Model dump after env processor specification rewriter: +module 0x42::m { + private fun foo(f: |&u64|) { + Tuple() + } + private fun g() { + m::foo(closure m::g$lambda$1()); + Tuple() + } + private fun g$lambda$1(v: &u64) { + Eq(v, Borrow(Immutable)(1)); + Tuple() + } +} // end 0x42::m + + + +Diagnostics: +warning: Unused parameter `f`. Consider removing or prefixing with an underscore: `_f` + ┌─ tests/lambda/inline-parity/eq_inline.move:3:13 + │ +3 │ fun foo(f: |&u64|) { + │ ^ + + +Diagnostics: +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/eq_inline.move:7:13 + │ +7 │ foo(|v| { + │ ╭─────────────^ +8 │ │ v == &1; +9 │ │ }); + │ ╰─────────^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eq_inline.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eq_inline.move new file mode 100644 index 00000000000000..1b235a795ff1d5 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eq_inline.move @@ -0,0 +1,13 @@ +module 0x42::m { + + fun foo(f: |&u64|) { + } + + fun g() { + foo(|v| { + v == &1; + }); + } + + +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eval_ignored_param.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eval_ignored_param.exp new file mode 100644 index 00000000000000..54a3ea61dd0448 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eval_ignored_param.exp @@ -0,0 +1,9 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `Test::foo` has function parameters: + ┌─ tests/lambda/inline-parity/eval_ignored_param.move:3:9 + │ +3 │ fun foo(f:|u64, u64, u64| u64, g: |u64, u64, u64| u64, x: u64, _: u64, y: u64, z: u64): u64 { + │ ^^^ - - Parameter `g` has function-valued type `|(u64, u64, u64)|u64`. + │ │ + │ Parameter `f` has function-valued type `|(u64, u64, u64)|u64`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eval_ignored_param.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eval_ignored_param.lambda.exp new file mode 100644 index 00000000000000..2bbc4c4bfd6038 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eval_ignored_param.lambda.exp @@ -0,0 +1,504 @@ +// -- Model dump before env processor pipeline: +module 0x42::Test { + private fun foo(f: |(u64, u64, u64)|u64,g: |(u64, u64, u64)|u64,x: u64,_: u64,y: u64,z: u64): u64 { + { + let r1: u64 = (f)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + { + let r2: u64 = (g)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + Add(Add(Add(Add(r1, r2), Mul(3, x)), Mul(5, y)), Mul(7, z)) + } + } + } + public fun test() { + { + let r: u64 = Test::foo(|(x: u64, _: u64, z: u64): (u64, u64, u64)| Mul(x, z), |(_: u64, y: u64, _: u64): (u64, u64, u64)| y, 1, 10, 100, 1000); + if Eq(r, 9637) { + Tuple() + } else { + Abort(r) + }; + Tuple() + } + } +} // end 0x42::Test + + +// -- Model dump after env processor unused checks: +module 0x42::Test { + private fun foo(f: |(u64, u64, u64)|u64,g: |(u64, u64, u64)|u64,x: u64,_: u64,y: u64,z: u64): u64 { + { + let r1: u64 = (f)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + { + let r2: u64 = (g)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + Add(Add(Add(Add(r1, r2), Mul(3, x)), Mul(5, y)), Mul(7, z)) + } + } + } + public fun test() { + { + let r: u64 = Test::foo(|(x: u64, _: u64, z: u64): (u64, u64, u64)| Mul(x, z), |(_: u64, y: u64, _: u64): (u64, u64, u64)| y, 1, 10, 100, 1000); + if Eq(r, 9637) { + Tuple() + } else { + Abort(r) + }; + Tuple() + } + } +} // end 0x42::Test + + +// -- Model dump after env processor type parameter check: +module 0x42::Test { + private fun foo(f: |(u64, u64, u64)|u64,g: |(u64, u64, u64)|u64,x: u64,_: u64,y: u64,z: u64): u64 { + { + let r1: u64 = (f)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + { + let r2: u64 = (g)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + Add(Add(Add(Add(r1, r2), Mul(3, x)), Mul(5, y)), Mul(7, z)) + } + } + } + public fun test() { + { + let r: u64 = Test::foo(|(x: u64, _: u64, z: u64): (u64, u64, u64)| Mul(x, z), |(_: u64, y: u64, _: u64): (u64, u64, u64)| y, 1, 10, 100, 1000); + if Eq(r, 9637) { + Tuple() + } else { + Abort(r) + }; + Tuple() + } + } +} // end 0x42::Test + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::Test { + private fun foo(f: |(u64, u64, u64)|u64,g: |(u64, u64, u64)|u64,x: u64,_: u64,y: u64,z: u64): u64 { + { + let r1: u64 = (f)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + { + let r2: u64 = (g)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + Add(Add(Add(Add(r1, r2), Mul(3, x)), Mul(5, y)), Mul(7, z)) + } + } + } + public fun test() { + { + let r: u64 = Test::foo(|(x: u64, _: u64, z: u64): (u64, u64, u64)| Mul(x, z), |(_: u64, y: u64, _: u64): (u64, u64, u64)| y, 1, 10, 100, 1000); + if Eq(r, 9637) { + Tuple() + } else { + Abort(r) + }; + Tuple() + } + } +} // end 0x42::Test + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::Test { + private fun foo(f: |(u64, u64, u64)|u64,g: |(u64, u64, u64)|u64,x: u64,_: u64,y: u64,z: u64): u64 { + { + let r1: u64 = (f)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + { + let r2: u64 = (g)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + Add(Add(Add(Add(r1, r2), Mul(3, x)), Mul(5, y)), Mul(7, z)) + } + } + } + public fun test() { + { + let r: u64 = Test::foo(|(x: u64, _: u64, z: u64): (u64, u64, u64)| Mul(x, z), |(_: u64, y: u64, _: u64): (u64, u64, u64)| y, 1, 10, 100, 1000); + if Eq(r, 9637) { + Tuple() + } else { + Abort(r) + }; + Tuple() + } + } +} // end 0x42::Test + + +// -- Model dump after env processor unused struct params check: +module 0x42::Test { + private fun foo(f: |(u64, u64, u64)|u64,g: |(u64, u64, u64)|u64,x: u64,_: u64,y: u64,z: u64): u64 { + { + let r1: u64 = (f)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + { + let r2: u64 = (g)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + Add(Add(Add(Add(r1, r2), Mul(3, x)), Mul(5, y)), Mul(7, z)) + } + } + } + public fun test() { + { + let r: u64 = Test::foo(|(x: u64, _: u64, z: u64): (u64, u64, u64)| Mul(x, z), |(_: u64, y: u64, _: u64): (u64, u64, u64)| y, 1, 10, 100, 1000); + if Eq(r, 9637) { + Tuple() + } else { + Abort(r) + }; + Tuple() + } + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::Test { + private fun foo(f: |(u64, u64, u64)|u64,g: |(u64, u64, u64)|u64,x: u64,_: u64,y: u64,z: u64): u64 { + { + let r1: u64 = (f)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + { + let r2: u64 = (g)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + Add(Add(Add(Add(r1, r2), Mul(3, x)), Mul(5, y)), Mul(7, z)) + } + } + } + public fun test() { + { + let r: u64 = Test::foo(|(x: u64, _: u64, z: u64): (u64, u64, u64)| Mul(x, z), |(_: u64, y: u64, _: u64): (u64, u64, u64)| y, 1, 10, 100, 1000); + if Eq(r, 9637) { + Tuple() + } else { + Abort(r) + }; + Tuple() + } + } +} // end 0x42::Test + + +// -- Model dump after env processor inlining: +module 0x42::Test { + private fun foo(f: |(u64, u64, u64)|u64,g: |(u64, u64, u64)|u64,x: u64,_: u64,y: u64,z: u64): u64 { + { + let r1: u64 = (f)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + { + let r2: u64 = (g)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + Add(Add(Add(Add(r1, r2), Mul(3, x)), Mul(5, y)), Mul(7, z)) + } + } + } + public fun test() { + { + let r: u64 = Test::foo(|(x: u64, _: u64, z: u64): (u64, u64, u64)| Mul(x, z), |(_: u64, y: u64, _: u64): (u64, u64, u64)| y, 1, 10, 100, 1000); + if Eq(r, 9637) { + Tuple() + } else { + Abort(r) + }; + Tuple() + } + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::Test { + private fun foo(f: |(u64, u64, u64)|u64,g: |(u64, u64, u64)|u64,x: u64,_: u64,y: u64,z: u64): u64 { + { + let r1: u64 = (f)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + { + let r2: u64 = (g)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + Add(Add(Add(Add(r1, r2), Mul(3, x)), Mul(5, y)), Mul(7, z)) + } + } + } + public fun test() { + { + let r: u64 = Test::foo(|(x: u64, _: u64, z: u64): (u64, u64, u64)| Mul(x, z), |(_: u64, y: u64, _: u64): (u64, u64, u64)| y, 1, 10, 100, 1000); + if Eq(r, 9637) { + Tuple() + } else { + Abort(r) + }; + Tuple() + } + } +} // end 0x42::Test + + +// -- Model dump after env processor acquires check: +module 0x42::Test { + private fun foo(f: |(u64, u64, u64)|u64,g: |(u64, u64, u64)|u64,x: u64,_: u64,y: u64,z: u64): u64 { + { + let r1: u64 = (f)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + { + let r2: u64 = (g)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + Add(Add(Add(Add(r1, r2), Mul(3, x)), Mul(5, y)), Mul(7, z)) + } + } + } + public fun test() { + { + let r: u64 = Test::foo(|(x: u64, _: u64, z: u64): (u64, u64, u64)| Mul(x, z), |(_: u64, y: u64, _: u64): (u64, u64, u64)| y, 1, 10, 100, 1000); + if Eq(r, 9637) { + Tuple() + } else { + Abort(r) + }; + Tuple() + } + } +} // end 0x42::Test + + +// -- Model dump after env processor simplifier: +module 0x42::Test { + private fun foo(f: |(u64, u64, u64)|u64,g: |(u64, u64, u64)|u64,x: u64,_: u64,y: u64,z: u64): u64 { + { + let r1: u64 = (f)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + { + let r2: u64 = (g)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + Add(Add(Add(Add(r1, r2), Mul(3, x)), Mul(5, y)), Mul(7, z)) + } + } + } + public fun test() { + { + let r: u64 = Test::foo(|(x: u64, _: u64, z: u64): (u64, u64, u64)| Mul(x, z), |(_: u64, y: u64, _: u64): (u64, u64, u64)| y, 1, 10, 100, 1000); + if Eq(r, 9637) { + Tuple() + } else { + Abort(r) + }; + Tuple() + } + } +} // end 0x42::Test + + +// -- Model dump after env processor lambda-lifting: +module 0x42::Test { + private fun foo(f: |(u64, u64, u64)|u64,g: |(u64, u64, u64)|u64,x: u64,_: u64,y: u64,z: u64): u64 { + { + let r1: u64 = (f)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + { + let r2: u64 = (g)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + Add(Add(Add(Add(r1, r2), Mul(3, x)), Mul(5, y)), Mul(7, z)) + } + } + } + public fun test() { + { + let r: u64 = Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 1, 10, 100, 1000); + if Eq(r, 9637) { + Tuple() + } else { + Abort(r) + }; + Tuple() + } + } + private fun test$lambda$1(x: u64,param$1: u64,z: u64): u64 { + { + let _: u64 = param$1; + Mul(x, z) + } + } + private fun test$lambda$2(param$0: u64,y: u64,param$2: u64): u64 { + { + let _: u64 = param$2; + { + let _: u64 = param$0; + y + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor specification checker: +module 0x42::Test { + private fun foo(f: |(u64, u64, u64)|u64,g: |(u64, u64, u64)|u64,x: u64,_: u64,y: u64,z: u64): u64 { + { + let r1: u64 = (f)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + { + let r2: u64 = (g)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + Add(Add(Add(Add(r1, r2), Mul(3, x)), Mul(5, y)), Mul(7, z)) + } + } + } + public fun test() { + { + let r: u64 = Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 1, 10, 100, 1000); + if Eq(r, 9637) { + Tuple() + } else { + Abort(r) + }; + Tuple() + } + } + private fun test$lambda$1(x: u64,param$1: u64,z: u64): u64 { + { + let _: u64 = param$1; + Mul(x, z) + } + } + private fun test$lambda$2(param$0: u64,y: u64,param$2: u64): u64 { + { + let _: u64 = param$2; + { + let _: u64 = param$0; + y + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor specification rewriter: +module 0x42::Test { + private fun foo(f: |(u64, u64, u64)|u64,g: |(u64, u64, u64)|u64,x: u64,_: u64,y: u64,z: u64): u64 { + { + let r1: u64 = (f)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + { + let r2: u64 = (g)(x: u64 = Add(x, 1); + x, y: u64 = Add(y, 1); + y, z: u64 = Add(z, 1); + z); + Add(Add(Add(Add(r1, r2), Mul(3, x)), Mul(5, y)), Mul(7, z)) + } + } + } + public fun test() { + { + let r: u64 = Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 1, 10, 100, 1000); + if Eq(r, 9637) { + Tuple() + } else { + Abort(r) + }; + Tuple() + } + } + private fun test$lambda$1(x: u64,param$1: u64,z: u64): u64 { + { + let _: u64 = param$1; + Mul(x, z) + } + } + private fun test$lambda$2(param$0: u64,y: u64,param$2: u64): u64 { + { + let _: u64 = param$2; + { + let _: u64 = param$0; + y + } + } + } +} // end 0x42::Test + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/eval_ignored_param.move:4:11 + │ +4 │ let r1 = f({x = x + 1; x}, {y = y + 1; y}, {z = z + 1; z}); + │ ^ + +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/eval_ignored_param.move:5:11 + │ +5 │ let r2 = g({x = x + 1; x}, {y = y + 1; y}, {z = z + 1 ; z}); + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/eval_ignored_param.move:10:14 + │ +10 │ let r = foo(|x, _, z| x*z, |_, y, _| y, 1, 10, 100, 1000); + │ ^^^^^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/eval_ignored_param.move:10:29 + │ +10 │ let r = foo(|x, _, z| x*z, |_, y, _| y, 1, 10, 100, 1000); + │ ^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eval_ignored_param.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eval_ignored_param.move new file mode 100644 index 00000000000000..92414e6a3ebc7f --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eval_ignored_param.move @@ -0,0 +1,15 @@ +//# publish +module 0x42::Test { + 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, _, z| x*z, |_, y, _| y, 1, 10, 100, 1000); + assert!(r == 9637, r); + } +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generic_calls.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generic_calls.exp new file mode 100644 index 00000000000000..e918c23234d633 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generic_calls.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `m::inlined` has a function parameter: + ┌─ tests/lambda/inline-parity/generic_calls.move:35:9 + │ +35 │ fun inlined(f: |S|S, s: S) { + │ ^^^^^^^ - Parameter `f` has function-valued type `|m::S|m::S`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generic_calls.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generic_calls.lambda.exp new file mode 100644 index 00000000000000..f01e29cb6cb81f --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generic_calls.lambda.exp @@ -0,0 +1,610 @@ +// -- Model dump before env processor pipeline: +module 0x42::m { + struct S { + x: T, + } + private fun id(self: m::S<#0>): m::S<#0> { + self + } + private 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) { + m::inlined(|s: m::S| m::id(s), s) + } +} // end 0x42::m + + +// -- Model dump after env processor unused checks: +module 0x42::m { + struct S { + x: T, + } + private fun id(self: m::S<#0>): m::S<#0> { + self + } + private 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) { + m::inlined(|s: m::S| m::id(s), s) + } +} // end 0x42::m + + +// -- Model dump after env processor type parameter check: +module 0x42::m { + struct S { + x: T, + } + private fun id(self: m::S<#0>): m::S<#0> { + self + } + private 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) { + m::inlined(|s: m::S| m::id(s), s) + } +} // end 0x42::m + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::m { + struct S { + x: T, + } + private fun id(self: m::S<#0>): m::S<#0> { + self + } + private 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) { + m::inlined(|s: m::S| m::id(s), s) + } +} // end 0x42::m + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::m { + struct S { + x: T, + } + private fun id(self: m::S<#0>): m::S<#0> { + self + } + private 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) { + m::inlined(|s: m::S| m::id(s), s) + } +} // end 0x42::m + + +// -- Model dump after env processor unused struct params check: +module 0x42::m { + struct S { + x: T, + } + private fun id(self: m::S<#0>): m::S<#0> { + self + } + private 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) { + m::inlined(|s: m::S| m::id(s), s) + } +} // end 0x42::m + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::m { + struct S { + x: T, + } + private fun id(self: m::S<#0>): m::S<#0> { + self + } + private 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) { + m::inlined(|s: m::S| m::id(s), s) + } +} // end 0x42::m + + +// -- Model dump after env processor inlining: +module 0x42::m { + struct S { + x: T, + } + private fun id(self: m::S<#0>): m::S<#0> { + self + } + private 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) { + m::inlined(|s: m::S| m::id(s), s) + } +} // end 0x42::m + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::m { + struct S { + x: T, + } + private fun id(self: m::S<#0>): m::S<#0> { + self + } + private 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) { + m::inlined(|s: m::S| m::id(s), s) + } +} // end 0x42::m + + +// -- Model dump after env processor acquires check: +module 0x42::m { + struct S { + x: T, + } + private fun id(self: m::S<#0>): m::S<#0> { + self + } + private 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) { + m::inlined(|s: m::S| m::id(s), s) + } +} // end 0x42::m + + +// -- Model dump after env processor simplifier: +module 0x42::m { + struct S { + x: T, + } + private fun id(self: m::S<#0>): m::S<#0> { + self + } + private 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) { + m::inlined(|s: m::S| m::id(s), s) + } +} // end 0x42::m + + +// -- Model dump after env processor lambda-lifting: +module 0x42::m { + struct S { + x: T, + } + private fun id(self: m::S<#0>): m::S<#0> { + self + } + private 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) { + m::inlined(closure m::test_receiver_inference$lambda$1(), s) + } + private fun test_receiver_inference$lambda$1(s: m::S): m::S { + m::id(s) + } +} // end 0x42::m + + +// -- Model dump after env processor specification checker: +module 0x42::m { + struct S { + x: T, + } + private fun id(self: m::S<#0>): m::S<#0> { + self + } + private 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) { + m::inlined(closure m::test_receiver_inference$lambda$1(), s) + } + private fun test_receiver_inference$lambda$1(s: m::S): m::S { + m::id(s) + } +} // end 0x42::m + + +// -- Model dump after env processor specification rewriter: +module 0x42::m { + struct S { + x: T, + } + private fun id(self: m::S<#0>): m::S<#0> { + self + } + private 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) { + m::inlined(closure m::test_receiver_inference$lambda$1(), s) + } + private fun test_receiver_inference$lambda$1(s: m::S): m::S { + m::id(s) + } +} // end 0x42::m + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/generic_calls.move:36:9 + │ +36 │ f(s); + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/generic_calls.move:47:17 + │ +47 │ inlined(|s| s.id(), s) + │ ^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generic_calls.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generic_calls.move new file mode 100644 index 00000000000000..ca586a2948e9ef --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generic_calls.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 + + 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.id(), s) + } +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generics.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generics.exp new file mode 100644 index 00000000000000..2e6790e9aa50e9 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generics.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `Test::foreach` has a function parameter: + ┌─ tests/lambda/inline-parity/generics.move:5:16 + │ +5 │ public fun foreach(v: &vector, action: |&X|) { + │ ^^^^^^^ ------ Parameter `action` has function-valued type `|&X|`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generics.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generics.lambda.exp new file mode 100644 index 00000000000000..6b84d94d83a583 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generics.lambda.exp @@ -0,0 +1,334 @@ +// -- Model dump before env processor pipeline: +module 0x42::Test { + use std::vector; + public 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 fun test(): u64 { + { + let v: vector = Vector(1, 2, 3); + { + let sum: u64 = 0; + Test::foreach(Borrow(Immutable)(v), |e: &u64| sum: u64 = Add(sum, Deref(e))); + sum + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor unused checks: +module 0x42::Test { + use std::vector; + public 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 fun test(): u64 { + { + let v: vector = Vector(1, 2, 3); + { + let sum: u64 = 0; + Test::foreach(Borrow(Immutable)(v), |e: &u64| sum: u64 = Add(sum, Deref(e))); + sum + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor type parameter check: +module 0x42::Test { + use std::vector; + public 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 fun test(): u64 { + { + let v: vector = Vector(1, 2, 3); + { + let sum: u64 = 0; + Test::foreach(Borrow(Immutable)(v), |e: &u64| sum: u64 = Add(sum, Deref(e))); + sum + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::Test { + use std::vector; + public 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 fun test(): u64 { + { + let v: vector = Vector(1, 2, 3); + { + let sum: u64 = 0; + Test::foreach(Borrow(Immutable)(v), |e: &u64| sum: u64 = Add(sum, Deref(e))); + sum + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::Test { + use std::vector; + public 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 fun test(): u64 { + { + let v: vector = Vector(1, 2, 3); + { + let sum: u64 = 0; + Test::foreach(Borrow(Immutable)(v), |e: &u64| sum: u64 = Add(sum, Deref(e))); + sum + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor unused struct params check: +module 0x42::Test { + use std::vector; + public 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 fun test(): u64 { + { + let v: vector = Vector(1, 2, 3); + { + let sum: u64 = 0; + Test::foreach(Borrow(Immutable)(v), |e: &u64| sum: u64 = Add(sum, Deref(e))); + sum + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::Test { + use std::vector; + public 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 fun test(): u64 { + { + let v: vector = Vector(1, 2, 3); + { + let sum: u64 = 0; + Test::foreach(Borrow(Immutable)(v), |e: &u64| sum: u64 = Add(sum, Deref(e))); + sum + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor inlining: +module 0x42::Test { + use std::vector; + public 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 fun test(): u64 { + { + let v: vector = Vector(1, 2, 3); + { + let sum: u64 = 0; + Test::foreach(Borrow(Immutable)(v), |e: &u64| sum: u64 = Add(sum, Deref(e))); + sum + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::Test { + use std::vector; + public 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 fun test(): u64 { + { + let v: vector = Vector(1, 2, 3); + { + let sum: u64 = 0; + Test::foreach(Borrow(Immutable)(v), |e: &u64| sum: u64 = Add(sum, Deref(e))); + sum + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor acquires check: +module 0x42::Test { + use std::vector; + public 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 fun test(): u64 { + { + let v: vector = Vector(1, 2, 3); + { + let sum: u64 = 0; + Test::foreach(Borrow(Immutable)(v), |e: &u64| sum: u64 = Add(sum, Deref(e))); + sum + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor simplifier: +module 0x42::Test { + use std::vector; + public 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 fun test(): u64 { + { + let sum: u64 = 0; + Test::foreach(Borrow(Immutable)([Number(1), Number(2), Number(3)]), |e: &u64| sum: u64 = Add(sum, Deref(e))); + sum + } + } +} // end 0x42::Test + + + +Diagnostics: +error: captured variable `sum` cannot be modified inside of a lambda + ┌─ tests/lambda/inline-parity/generics.move:16:30 + │ +16 │ foreach(&v, |e| sum = sum + *e); + │ ^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generics.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generics.move new file mode 100644 index 00000000000000..c9eb19337cb43b --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generics.move @@ -0,0 +1,22 @@ +//# publish +module 0x42::Test { + use std::vector; + + public 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| sum = sum + *e); + sum + } + +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inline_fun_in_spec.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inline_fun_in_spec.exp new file mode 100644 index 00000000000000..b7b47a45a6628e --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inline_fun_in_spec.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `m::exec` has a function parameter: + ┌─ tests/lambda/inline-parity/inline_fun_in_spec.move:3:9 + │ +3 │ fun exec(f: |T|R, x: T): R { + │ ^^^^ - Parameter `f` has function-valued type `|T|R`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inline_fun_in_spec.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inline_fun_in_spec.lambda.exp new file mode 100644 index 00000000000000..aaab208a76c33b --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inline_fun_in_spec.lambda.exp @@ -0,0 +1,645 @@ +// -- Model dump before env processor pipeline: +module 0x42::m { + spec { + invariant forall a: address: TypeDomain
(): Implies(exists(a), m::exec(|a: address| Lt(select m::S.f(m::get(a)), 10), a)); + } + + struct S { + f: u64, + } + spec { + invariant m::exec(|x: num| Gt(x, 0), select m::S.f()); + } + + private 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 m::exec(|y: num| Gt(y, 0), $t0); + } + ; + Add(x, 1) + } + private fun function_spec_block(x: u64): u64 { + Add(x, 1) + } + spec { + ensures Eq(result0(), m::exec(|x: num| Add(x, 1), $t0)); + } + + private inline fun get(a: address): � { + BorrowGlobal(Immutable)(a) + } +} // end 0x42::m + + +// -- Model dump after env processor unused checks: +module 0x42::m { + spec { + invariant forall a: address: TypeDomain
(): Implies(exists(a), m::exec(|a: address| Lt(select m::S.f(m::get(a)), 10), a)); + } + + struct S { + f: u64, + } + spec { + invariant m::exec(|x: num| Gt(x, 0), select m::S.f()); + } + + private 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 m::exec(|y: num| Gt(y, 0), $t0); + } + ; + Add(x, 1) + } + private fun function_spec_block(x: u64): u64 { + Add(x, 1) + } + spec { + ensures Eq(result0(), m::exec(|x: num| Add(x, 1), $t0)); + } + + private inline fun get(a: address): � { + BorrowGlobal(Immutable)(a) + } +} // end 0x42::m + + +// -- Model dump after env processor type parameter check: +module 0x42::m { + spec { + invariant forall a: address: TypeDomain
(): Implies(exists(a), m::exec(|a: address| Lt(select m::S.f(m::get(a)), 10), a)); + } + + struct S { + f: u64, + } + spec { + invariant m::exec(|x: num| Gt(x, 0), select m::S.f()); + } + + private 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 m::exec(|y: num| Gt(y, 0), $t0); + } + ; + Add(x, 1) + } + private fun function_spec_block(x: u64): u64 { + Add(x, 1) + } + spec { + ensures Eq(result0(), m::exec(|x: num| Add(x, 1), $t0)); + } + + private inline fun get(a: address): � { + BorrowGlobal(Immutable)(a) + } +} // end 0x42::m + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::m { + spec { + invariant forall a: address: TypeDomain
(): Implies(exists(a), m::exec(|a: address| Lt(select m::S.f(m::get(a)), 10), a)); + } + + struct S { + f: u64, + } + spec { + invariant m::exec(|x: num| Gt(x, 0), select m::S.f()); + } + + private 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 m::exec(|y: num| Gt(y, 0), $t0); + } + ; + Add(x, 1) + } + private fun function_spec_block(x: u64): u64 { + Add(x, 1) + } + spec { + ensures Eq(result0(), m::exec(|x: num| Add(x, 1), $t0)); + } + + private inline fun get(a: address): � { + BorrowGlobal(Immutable)(a) + } +} // end 0x42::m + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::m { + spec { + invariant forall a: address: TypeDomain
(): Implies(exists(a), m::exec(|a: address| Lt(select m::S.f(m::get(a)), 10), a)); + } + + struct S { + f: u64, + } + spec { + invariant m::exec(|x: num| Gt(x, 0), select m::S.f()); + } + + private 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 m::exec(|y: num| Gt(y, 0), $t0); + } + ; + Add(x, 1) + } + private fun function_spec_block(x: u64): u64 { + Add(x, 1) + } + spec { + ensures Eq(result0(), m::exec(|x: num| Add(x, 1), $t0)); + } + + private inline fun get(a: address): � { + BorrowGlobal(Immutable)(a) + } +} // end 0x42::m + + +// -- Model dump after env processor unused struct params check: +module 0x42::m { + spec { + invariant forall a: address: TypeDomain
(): Implies(exists(a), m::exec(|a: address| Lt(select m::S.f(m::get(a)), 10), a)); + } + + struct S { + f: u64, + } + spec { + invariant m::exec(|x: num| Gt(x, 0), select m::S.f()); + } + + private 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 m::exec(|y: num| Gt(y, 0), $t0); + } + ; + Add(x, 1) + } + private fun function_spec_block(x: u64): u64 { + Add(x, 1) + } + spec { + ensures Eq(result0(), m::exec(|x: num| Add(x, 1), $t0)); + } + + private inline fun get(a: address): � { + BorrowGlobal(Immutable)(a) + } +} // end 0x42::m + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::m { + spec { + invariant forall a: address: TypeDomain
(): Implies(exists(a), m::exec(|a: address| Lt(select m::S.f(m::get(a)), 10), a)); + } + + struct S { + f: u64, + } + spec { + invariant m::exec(|x: num| Gt(x, 0), select m::S.f()); + } + + private 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 m::exec(|y: num| Gt(y, 0), $t0); + } + ; + Add(x, 1) + } + private fun function_spec_block(x: u64): u64 { + Add(x, 1) + } + spec { + ensures Eq(result0(), m::exec(|x: num| Add(x, 1), $t0)); + } + + private inline fun get(a: address): � { + BorrowGlobal(Immutable)(a) + } +} // end 0x42::m + + +// -- Model dump after env processor inlining: +module 0x42::m { + spec { + invariant forall a: address: TypeDomain
(): Implies(exists(a), m::exec(|a: address| Lt(select m::S.f({ + let (a: address): (address) = Tuple(a); + BorrowGlobal(Immutable)(a) + }), 10), a)); + } + + struct S { + f: u64, + } + spec { + invariant m::exec(|x: num| Gt(x, 0), select m::S.f()); + } + + private 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 m::exec(|y: num| Gt(y, 0), $t0); + } + ; + Add(x, 1) + } + private fun function_spec_block(x: u64): u64 { + Add(x, 1) + } + spec { + ensures Eq(result0(), m::exec(|x: num| Add(x, 1), $t0)); + } + + private inline fun get(a: address): � { + BorrowGlobal(Immutable)(a) + } +} // end 0x42::m + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::m { + spec { + invariant forall a: address: TypeDomain
(): Implies(exists(a), m::exec(|a: address| Lt(select m::S.f({ + let (a: address): (address) = Tuple(a); + BorrowGlobal(Immutable)(a) + }), 10), a)); + } + + struct S { + f: u64, + } + spec { + invariant m::exec(|x: num| Gt(x, 0), select m::S.f()); + } + + private 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 m::exec(|y: num| Gt(y, 0), $t0); + } + ; + Add(x, 1) + } + private fun function_spec_block(x: u64): u64 { + Add(x, 1) + } + spec { + ensures Eq(result0(), m::exec(|x: num| Add(x, 1), $t0)); + } + + private inline fun get(a: address): � { + BorrowGlobal(Immutable)(a) + } +} // end 0x42::m + + +// -- Model dump after env processor acquires check: +module 0x42::m { + spec { + invariant forall a: address: TypeDomain
(): Implies(exists(a), m::exec(|a: address| Lt(select m::S.f({ + let (a: address): (address) = Tuple(a); + BorrowGlobal(Immutable)(a) + }), 10), a)); + } + + struct S { + f: u64, + } + spec { + invariant m::exec(|x: num| Gt(x, 0), select m::S.f()); + } + + private 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 m::exec(|y: num| Gt(y, 0), $t0); + } + ; + Add(x, 1) + } + private fun function_spec_block(x: u64): u64 { + Add(x, 1) + } + spec { + ensures Eq(result0(), m::exec(|x: num| Add(x, 1), $t0)); + } + + private inline fun get(a: address): � { + BorrowGlobal(Immutable)(a) + } +} // end 0x42::m + + +// -- Model dump after env processor simplifier: +module 0x42::m { + spec { + invariant forall a: address: TypeDomain
(): Implies(exists(a), m::exec(|a: address| Lt(select m::S.f({ + let (a: address): (address) = Tuple(a); + BorrowGlobal(Immutable)(a) + }), 10), a)); + } + + struct S { + f: u64, + } + spec { + invariant m::exec(|x: num| Gt(x, 0), select m::S.f()); + } + + private 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 m::exec(|y: num| Gt(y, 0), $t0); + } + ; + Add(x, 1) + } + private fun function_spec_block(x: u64): u64 { + Add(x, 1) + } + spec { + ensures Eq(result0(), m::exec(|x: num| Add(x, 1), $t0)); + } + + private inline fun get(a: address): � { + BorrowGlobal(Immutable)(a) + } +} // end 0x42::m + + +// -- Model dump after env processor lambda-lifting: +module 0x42::m { + spec { + invariant forall a: address: TypeDomain
(): Implies(exists(a), m::exec(|a: address| Lt(select m::S.f({ + let (a: address): (address) = Tuple(a); + BorrowGlobal(Immutable)(a) + }), 10), a)); + } + + struct S { + f: u64, + } + spec { + invariant m::exec(|x: num| Gt(x, 0), select m::S.f()); + } + + private 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 m::exec(closure m::function_code_spec_block$lambda$1(), $t0); + } + ; + Add(x, 1) + } + private fun function_spec_block(x: u64): u64 { + Add(x, 1) + } + spec { + ensures Eq(result0(), m::exec(|x: num| Add(x, 1), $t0)); + } + + private inline fun get(a: address): � { + BorrowGlobal(Immutable)(a) + } + private fun function_code_spec_block$lambda$1(y: num): bool { + Gt(y, 0) + } +} // end 0x42::m + + +// -- Model dump after env processor specification checker: +module 0x42::m { + spec { + invariant forall a: address: TypeDomain
(): Implies(exists(a), m::exec(|a: address| Lt(select m::S.f({ + let (a: address): (address) = Tuple(a); + BorrowGlobal(Immutable)(a) + }), 10), a)); + } + + struct S { + f: u64, + } + spec { + invariant m::exec(|x: num| Gt(x, 0), select m::S.f()); + } + + private 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 m::exec(closure m::function_code_spec_block$lambda$1(), $t0); + } + ; + Add(x, 1) + } + private fun function_spec_block(x: u64): u64 { + Add(x, 1) + } + spec { + ensures Eq(result0(), m::exec(|x: num| Add(x, 1), $t0)); + } + + private inline fun get(a: address): � { + BorrowGlobal(Immutable)(a) + } + private fun function_code_spec_block$lambda$1(y: num): bool { + Gt(y, 0) + } +} // end 0x42::m + + +// -- Model dump after env processor specification rewriter: +module 0x42::m { + spec { + invariant forall a: address: TypeDomain
(): Implies(exists(a), m::$exec(|a: address| Lt(select m::S.f({ + let (a: address): (address) = Tuple(a); + global(a) + }), 10), a)); + } + + struct S { + f: u64, + } + spec { + invariant m::$exec(|x: num| Gt(x, 0), select m::S.f()); + } + + private 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 m::$exec(closure m::function_code_spec_block$lambda$1(), $t0); + } + ; + Add(x, 1) + } + private fun function_spec_block(x: u64): u64 { + Add(x, 1) + } + spec { + ensures Eq(result0(), m::$exec(|x: num| Add(x, 1), $t0)); + } + + private inline fun get(a: address): � { + BorrowGlobal(Immutable)(a) + } + private fun function_code_spec_block$lambda$1(y: num): bool { + Gt(y, 0) + } + spec fun $exec(f: |#0|#1,x: #0): #1 { + { + let r: #1 = (f)(x); + r + } + } +} // end 0x42::m + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/inline_fun_in_spec.move:4:17 + │ +4 │ let r = f(x); + │ ^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inline_fun_in_spec.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inline_fun_in_spec.move new file mode 100644 index 00000000000000..44d0592c4e1104 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inline_fun_in_spec.move @@ -0,0 +1,33 @@ +module 0x42::m { + + 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| x + 1, x); + } + + // Function code spec block + fun function_code_spec_block(x: u64): u64 { + spec { assert exec(|y| y > 0, x); }; + x + 1 + } + + // Struct spec block + struct S has key { f: u64 } + spec S { invariant exec(|x| x > 0, f); } + + // Global invariant + spec module { + invariant forall a: address: + exists(a) ==> exec(|a| get(a).f < 10, a); + } + inline fun get(a: address): &R { borrow_global(a) } +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inlining1.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inlining1.exp new file mode 100644 index 00000000000000..e98e2139f1333f --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inlining1.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `Test::foo` has a function parameter: + ┌─ tests/lambda/inline-parity/inlining1.move:3:9 + │ +3 │ fun foo(f:|u64| u64, x: u64): u64 { + │ ^^^ - Parameter `f` has function-valued type `|u64|u64`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inlining1.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inlining1.lambda.exp new file mode 100644 index 00000000000000..ccd5c619914857 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inlining1.lambda.exp @@ -0,0 +1,297 @@ +// -- Model dump before env processor pipeline: +module 0x42::Test { + private fun foo(f: |u64|u64,x: u64): u64 { + (f)(x) + } + public fun main() { + if Eq(Test::test(), 3) { + Tuple() + } else { + Abort(5) + }; + Tuple() + } + public fun test(): u64 { + Test::foo(|_: u64| 3, 10) + } +} // end 0x42::Test + + +// -- Model dump after env processor unused checks: +module 0x42::Test { + private fun foo(f: |u64|u64,x: u64): u64 { + (f)(x) + } + public fun main() { + if Eq(Test::test(), 3) { + Tuple() + } else { + Abort(5) + }; + Tuple() + } + public fun test(): u64 { + Test::foo(|_: u64| 3, 10) + } +} // end 0x42::Test + + +// -- Model dump after env processor type parameter check: +module 0x42::Test { + private fun foo(f: |u64|u64,x: u64): u64 { + (f)(x) + } + public fun main() { + if Eq(Test::test(), 3) { + Tuple() + } else { + Abort(5) + }; + Tuple() + } + public fun test(): u64 { + Test::foo(|_: u64| 3, 10) + } +} // end 0x42::Test + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::Test { + private fun foo(f: |u64|u64,x: u64): u64 { + (f)(x) + } + public fun main() { + if Eq(Test::test(), 3) { + Tuple() + } else { + Abort(5) + }; + Tuple() + } + public fun test(): u64 { + Test::foo(|_: u64| 3, 10) + } +} // end 0x42::Test + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::Test { + private fun foo(f: |u64|u64,x: u64): u64 { + (f)(x) + } + public fun main() { + if Eq(Test::test(), 3) { + Tuple() + } else { + Abort(5) + }; + Tuple() + } + public fun test(): u64 { + Test::foo(|_: u64| 3, 10) + } +} // end 0x42::Test + + +// -- Model dump after env processor unused struct params check: +module 0x42::Test { + private fun foo(f: |u64|u64,x: u64): u64 { + (f)(x) + } + public fun main() { + if Eq(Test::test(), 3) { + Tuple() + } else { + Abort(5) + }; + Tuple() + } + public fun test(): u64 { + Test::foo(|_: u64| 3, 10) + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::Test { + private fun foo(f: |u64|u64,x: u64): u64 { + (f)(x) + } + public fun main() { + if Eq(Test::test(), 3) { + Tuple() + } else { + Abort(5) + }; + Tuple() + } + public fun test(): u64 { + Test::foo(|_: u64| 3, 10) + } +} // end 0x42::Test + + +// -- Model dump after env processor inlining: +module 0x42::Test { + private fun foo(f: |u64|u64,x: u64): u64 { + (f)(x) + } + public fun main() { + if Eq(Test::test(), 3) { + Tuple() + } else { + Abort(5) + }; + Tuple() + } + public fun test(): u64 { + Test::foo(|_: u64| 3, 10) + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::Test { + private fun foo(f: |u64|u64,x: u64): u64 { + (f)(x) + } + public fun main() { + if Eq(Test::test(), 3) { + Tuple() + } else { + Abort(5) + }; + Tuple() + } + public fun test(): u64 { + Test::foo(|_: u64| 3, 10) + } +} // end 0x42::Test + + +// -- Model dump after env processor acquires check: +module 0x42::Test { + private fun foo(f: |u64|u64,x: u64): u64 { + (f)(x) + } + public fun main() { + if Eq(Test::test(), 3) { + Tuple() + } else { + Abort(5) + }; + Tuple() + } + public fun test(): u64 { + Test::foo(|_: u64| 3, 10) + } +} // end 0x42::Test + + +// -- Model dump after env processor simplifier: +module 0x42::Test { + private fun foo(f: |u64|u64,x: u64): u64 { + (f)(x) + } + public fun main() { + if Eq(Test::test(), 3) { + Tuple() + } else { + Abort(5) + }; + Tuple() + } + public fun test(): u64 { + Test::foo(|_: u64| 3, 10) + } +} // end 0x42::Test + + +// -- Model dump after env processor lambda-lifting: +module 0x42::Test { + private fun foo(f: |u64|u64,x: u64): u64 { + (f)(x) + } + public fun main() { + if Eq(Test::test(), 3) { + Tuple() + } else { + Abort(5) + }; + Tuple() + } + public fun test(): u64 { + Test::foo(closure Test::test$lambda$1(), 10) + } + private fun test$lambda$1(param$0: u64): u64 { + { + let _: u64 = param$0; + 3 + } + } +} // end 0x42::Test + + +// -- Model dump after env processor specification checker: +module 0x42::Test { + private fun foo(f: |u64|u64,x: u64): u64 { + (f)(x) + } + public fun main() { + if Eq(Test::test(), 3) { + Tuple() + } else { + Abort(5) + }; + Tuple() + } + public fun test(): u64 { + Test::foo(closure Test::test$lambda$1(), 10) + } + private fun test$lambda$1(param$0: u64): u64 { + { + let _: u64 = param$0; + 3 + } + } +} // end 0x42::Test + + +// -- Model dump after env processor specification rewriter: +module 0x42::Test { + private fun foo(f: |u64|u64,x: u64): u64 { + (f)(x) + } + public fun main() { + if Eq(Test::test(), 3) { + Tuple() + } else { + Abort(5) + }; + Tuple() + } + public fun test(): u64 { + Test::foo(closure Test::test$lambda$1(), 10) + } + private fun test$lambda$1(param$0: u64): u64 { + { + let _: u64 = param$0; + 3 + } + } +} // end 0x42::Test + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/inlining1.move:4:9 + │ +4 │ f(x) + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/inlining1.move:8:13 + │ +8 │ foo(|_| 3, 10) + │ ^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inlining1.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inlining1.move new file mode 100644 index 00000000000000..90e1730c035e70 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inlining1.move @@ -0,0 +1,16 @@ +//# publish +module 0x42::Test { + fun foo(f:|u64| u64, x: u64): u64 { + f(x) + } + + public fun test(): u64 { + foo(|_| 3, 10) + } + + public fun main() { + assert!(test() == 3, 5); + } +} + +//# run 0x42::Test::main diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda.exp new file mode 100644 index 00000000000000..2c88c63b0241a4 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda.exp @@ -0,0 +1,37 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `LambdaTest1::inline_apply1` has a function parameter: + ┌─ tests/lambda/inline-parity/lambda.move:6:16 + │ +6 │ public fun inline_apply1(f: |u64|u64, b: u64) : u64 { + │ ^^^^^^^^^^^^^ - Parameter `f` has function-valued type `|u64|u64`. + +error: Only inline functions may have function-typed parameters, but non-inline function `LambdaTest1::inline_apply` has a function parameter: + ┌─ tests/lambda/inline-parity/lambda.move:10:16 + │ +10 │ public fun inline_apply(f: |u64|u64, b: u64) : u64 { + │ ^^^^^^^^^^^^ - Parameter `f` has function-valued type `|u64|u64`. + +error: Only inline functions may have function-typed parameters, but non-inline function `LambdaTest2::foreach` has a function parameter: + ┌─ tests/lambda/inline-parity/lambda.move:19:16 + │ +19 │ public fun foreach(v: &vector, action: |&T|) { // expected to be not implemented + │ ^^^^^^^ ------ Parameter `action` has function-valued type `|&T|`. + +error: Only inline functions may have function-typed parameters, but non-inline function `LambdaTest2::inline_apply2` has a function parameter: + ┌─ tests/lambda/inline-parity/lambda.move:33:16 + │ +33 │ public fun inline_apply2(g: |u64|u64, c: u64) : u64 { + │ ^^^^^^^^^^^^^ - Parameter `g` has function-valued type `|u64|u64`. + +error: Only inline functions may have function-typed parameters, but non-inline function `LambdaTest2::inline_apply3` has a function parameter: + ┌─ tests/lambda/inline-parity/lambda.move:37:16 + │ +37 │ public fun inline_apply3(g: |u64|u64, c: u64) : u64 { + │ ^^^^^^^^^^^^^ - Parameter `g` has function-valued type `|u64|u64`. + +error: Only inline functions may have function-typed parameters, but non-inline function `LambdaTest::inline_apply` has a function parameter: + ┌─ tests/lambda/inline-parity/lambda.move:49:16 + │ +49 │ public fun inline_apply(f: |u64|u64, b: u64) : u64 { + │ ^^^^^^^^^^^^ - Parameter `f` has function-valued type `|u64|u64`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda.lambda.exp new file mode 100644 index 00000000000000..83d126ea90464d --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda.lambda.exp @@ -0,0 +1,752 @@ +// -- Model dump before env processor pipeline: +module 0x42::LambdaTest1 { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply1(f: |u64|u64,b: u64): u64 { + LambdaTest1::inline_mul(Add((f)(b), 1), LambdaTest1::inline_mul(3, 4)) + } + public 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 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 fun inline_apply2(g: |u64|u64,c: u64): u64 { + Add(LambdaTest1::inline_apply1(|z: u64| z, (g)(LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(|x: u64| x, 3)))), 2) + } + public 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 v: vector = Vector(1, 2, 3); + { + let product: u64 = 1; + LambdaTest2::foreach(Borrow(Immutable)(v), |e: &u64| product: u64 = LambdaTest1::inline_mul(product, Deref(e))); + Tuple() + } + } + } +} // end 0x42::LambdaTest2 +module 0x42::LambdaTest { + use 0x42::LambdaTest2; // resolved as: 0x42::LambdaTest2 + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply_test(): u64 { + Add(LambdaTest2::inline_apply2(|x: u64| Add(x, 1), 3), LambdaTest2::inline_apply2(|x: u64| Mul(x, x), LambdaTest::inline_apply(|y: u64| y, 3))) + } + private fun test_lambda() { + { + let a: u64 = LambdaTest::inline_apply_test(); + if Eq(a, 1) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaTest + + +// -- Model dump after env processor unused checks: +module 0x42::LambdaTest1 { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply1(f: |u64|u64,b: u64): u64 { + LambdaTest1::inline_mul(Add((f)(b), 1), LambdaTest1::inline_mul(3, 4)) + } + public 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 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 fun inline_apply2(g: |u64|u64,c: u64): u64 { + Add(LambdaTest1::inline_apply1(|z: u64| z, (g)(LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(|x: u64| x, 3)))), 2) + } + public 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 v: vector = Vector(1, 2, 3); + { + let product: u64 = 1; + LambdaTest2::foreach(Borrow(Immutable)(v), |e: &u64| product: u64 = LambdaTest1::inline_mul(product, Deref(e))); + Tuple() + } + } + } +} // end 0x42::LambdaTest2 +module 0x42::LambdaTest { + use 0x42::LambdaTest2; // resolved as: 0x42::LambdaTest2 + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply_test(): u64 { + Add(LambdaTest2::inline_apply2(|x: u64| Add(x, 1), 3), LambdaTest2::inline_apply2(|x: u64| Mul(x, x), LambdaTest::inline_apply(|y: u64| y, 3))) + } + private fun test_lambda() { + { + let a: u64 = LambdaTest::inline_apply_test(); + if Eq(a, 1) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaTest + + +// -- Model dump after env processor type parameter check: +module 0x42::LambdaTest1 { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply1(f: |u64|u64,b: u64): u64 { + LambdaTest1::inline_mul(Add((f)(b), 1), LambdaTest1::inline_mul(3, 4)) + } + public 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 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 fun inline_apply2(g: |u64|u64,c: u64): u64 { + Add(LambdaTest1::inline_apply1(|z: u64| z, (g)(LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(|x: u64| x, 3)))), 2) + } + public 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 v: vector = Vector(1, 2, 3); + { + let product: u64 = 1; + LambdaTest2::foreach(Borrow(Immutable)(v), |e: &u64| product: u64 = LambdaTest1::inline_mul(product, Deref(e))); + Tuple() + } + } + } +} // end 0x42::LambdaTest2 +module 0x42::LambdaTest { + use 0x42::LambdaTest2; // resolved as: 0x42::LambdaTest2 + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply_test(): u64 { + Add(LambdaTest2::inline_apply2(|x: u64| Add(x, 1), 3), LambdaTest2::inline_apply2(|x: u64| Mul(x, x), LambdaTest::inline_apply(|y: u64| y, 3))) + } + private fun test_lambda() { + { + let a: u64 = LambdaTest::inline_apply_test(); + if Eq(a, 1) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaTest + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::LambdaTest1 { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply1(f: |u64|u64,b: u64): u64 { + LambdaTest1::inline_mul(Add((f)(b), 1), LambdaTest1::inline_mul(3, 4)) + } + public 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 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 fun inline_apply2(g: |u64|u64,c: u64): u64 { + Add(LambdaTest1::inline_apply1(|z: u64| z, (g)(LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(|x: u64| x, 3)))), 2) + } + public 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 v: vector = Vector(1, 2, 3); + { + let product: u64 = 1; + LambdaTest2::foreach(Borrow(Immutable)(v), |e: &u64| product: u64 = LambdaTest1::inline_mul(product, Deref(e))); + Tuple() + } + } + } +} // end 0x42::LambdaTest2 +module 0x42::LambdaTest { + use 0x42::LambdaTest2; // resolved as: 0x42::LambdaTest2 + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply_test(): u64 { + Add(LambdaTest2::inline_apply2(|x: u64| Add(x, 1), 3), LambdaTest2::inline_apply2(|x: u64| Mul(x, x), LambdaTest::inline_apply(|y: u64| y, 3))) + } + private fun test_lambda() { + { + let a: u64 = LambdaTest::inline_apply_test(); + if Eq(a, 1) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaTest + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::LambdaTest1 { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply1(f: |u64|u64,b: u64): u64 { + LambdaTest1::inline_mul(Add((f)(b), 1), LambdaTest1::inline_mul(3, 4)) + } + public 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 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 fun inline_apply2(g: |u64|u64,c: u64): u64 { + Add(LambdaTest1::inline_apply1(|z: u64| z, (g)(LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(|x: u64| x, 3)))), 2) + } + public 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 v: vector = Vector(1, 2, 3); + { + let product: u64 = 1; + LambdaTest2::foreach(Borrow(Immutable)(v), |e: &u64| product: u64 = LambdaTest1::inline_mul(product, Deref(e))); + Tuple() + } + } + } +} // end 0x42::LambdaTest2 +module 0x42::LambdaTest { + use 0x42::LambdaTest2; // resolved as: 0x42::LambdaTest2 + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply_test(): u64 { + Add(LambdaTest2::inline_apply2(|x: u64| Add(x, 1), 3), LambdaTest2::inline_apply2(|x: u64| Mul(x, x), LambdaTest::inline_apply(|y: u64| y, 3))) + } + private fun test_lambda() { + { + let a: u64 = LambdaTest::inline_apply_test(); + if Eq(a, 1) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaTest + + +// -- Model dump after env processor unused struct params check: +module 0x42::LambdaTest1 { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply1(f: |u64|u64,b: u64): u64 { + LambdaTest1::inline_mul(Add((f)(b), 1), LambdaTest1::inline_mul(3, 4)) + } + public 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 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 fun inline_apply2(g: |u64|u64,c: u64): u64 { + Add(LambdaTest1::inline_apply1(|z: u64| z, (g)(LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(|x: u64| x, 3)))), 2) + } + public 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 v: vector = Vector(1, 2, 3); + { + let product: u64 = 1; + LambdaTest2::foreach(Borrow(Immutable)(v), |e: &u64| product: u64 = LambdaTest1::inline_mul(product, Deref(e))); + Tuple() + } + } + } +} // end 0x42::LambdaTest2 +module 0x42::LambdaTest { + use 0x42::LambdaTest2; // resolved as: 0x42::LambdaTest2 + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply_test(): u64 { + Add(LambdaTest2::inline_apply2(|x: u64| Add(x, 1), 3), LambdaTest2::inline_apply2(|x: u64| Mul(x, x), LambdaTest::inline_apply(|y: u64| y, 3))) + } + private fun test_lambda() { + { + let a: u64 = LambdaTest::inline_apply_test(); + if Eq(a, 1) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaTest + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::LambdaTest1 { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply1(f: |u64|u64,b: u64): u64 { + LambdaTest1::inline_mul(Add((f)(b), 1), LambdaTest1::inline_mul(3, 4)) + } + public 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 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 fun inline_apply2(g: |u64|u64,c: u64): u64 { + Add(LambdaTest1::inline_apply1(|z: u64| z, (g)(LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(|x: u64| x, 3)))), 2) + } + public 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 v: vector = Vector(1, 2, 3); + { + let product: u64 = 1; + LambdaTest2::foreach(Borrow(Immutable)(v), |e: &u64| product: u64 = LambdaTest1::inline_mul(product, Deref(e))); + Tuple() + } + } + } +} // end 0x42::LambdaTest2 +module 0x42::LambdaTest { + use 0x42::LambdaTest2; // resolved as: 0x42::LambdaTest2 + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply_test(): u64 { + Add(LambdaTest2::inline_apply2(|x: u64| Add(x, 1), 3), LambdaTest2::inline_apply2(|x: u64| Mul(x, x), LambdaTest::inline_apply(|y: u64| y, 3))) + } + private fun test_lambda() { + { + let a: u64 = LambdaTest::inline_apply_test(); + if Eq(a, 1) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaTest + + +// -- Model dump after env processor inlining: +module 0x42::LambdaTest1 { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply1(f: |u64|u64,b: u64): u64 { + LambdaTest1::inline_mul(Add((f)(b), 1), LambdaTest1::inline_mul(3, 4)) + } + public 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 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 fun inline_apply2(g: |u64|u64,c: u64): u64 { + Add(LambdaTest1::inline_apply1(|z: u64| z, (g)(LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(|x: u64| x, 3)))), 2) + } + public 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 v: vector = Vector(1, 2, 3); + { + let product: u64 = 1; + LambdaTest2::foreach(Borrow(Immutable)(v), |e: &u64| product: u64 = LambdaTest1::inline_mul(product, Deref(e))); + Tuple() + } + } + } +} // end 0x42::LambdaTest2 +module 0x42::LambdaTest { + use 0x42::LambdaTest2; // resolved as: 0x42::LambdaTest2 + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply_test(): u64 { + Add(LambdaTest2::inline_apply2(|x: u64| Add(x, 1), 3), LambdaTest2::inline_apply2(|x: u64| Mul(x, x), LambdaTest::inline_apply(|y: u64| y, 3))) + } + private fun test_lambda() { + { + let a: u64 = LambdaTest::inline_apply_test(); + if Eq(a, 1) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaTest + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::LambdaTest1 { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply1(f: |u64|u64,b: u64): u64 { + LambdaTest1::inline_mul(Add((f)(b), 1), LambdaTest1::inline_mul(3, 4)) + } + public 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 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 fun inline_apply2(g: |u64|u64,c: u64): u64 { + Add(LambdaTest1::inline_apply1(|z: u64| z, (g)(LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(|x: u64| x, 3)))), 2) + } + public 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 v: vector = Vector(1, 2, 3); + { + let product: u64 = 1; + LambdaTest2::foreach(Borrow(Immutable)(v), |e: &u64| product: u64 = LambdaTest1::inline_mul(product, Deref(e))); + Tuple() + } + } + } +} // end 0x42::LambdaTest2 +module 0x42::LambdaTest { + use 0x42::LambdaTest2; // resolved as: 0x42::LambdaTest2 + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply_test(): u64 { + Add(LambdaTest2::inline_apply2(|x: u64| Add(x, 1), 3), LambdaTest2::inline_apply2(|x: u64| Mul(x, x), LambdaTest::inline_apply(|y: u64| y, 3))) + } + private fun test_lambda() { + { + let a: u64 = LambdaTest::inline_apply_test(); + if Eq(a, 1) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaTest + + +// -- Model dump after env processor acquires check: +module 0x42::LambdaTest1 { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply1(f: |u64|u64,b: u64): u64 { + LambdaTest1::inline_mul(Add((f)(b), 1), LambdaTest1::inline_mul(3, 4)) + } + public 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 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 fun inline_apply2(g: |u64|u64,c: u64): u64 { + Add(LambdaTest1::inline_apply1(|z: u64| z, (g)(LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(|x: u64| x, 3)))), 2) + } + public 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 v: vector = Vector(1, 2, 3); + { + let product: u64 = 1; + LambdaTest2::foreach(Borrow(Immutable)(v), |e: &u64| product: u64 = LambdaTest1::inline_mul(product, Deref(e))); + Tuple() + } + } + } +} // end 0x42::LambdaTest2 +module 0x42::LambdaTest { + use 0x42::LambdaTest2; // resolved as: 0x42::LambdaTest2 + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply_test(): u64 { + Add(LambdaTest2::inline_apply2(|x: u64| Add(x, 1), 3), LambdaTest2::inline_apply2(|x: u64| Mul(x, x), LambdaTest::inline_apply(|y: u64| y, 3))) + } + private fun test_lambda() { + { + let a: u64 = LambdaTest::inline_apply_test(); + if Eq(a, 1) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaTest + + +// -- Model dump after env processor simplifier: +module 0x42::LambdaTest1 { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply1(f: |u64|u64,b: u64): u64 { + LambdaTest1::inline_mul(Add((f)(b), 1), LambdaTest1::inline_mul(3, 4)) + } + public 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 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 fun inline_apply2(g: |u64|u64,c: u64): u64 { + Add(LambdaTest1::inline_apply1(|z: u64| z, (g)(LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(|x: u64| x, 3)))), 2) + } + public 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; + LambdaTest2::foreach(Borrow(Immutable)([Number(1), Number(2), Number(3)]), |e: &u64| product: u64 = LambdaTest1::inline_mul(product, Deref(e))); + Tuple() + } + } +} // end 0x42::LambdaTest2 +module 0x42::LambdaTest { + use 0x42::LambdaTest2; // resolved as: 0x42::LambdaTest2 + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply_test(): u64 { + Add(LambdaTest2::inline_apply2(|x: u64| Add(x, 1), 3), LambdaTest2::inline_apply2(|x: u64| Mul(x, x), LambdaTest::inline_apply(|y: u64| y, 3))) + } + private fun test_lambda() { + { + let a: u64 = LambdaTest::inline_apply_test(); + if Eq(a, 1) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaTest + + + +Diagnostics: +error: captured variable `product` cannot be modified inside of a lambda + ┌─ tests/lambda/inline-parity/lambda.move:30:18 + │ +30 │ foreach(&v, |e| product = LambdaTest1::inline_mul(product, *e)); + │ ^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda.move new file mode 100644 index 00000000000000..b742f0ec18982b --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda.move @@ -0,0 +1,62 @@ +module 0x42::LambdaTest1 { + public fun inline_mul(a: u64, b: u64): u64 { + a * b + } + + public fun inline_apply1(f: |u64|u64, b: u64) : u64 { + inline_mul(f(b) + 1, inline_mul(3, 4)) + } + + public fun inline_apply(f: |u64|u64, b: u64) : u64 { + f(b) + } +} + +module 0x42::LambdaTest2 { + use 0x42::LambdaTest1; + use std::vector; + + public 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| product = LambdaTest1::inline_mul(product, *e)); + } + + public fun inline_apply2(g: |u64|u64, c: u64) : u64 { + LambdaTest1::inline_apply1(|z|z, g(LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(|x|x, 3)))) + 2 + } + + public fun inline_apply3(g: |u64|u64, c: u64) : u64 { + LambdaTest1::inline_apply1(g, + LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(|x| { + LambdaTest1::inline_apply(|y|y, x) + }, + 3))) + 4 + } +} + +module 0x42::LambdaTest { + use 0x42::LambdaTest2; + + public fun inline_apply(f: |u64|u64, b: u64) : u64 { + f(b) + } + + public fun inline_apply_test() : u64 { + LambdaTest2::inline_apply2(|x| x + 1, 3) + + LambdaTest2::inline_apply2(|x| x * x, inline_apply(|y|y, 3)) + } + + fun test_lambda() { + let a = inline_apply_test(); + assert!(a == 1, 0); + } +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast.exp new file mode 100644 index 00000000000000..f691386af6c2d1 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast.exp @@ -0,0 +1,16 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `M::vector_for_each` has a function parameter: + ┌─ tests/lambda/inline-parity/lambda_cast.move:4:9 + │ +4 │ fun vector_for_each(v: vector, f: |Element|) { + │ ^^^^^^^^^^^^^^^ - Parameter `f` has function-valued type `|Element|`. + +error: Only inline functions may have function-typed parameters, but non-inline function `M::vector_fold` has a function parameter: + ┌─ tests/lambda/inline-parity/lambda_cast.move:12:9 + │ +12 │ fun vector_fold( + │ ^^^^^^^^^^^ + · +15 │ f: |Accumulator,Element|Accumulator + │ - Parameter `f` has function-valued type `|(Accumulator, Element)|Accumulator`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast.lambda.exp new file mode 100644 index 00000000000000..8b79f94a921a27 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast.lambda.exp @@ -0,0 +1,441 @@ +// -- Model dump before env processor pipeline: +module 0x12391283::M { + use std::vector; + private fun test_1(): u64 { + { + let gas_schedule_blob: vector = Vector(115, 115, 95, 112, 97, 99, 107, 101, 100, 32, 0, 0, 0, 0, 0, 0, 0); + M::vector_fold(gas_schedule_blob, Cast(0), |(sum: u64, addend: u8): (u64, u8)| Add(sum, Cast(addend))) + } + } + private fun test_2(): u64 { + { + let gas_schedule_blob: vector = Vector(115, 115, 95, 112, 97, 99, 107, 101, 100, 32, 0, 0, 0, 0, 0, 0, 0); + M::vector_fold(gas_schedule_blob, Cast(0), |(sum: u64, addend: u8): (u64, u8)| Add(sum, Cast(addend))) + } + } + private fun vector_fold(v: vector<#1>,init: #0,f: |(#0, #1)|#0): #0 { + { + let accu: Accumulator = init; + M::vector_for_each(v, |elem: Element| accu: Accumulator = (f)(accu, elem)); + accu + } + } + private fun vector_for_each(v: vector<#0>,f: |#0|) { + vector::reverse(Borrow(Mutable)(v)); + loop { + if Not(vector::is_empty(Borrow(Immutable)(v))) { + { + let e: Element = vector::pop_back(Borrow(Mutable)(v)); + (f)(e); + Tuple() + } + } else { + break + } + }; + Tuple() + } +} // end 0x12391283::M + + +// -- Model dump after env processor unused checks: +module 0x12391283::M { + use std::vector; + private fun test_1(): u64 { + { + let gas_schedule_blob: vector = Vector(115, 115, 95, 112, 97, 99, 107, 101, 100, 32, 0, 0, 0, 0, 0, 0, 0); + M::vector_fold(gas_schedule_blob, Cast(0), |(sum: u64, addend: u8): (u64, u8)| Add(sum, Cast(addend))) + } + } + private fun test_2(): u64 { + { + let gas_schedule_blob: vector = Vector(115, 115, 95, 112, 97, 99, 107, 101, 100, 32, 0, 0, 0, 0, 0, 0, 0); + M::vector_fold(gas_schedule_blob, Cast(0), |(sum: u64, addend: u8): (u64, u8)| Add(sum, Cast(addend))) + } + } + private fun vector_fold(v: vector<#1>,init: #0,f: |(#0, #1)|#0): #0 { + { + let accu: Accumulator = init; + M::vector_for_each(v, |elem: Element| accu: Accumulator = (f)(accu, elem)); + accu + } + } + private fun vector_for_each(v: vector<#0>,f: |#0|) { + vector::reverse(Borrow(Mutable)(v)); + loop { + if Not(vector::is_empty(Borrow(Immutable)(v))) { + { + let e: Element = vector::pop_back(Borrow(Mutable)(v)); + (f)(e); + Tuple() + } + } else { + break + } + }; + Tuple() + } +} // end 0x12391283::M + + +// -- Model dump after env processor type parameter check: +module 0x12391283::M { + use std::vector; + private fun test_1(): u64 { + { + let gas_schedule_blob: vector = Vector(115, 115, 95, 112, 97, 99, 107, 101, 100, 32, 0, 0, 0, 0, 0, 0, 0); + M::vector_fold(gas_schedule_blob, Cast(0), |(sum: u64, addend: u8): (u64, u8)| Add(sum, Cast(addend))) + } + } + private fun test_2(): u64 { + { + let gas_schedule_blob: vector = Vector(115, 115, 95, 112, 97, 99, 107, 101, 100, 32, 0, 0, 0, 0, 0, 0, 0); + M::vector_fold(gas_schedule_blob, Cast(0), |(sum: u64, addend: u8): (u64, u8)| Add(sum, Cast(addend))) + } + } + private fun vector_fold(v: vector<#1>,init: #0,f: |(#0, #1)|#0): #0 { + { + let accu: Accumulator = init; + M::vector_for_each(v, |elem: Element| accu: Accumulator = (f)(accu, elem)); + accu + } + } + private fun vector_for_each(v: vector<#0>,f: |#0|) { + vector::reverse(Borrow(Mutable)(v)); + loop { + if Not(vector::is_empty(Borrow(Immutable)(v))) { + { + let e: Element = vector::pop_back(Borrow(Mutable)(v)); + (f)(e); + Tuple() + } + } else { + break + } + }; + Tuple() + } +} // end 0x12391283::M + + +// -- Model dump after env processor check recursive struct definition: +module 0x12391283::M { + use std::vector; + private fun test_1(): u64 { + { + let gas_schedule_blob: vector = Vector(115, 115, 95, 112, 97, 99, 107, 101, 100, 32, 0, 0, 0, 0, 0, 0, 0); + M::vector_fold(gas_schedule_blob, Cast(0), |(sum: u64, addend: u8): (u64, u8)| Add(sum, Cast(addend))) + } + } + private fun test_2(): u64 { + { + let gas_schedule_blob: vector = Vector(115, 115, 95, 112, 97, 99, 107, 101, 100, 32, 0, 0, 0, 0, 0, 0, 0); + M::vector_fold(gas_schedule_blob, Cast(0), |(sum: u64, addend: u8): (u64, u8)| Add(sum, Cast(addend))) + } + } + private fun vector_fold(v: vector<#1>,init: #0,f: |(#0, #1)|#0): #0 { + { + let accu: Accumulator = init; + M::vector_for_each(v, |elem: Element| accu: Accumulator = (f)(accu, elem)); + accu + } + } + private fun vector_for_each(v: vector<#0>,f: |#0|) { + vector::reverse(Borrow(Mutable)(v)); + loop { + if Not(vector::is_empty(Borrow(Immutable)(v))) { + { + let e: Element = vector::pop_back(Borrow(Mutable)(v)); + (f)(e); + Tuple() + } + } else { + break + } + }; + Tuple() + } +} // end 0x12391283::M + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x12391283::M { + use std::vector; + private fun test_1(): u64 { + { + let gas_schedule_blob: vector = Vector(115, 115, 95, 112, 97, 99, 107, 101, 100, 32, 0, 0, 0, 0, 0, 0, 0); + M::vector_fold(gas_schedule_blob, Cast(0), |(sum: u64, addend: u8): (u64, u8)| Add(sum, Cast(addend))) + } + } + private fun test_2(): u64 { + { + let gas_schedule_blob: vector = Vector(115, 115, 95, 112, 97, 99, 107, 101, 100, 32, 0, 0, 0, 0, 0, 0, 0); + M::vector_fold(gas_schedule_blob, Cast(0), |(sum: u64, addend: u8): (u64, u8)| Add(sum, Cast(addend))) + } + } + private fun vector_fold(v: vector<#1>,init: #0,f: |(#0, #1)|#0): #0 { + { + let accu: Accumulator = init; + M::vector_for_each(v, |elem: Element| accu: Accumulator = (f)(accu, elem)); + accu + } + } + private fun vector_for_each(v: vector<#0>,f: |#0|) { + vector::reverse(Borrow(Mutable)(v)); + loop { + if Not(vector::is_empty(Borrow(Immutable)(v))) { + { + let e: Element = vector::pop_back(Borrow(Mutable)(v)); + (f)(e); + Tuple() + } + } else { + break + } + }; + Tuple() + } +} // end 0x12391283::M + + +// -- Model dump after env processor unused struct params check: +module 0x12391283::M { + use std::vector; + private fun test_1(): u64 { + { + let gas_schedule_blob: vector = Vector(115, 115, 95, 112, 97, 99, 107, 101, 100, 32, 0, 0, 0, 0, 0, 0, 0); + M::vector_fold(gas_schedule_blob, Cast(0), |(sum: u64, addend: u8): (u64, u8)| Add(sum, Cast(addend))) + } + } + private fun test_2(): u64 { + { + let gas_schedule_blob: vector = Vector(115, 115, 95, 112, 97, 99, 107, 101, 100, 32, 0, 0, 0, 0, 0, 0, 0); + M::vector_fold(gas_schedule_blob, Cast(0), |(sum: u64, addend: u8): (u64, u8)| Add(sum, Cast(addend))) + } + } + private fun vector_fold(v: vector<#1>,init: #0,f: |(#0, #1)|#0): #0 { + { + let accu: Accumulator = init; + M::vector_for_each(v, |elem: Element| accu: Accumulator = (f)(accu, elem)); + accu + } + } + private fun vector_for_each(v: vector<#0>,f: |#0|) { + vector::reverse(Borrow(Mutable)(v)); + loop { + if Not(vector::is_empty(Borrow(Immutable)(v))) { + { + let e: Element = vector::pop_back(Borrow(Mutable)(v)); + (f)(e); + Tuple() + } + } else { + break + } + }; + Tuple() + } +} // end 0x12391283::M + + +// -- Model dump after env processor access and use check before inlining: +module 0x12391283::M { + use std::vector; + private fun test_1(): u64 { + { + let gas_schedule_blob: vector = Vector(115, 115, 95, 112, 97, 99, 107, 101, 100, 32, 0, 0, 0, 0, 0, 0, 0); + M::vector_fold(gas_schedule_blob, Cast(0), |(sum: u64, addend: u8): (u64, u8)| Add(sum, Cast(addend))) + } + } + private fun test_2(): u64 { + { + let gas_schedule_blob: vector = Vector(115, 115, 95, 112, 97, 99, 107, 101, 100, 32, 0, 0, 0, 0, 0, 0, 0); + M::vector_fold(gas_schedule_blob, Cast(0), |(sum: u64, addend: u8): (u64, u8)| Add(sum, Cast(addend))) + } + } + private fun vector_fold(v: vector<#1>,init: #0,f: |(#0, #1)|#0): #0 { + { + let accu: Accumulator = init; + M::vector_for_each(v, |elem: Element| accu: Accumulator = (f)(accu, elem)); + accu + } + } + private fun vector_for_each(v: vector<#0>,f: |#0|) { + vector::reverse(Borrow(Mutable)(v)); + loop { + if Not(vector::is_empty(Borrow(Immutable)(v))) { + { + let e: Element = vector::pop_back(Borrow(Mutable)(v)); + (f)(e); + Tuple() + } + } else { + break + } + }; + Tuple() + } +} // end 0x12391283::M + + +// -- Model dump after env processor inlining: +module 0x12391283::M { + use std::vector; + private fun test_1(): u64 { + { + let gas_schedule_blob: vector = Vector(115, 115, 95, 112, 97, 99, 107, 101, 100, 32, 0, 0, 0, 0, 0, 0, 0); + M::vector_fold(gas_schedule_blob, Cast(0), |(sum: u64, addend: u8): (u64, u8)| Add(sum, Cast(addend))) + } + } + private fun test_2(): u64 { + { + let gas_schedule_blob: vector = Vector(115, 115, 95, 112, 97, 99, 107, 101, 100, 32, 0, 0, 0, 0, 0, 0, 0); + M::vector_fold(gas_schedule_blob, Cast(0), |(sum: u64, addend: u8): (u64, u8)| Add(sum, Cast(addend))) + } + } + private fun vector_fold(v: vector<#1>,init: #0,f: |(#0, #1)|#0): #0 { + { + let accu: Accumulator = init; + M::vector_for_each(v, |elem: Element| accu: Accumulator = (f)(accu, elem)); + accu + } + } + private fun vector_for_each(v: vector<#0>,f: |#0|) { + vector::reverse(Borrow(Mutable)(v)); + loop { + if Not(vector::is_empty(Borrow(Immutable)(v))) { + { + let e: Element = vector::pop_back(Borrow(Mutable)(v)); + (f)(e); + Tuple() + } + } else { + break + } + }; + Tuple() + } +} // end 0x12391283::M + + +// -- Model dump after env processor access and use check after inlining: +module 0x12391283::M { + use std::vector; + private fun test_1(): u64 { + { + let gas_schedule_blob: vector = Vector(115, 115, 95, 112, 97, 99, 107, 101, 100, 32, 0, 0, 0, 0, 0, 0, 0); + M::vector_fold(gas_schedule_blob, Cast(0), |(sum: u64, addend: u8): (u64, u8)| Add(sum, Cast(addend))) + } + } + private fun test_2(): u64 { + { + let gas_schedule_blob: vector = Vector(115, 115, 95, 112, 97, 99, 107, 101, 100, 32, 0, 0, 0, 0, 0, 0, 0); + M::vector_fold(gas_schedule_blob, Cast(0), |(sum: u64, addend: u8): (u64, u8)| Add(sum, Cast(addend))) + } + } + private fun vector_fold(v: vector<#1>,init: #0,f: |(#0, #1)|#0): #0 { + { + let accu: Accumulator = init; + M::vector_for_each(v, |elem: Element| accu: Accumulator = (f)(accu, elem)); + accu + } + } + private fun vector_for_each(v: vector<#0>,f: |#0|) { + vector::reverse(Borrow(Mutable)(v)); + loop { + if Not(vector::is_empty(Borrow(Immutable)(v))) { + { + let e: Element = vector::pop_back(Borrow(Mutable)(v)); + (f)(e); + Tuple() + } + } else { + break + } + }; + Tuple() + } +} // end 0x12391283::M + + +// -- Model dump after env processor acquires check: +module 0x12391283::M { + use std::vector; + private fun test_1(): u64 { + { + let gas_schedule_blob: vector = Vector(115, 115, 95, 112, 97, 99, 107, 101, 100, 32, 0, 0, 0, 0, 0, 0, 0); + M::vector_fold(gas_schedule_blob, Cast(0), |(sum: u64, addend: u8): (u64, u8)| Add(sum, Cast(addend))) + } + } + private fun test_2(): u64 { + { + let gas_schedule_blob: vector = Vector(115, 115, 95, 112, 97, 99, 107, 101, 100, 32, 0, 0, 0, 0, 0, 0, 0); + M::vector_fold(gas_schedule_blob, Cast(0), |(sum: u64, addend: u8): (u64, u8)| Add(sum, Cast(addend))) + } + } + private fun vector_fold(v: vector<#1>,init: #0,f: |(#0, #1)|#0): #0 { + { + let accu: Accumulator = init; + M::vector_for_each(v, |elem: Element| accu: Accumulator = (f)(accu, elem)); + accu + } + } + private fun vector_for_each(v: vector<#0>,f: |#0|) { + vector::reverse(Borrow(Mutable)(v)); + loop { + if Not(vector::is_empty(Borrow(Immutable)(v))) { + { + let e: Element = vector::pop_back(Borrow(Mutable)(v)); + (f)(e); + Tuple() + } + } else { + break + } + }; + Tuple() + } +} // end 0x12391283::M + + +// -- Model dump after env processor simplifier: +module 0x12391283::M { + use std::vector; + private fun test_1(): u64 { + M::vector_fold([Number(115), Number(115), Number(95), Number(112), Number(97), Number(99), Number(107), Number(101), Number(100), Number(32), Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), Number(0)], 0, |(sum: u64, addend: u8): (u64, u8)| Add(sum, Cast(addend))) + } + private fun test_2(): u64 { + M::vector_fold([Number(115), Number(115), Number(95), Number(112), Number(97), Number(99), Number(107), Number(101), Number(100), Number(32), Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), Number(0)], 0, |(sum: u64, addend: u8): (u64, u8)| Add(sum, Cast(addend))) + } + private fun vector_fold(v: vector<#1>,init: #0,f: |(#0, #1)|#0): #0 { + { + let accu: Accumulator = init; + M::vector_for_each(v, |elem: Element| accu: Accumulator = (f)(accu, elem)); + accu + } + } + private fun vector_for_each(v: vector<#0>,f: |#0|) { + vector::reverse(Borrow(Mutable)(v)); + loop { + if Not(vector::is_empty(Borrow(Immutable)(v))) { + { + let e: Element = vector::pop_back(Borrow(Mutable)(v)); + (f)(e); + Tuple() + } + } else { + break + } + }; + Tuple() + } +} // end 0x12391283::M + + + +Diagnostics: +error: captured variable `accu` cannot be modified inside of a lambda + ┌─ tests/lambda/inline-parity/lambda_cast.move:18:35 + │ +18 │ vector_for_each(v, |elem| accu = f(accu, elem)); + │ ^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast.move new file mode 100644 index 00000000000000..28e6cb88a9e82d --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast.move @@ -0,0 +1,35 @@ +module 0x12391283::M { + use std::vector; + + fun vector_for_each(v: vector, f: |Element|) { + vector::reverse(&mut v); // We need to reverse the vector to consume it efficiently + while (!vector::is_empty(&v)) { + let e = vector::pop_back(&mut v); + f(e); + }; + } + + fun vector_fold( + v: vector, + init: Accumulator, + f: |Accumulator,Element|Accumulator + ): Accumulator { + let accu = init; + vector_for_each(v, |elem| accu = f(accu, elem)); + accu + } + + fun test_1() : u64 { + let gas_schedule_blob: vector = vector[ + 115, 115, 95, 112, 97, 99, 107, 101, 100, 32, 0, 0, 0, 0, 0, 0, 0, + ]; + vector_fold(gas_schedule_blob, (0 as u64), |sum, addend| sum + (addend as u64)) + } + + fun test_2() : u64 { + let gas_schedule_blob: vector = vector[ + 115, 115, 95, 112, 97, 99, 107, 101, 100, 32, 0, 0, 0, 0, 0, 0, 0, + ]; + vector_fold(gas_schedule_blob, (0 as u64), |sum, addend| sum + (addend as u64)) + } +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.exp new file mode 100644 index 00000000000000..d9cd9d072137ba --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: cannot pass `|(u64, integer)|u64` to a function which expects argument of type `|(u64, vector)|u64` + ┌─ tests/lambda/inline-parity/lambda_cast_err.move:26:52 + │ +26 │ vector_fold(gas_schedule_blob, (0 as u64), |sum, addend| sum + (addend as u64)) + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.lambda.exp new file mode 100644 index 00000000000000..d9cd9d072137ba --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.lambda.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: cannot pass `|(u64, integer)|u64` to a function which expects argument of type `|(u64, vector)|u64` + ┌─ tests/lambda/inline-parity/lambda_cast_err.move:26:52 + │ +26 │ vector_fold(gas_schedule_blob, (0 as u64), |sum, addend| sum + (addend as u64)) + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.move new file mode 100644 index 00000000000000..0ed5c353c6a585 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.move @@ -0,0 +1,28 @@ +module 0x12391283::M { + use std::vector; + + fun vector_for_each(v: vector, f: |Element|) { + vector::reverse(&mut v); // We need to reverse the vector to consume it efficiently + while (!vector::is_empty(&v)) { + let e = vector::pop_back(&mut v); + f(e); + }; + } + + fun vector_fold( + v: vector, + init: Accumulator, + f: |Accumulator,Element|Accumulator + ): Accumulator { + let accu = init; + vector_for_each(v, |elem| accu = f(accu, elem)); + accu + } + + fun test(gas_schedule_blob: vector) : u64 { + let gas_schedule_blob: vector> = vector[ + vector[115], vector[115], vector[95], + ]; + vector_fold(gas_schedule_blob, (0 as u64), |sum, addend| sum + (addend as u64)) + } +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_no_param.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_no_param.exp new file mode 100644 index 00000000000000..dd2f576e96129f --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_no_param.exp @@ -0,0 +1,13 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `m::foo` has a function parameter: + ┌─ tests/lambda/inline-parity/lambda_no_param.move:2:9 + │ +2 │ fun foo(f: ||) { + │ ^^^ - Parameter `f` has function-valued type `|()|`. + +error: Only inline functions may have function-typed parameters, but non-inline function `m::bar` has a function parameter: + ┌─ tests/lambda/inline-parity/lambda_no_param.move:10:9 + │ +10 │ fun bar(f:||u64): u64 { + │ ^^^ - Parameter `f` has function-valued type `|()|u64`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_no_param.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_no_param.lambda.exp new file mode 100644 index 00000000000000..eb23c97b263b2e --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_no_param.lambda.exp @@ -0,0 +1,309 @@ +// -- Model dump before env processor pipeline: +module 0xdecafbad::m { + private fun bar(f: |()|u64): u64 { + (f)() + } + private fun foo(f: |()|) { + (f)(); + Tuple() + } + public fun one() { + m::foo(|(): ()| Tuple()); + Tuple() + } + public fun two(x: u64): u64 { + m::bar(|(): ()| x) + } +} // end 0xdecafbad::m + + +// -- Model dump after env processor unused checks: +module 0xdecafbad::m { + private fun bar(f: |()|u64): u64 { + (f)() + } + private fun foo(f: |()|) { + (f)(); + Tuple() + } + public fun one() { + m::foo(|(): ()| Tuple()); + Tuple() + } + public fun two(x: u64): u64 { + m::bar(|(): ()| x) + } +} // end 0xdecafbad::m + + +// -- Model dump after env processor type parameter check: +module 0xdecafbad::m { + private fun bar(f: |()|u64): u64 { + (f)() + } + private fun foo(f: |()|) { + (f)(); + Tuple() + } + public fun one() { + m::foo(|(): ()| Tuple()); + Tuple() + } + public fun two(x: u64): u64 { + m::bar(|(): ()| x) + } +} // end 0xdecafbad::m + + +// -- Model dump after env processor check recursive struct definition: +module 0xdecafbad::m { + private fun bar(f: |()|u64): u64 { + (f)() + } + private fun foo(f: |()|) { + (f)(); + Tuple() + } + public fun one() { + m::foo(|(): ()| Tuple()); + Tuple() + } + public fun two(x: u64): u64 { + m::bar(|(): ()| x) + } +} // end 0xdecafbad::m + + +// -- Model dump after env processor check cyclic type instantiation: +module 0xdecafbad::m { + private fun bar(f: |()|u64): u64 { + (f)() + } + private fun foo(f: |()|) { + (f)(); + Tuple() + } + public fun one() { + m::foo(|(): ()| Tuple()); + Tuple() + } + public fun two(x: u64): u64 { + m::bar(|(): ()| x) + } +} // end 0xdecafbad::m + + +// -- Model dump after env processor unused struct params check: +module 0xdecafbad::m { + private fun bar(f: |()|u64): u64 { + (f)() + } + private fun foo(f: |()|) { + (f)(); + Tuple() + } + public fun one() { + m::foo(|(): ()| Tuple()); + Tuple() + } + public fun two(x: u64): u64 { + m::bar(|(): ()| x) + } +} // end 0xdecafbad::m + + +// -- Model dump after env processor access and use check before inlining: +module 0xdecafbad::m { + private fun bar(f: |()|u64): u64 { + (f)() + } + private fun foo(f: |()|) { + (f)(); + Tuple() + } + public fun one() { + m::foo(|(): ()| Tuple()); + Tuple() + } + public fun two(x: u64): u64 { + m::bar(|(): ()| x) + } +} // end 0xdecafbad::m + + +// -- Model dump after env processor inlining: +module 0xdecafbad::m { + private fun bar(f: |()|u64): u64 { + (f)() + } + private fun foo(f: |()|) { + (f)(); + Tuple() + } + public fun one() { + m::foo(|(): ()| Tuple()); + Tuple() + } + public fun two(x: u64): u64 { + m::bar(|(): ()| x) + } +} // end 0xdecafbad::m + + +// -- Model dump after env processor access and use check after inlining: +module 0xdecafbad::m { + private fun bar(f: |()|u64): u64 { + (f)() + } + private fun foo(f: |()|) { + (f)(); + Tuple() + } + public fun one() { + m::foo(|(): ()| Tuple()); + Tuple() + } + public fun two(x: u64): u64 { + m::bar(|(): ()| x) + } +} // end 0xdecafbad::m + + +// -- Model dump after env processor acquires check: +module 0xdecafbad::m { + private fun bar(f: |()|u64): u64 { + (f)() + } + private fun foo(f: |()|) { + (f)(); + Tuple() + } + public fun one() { + m::foo(|(): ()| Tuple()); + Tuple() + } + public fun two(x: u64): u64 { + m::bar(|(): ()| x) + } +} // end 0xdecafbad::m + + +// -- Model dump after env processor simplifier: +module 0xdecafbad::m { + private fun bar(f: |()|u64): u64 { + (f)() + } + private fun foo(f: |()|) { + (f)(); + Tuple() + } + public fun one() { + m::foo(|(): ()| Tuple()); + Tuple() + } + public fun two(x: u64): u64 { + m::bar(|(): ()| x) + } +} // end 0xdecafbad::m + + +// -- Model dump after env processor lambda-lifting: +module 0xdecafbad::m { + private fun bar(f: |()|u64): u64 { + (f)() + } + private fun foo(f: |()|) { + (f)(); + Tuple() + } + public fun one() { + m::foo(closure m::one$lambda$1()); + Tuple() + } + public fun two(x: u64): u64 { + m::bar(closure m::two$lambda$1(x)) + } + private fun one$lambda$1() { + Tuple() + } + private fun two$lambda$1(x: u64): u64 { + x + } +} // end 0xdecafbad::m + + +// -- Model dump after env processor specification checker: +module 0xdecafbad::m { + private fun bar(f: |()|u64): u64 { + (f)() + } + private fun foo(f: |()|) { + (f)(); + Tuple() + } + public fun one() { + m::foo(closure m::one$lambda$1()); + Tuple() + } + public fun two(x: u64): u64 { + m::bar(closure m::two$lambda$1(x)) + } + private fun one$lambda$1() { + Tuple() + } + private fun two$lambda$1(x: u64): u64 { + x + } +} // end 0xdecafbad::m + + +// -- Model dump after env processor specification rewriter: +module 0xdecafbad::m { + private fun bar(f: |()|u64): u64 { + (f)() + } + private fun foo(f: |()|) { + (f)(); + Tuple() + } + public fun one() { + m::foo(closure m::one$lambda$1()); + Tuple() + } + public fun two(x: u64): u64 { + m::bar(closure m::two$lambda$1(x)) + } + private fun one$lambda$1() { + Tuple() + } + private fun two$lambda$1(x: u64): u64 { + x + } +} // end 0xdecafbad::m + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/lambda_no_param.move:3:9 + │ +3 │ f(); + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/lambda_no_param.move:7:13 + │ +7 │ foo(|| {}); + │ ^^^^^ + +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/lambda_no_param.move:11:9 + │ +11 │ f() + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/lambda_no_param.move:15:13 + │ +15 │ bar(||x) + │ ^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_no_param.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_no_param.move new file mode 100644 index 00000000000000..8ada4a53d6d566 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_no_param.move @@ -0,0 +1,17 @@ +module 0xdecafbad::m { + fun foo(f: ||) { + f(); + } + + public fun one() { + foo(|| {}); + } + + fun bar(f:||u64): u64 { + f() + } + + public fun two(x:u64): u64 { + bar(||x) + } +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param.exp new file mode 100644 index 00000000000000..7be9a4290fcc3f --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param.exp @@ -0,0 +1,25 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `LambdaParam::inline_apply` has a function parameter: + ┌─ tests/lambda/inline-parity/lambda_param.move:2:16 + │ +2 │ public fun inline_apply(f: |u64|u64, b: u64) : u64 { + │ ^^^^^^^^^^^^ - Parameter `f` has function-valued type `|u64|u64`. + +error: Only inline functions may have function-typed parameters, but non-inline function `LambdaParam::inline_apply2` has a function parameter: + ┌─ tests/lambda/inline-parity/lambda_param.move:6:16 + │ +6 │ public fun inline_apply2(f: |u64|u64, b: u64) : u64 { + │ ^^^^^^^^^^^^^ - Parameter `f` has function-valued type `|u64|u64`. + +error: Only inline functions may have function-typed parameters, but non-inline function `LambdaParam::inline_apply3` has a function parameter: + ┌─ tests/lambda/inline-parity/lambda_param.move:10:16 + │ +10 │ public fun inline_apply3(f: |u64|u64, b: u64) : u64 { + │ ^^^^^^^^^^^^^ - Parameter `f` has function-valued type `|u64|u64`. + +error: Only inline functions may have function-typed parameters, but non-inline function `LambdaParam::inline_apply4` has a function parameter: + ┌─ tests/lambda/inline-parity/lambda_param.move:14:16 + │ +14 │ public fun inline_apply4(_f: |u64|u64, b: u64) : u64 { + │ ^^^^^^^^^^^^^ -- Parameter `_f` has function-valued type `|u64|u64`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param.lambda.exp new file mode 100644 index 00000000000000..b3587c0f077efc --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param.lambda.exp @@ -0,0 +1,837 @@ +// -- Model dump before env processor pipeline: +module 0x42::LambdaParam { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply(f, b) + } + public fun inline_apply3(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply4(f, b) + } + public fun inline_apply4(_f: |u64|u64,b: u64): u64 { + b + } + private fun test_lambda_symbol_param1() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + private fun test_lambda_symbol_param2() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply3(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + } + } +} // end 0x42::LambdaParam + + +// -- Model dump after env processor unused checks: +module 0x42::LambdaParam { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply(f, b) + } + public fun inline_apply3(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply4(f, b) + } + public fun inline_apply4(_f: |u64|u64,b: u64): u64 { + b + } + private fun test_lambda_symbol_param1() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + private fun test_lambda_symbol_param2() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply3(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + } + } +} // end 0x42::LambdaParam + + +// -- Model dump after env processor type parameter check: +module 0x42::LambdaParam { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply(f, b) + } + public fun inline_apply3(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply4(f, b) + } + public fun inline_apply4(_f: |u64|u64,b: u64): u64 { + b + } + private fun test_lambda_symbol_param1() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + private fun test_lambda_symbol_param2() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply3(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + } + } +} // end 0x42::LambdaParam + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::LambdaParam { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply(f, b) + } + public fun inline_apply3(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply4(f, b) + } + public fun inline_apply4(_f: |u64|u64,b: u64): u64 { + b + } + private fun test_lambda_symbol_param1() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + private fun test_lambda_symbol_param2() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply3(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + } + } +} // end 0x42::LambdaParam + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::LambdaParam { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply(f, b) + } + public fun inline_apply3(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply4(f, b) + } + public fun inline_apply4(_f: |u64|u64,b: u64): u64 { + b + } + private fun test_lambda_symbol_param1() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + private fun test_lambda_symbol_param2() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply3(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + } + } +} // end 0x42::LambdaParam + + +// -- Model dump after env processor unused struct params check: +module 0x42::LambdaParam { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply(f, b) + } + public fun inline_apply3(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply4(f, b) + } + public fun inline_apply4(_f: |u64|u64,b: u64): u64 { + b + } + private fun test_lambda_symbol_param1() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + private fun test_lambda_symbol_param2() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply3(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + } + } +} // end 0x42::LambdaParam + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::LambdaParam { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply(f, b) + } + public fun inline_apply3(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply4(f, b) + } + public fun inline_apply4(_f: |u64|u64,b: u64): u64 { + b + } + private fun test_lambda_symbol_param1() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + private fun test_lambda_symbol_param2() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply3(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + } + } +} // end 0x42::LambdaParam + + +// -- Model dump after env processor inlining: +module 0x42::LambdaParam { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply(f, b) + } + public fun inline_apply3(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply4(f, b) + } + public fun inline_apply4(_f: |u64|u64,b: u64): u64 { + b + } + private fun test_lambda_symbol_param1() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + private fun test_lambda_symbol_param2() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply3(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + } + } +} // end 0x42::LambdaParam + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::LambdaParam { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply(f, b) + } + public fun inline_apply3(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply4(f, b) + } + public fun inline_apply4(_f: |u64|u64,b: u64): u64 { + b + } + private fun test_lambda_symbol_param1() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + private fun test_lambda_symbol_param2() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply3(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + } + } +} // end 0x42::LambdaParam + + +// -- Model dump after env processor acquires check: +module 0x42::LambdaParam { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply(f, b) + } + public fun inline_apply3(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply4(f, b) + } + public fun inline_apply4(_f: |u64|u64,b: u64): u64 { + b + } + private fun test_lambda_symbol_param1() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + private fun test_lambda_symbol_param2() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply3(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + } + } +} // end 0x42::LambdaParam + + +// -- Model dump after env processor simplifier: +module 0x42::LambdaParam { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply(f, b) + } + public fun inline_apply3(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply4(f, b) + } + public fun inline_apply4(_f: |u64|u64,b: u64): u64 { + b + } + private fun test_lambda_symbol_param1() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + private fun test_lambda_symbol_param2() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply3(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + } + } +} // end 0x42::LambdaParam + + +// -- Model dump after env processor lambda-lifting: +module 0x42::LambdaParam { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply(f, b) + } + public fun inline_apply3(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply4(f, b) + } + public fun inline_apply4(_f: |u64|u64,b: u64): u64 { + b + } + private fun test_lambda_symbol_param1() { + { + let a: u64 = LambdaParam::inline_apply2(closure LambdaParam::test_lambda_symbol_param1$lambda$1(), 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + private fun test_lambda_symbol_param2() { + { + let a: u64 = LambdaParam::inline_apply2(closure LambdaParam::test_lambda_symbol_param2$lambda$1(), 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply(closure LambdaParam::test_lambda_symbol_param2$lambda$2(), 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply3(closure LambdaParam::test_lambda_symbol_param2$lambda$3(), 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + } + } + private fun test_lambda_symbol_param1$lambda$1(x: u64): u64 { + x + } + private fun test_lambda_symbol_param2$lambda$1(x: u64): u64 { + x + } + private fun test_lambda_symbol_param2$lambda$2(x: u64): u64 { + x + } + private fun test_lambda_symbol_param2$lambda$3(x: u64): u64 { + x + } +} // end 0x42::LambdaParam + + +// -- Model dump after env processor specification checker: +module 0x42::LambdaParam { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply(f, b) + } + public fun inline_apply3(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply4(f, b) + } + public fun inline_apply4(_f: |u64|u64,b: u64): u64 { + b + } + private fun test_lambda_symbol_param1() { + { + let a: u64 = LambdaParam::inline_apply2(closure LambdaParam::test_lambda_symbol_param1$lambda$1(), 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + private fun test_lambda_symbol_param2() { + { + let a: u64 = LambdaParam::inline_apply2(closure LambdaParam::test_lambda_symbol_param2$lambda$1(), 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply(closure LambdaParam::test_lambda_symbol_param2$lambda$2(), 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply3(closure LambdaParam::test_lambda_symbol_param2$lambda$3(), 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + } + } + private fun test_lambda_symbol_param1$lambda$1(x: u64): u64 { + x + } + private fun test_lambda_symbol_param2$lambda$1(x: u64): u64 { + x + } + private fun test_lambda_symbol_param2$lambda$2(x: u64): u64 { + x + } + private fun test_lambda_symbol_param2$lambda$3(x: u64): u64 { + x + } +} // end 0x42::LambdaParam + + +// -- Model dump after env processor specification rewriter: +module 0x42::LambdaParam { + public fun inline_apply(f: |u64|u64,b: u64): u64 { + (f)(b) + } + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply(f, b) + } + public fun inline_apply3(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply4(f, b) + } + public fun inline_apply4(_f: |u64|u64,b: u64): u64 { + b + } + private fun test_lambda_symbol_param1() { + { + let a: u64 = LambdaParam::inline_apply2(closure LambdaParam::test_lambda_symbol_param1$lambda$1(), 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + private fun test_lambda_symbol_param2() { + { + let a: u64 = LambdaParam::inline_apply2(closure LambdaParam::test_lambda_symbol_param2$lambda$1(), 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply(closure LambdaParam::test_lambda_symbol_param2$lambda$2(), 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply3(closure LambdaParam::test_lambda_symbol_param2$lambda$3(), 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + } + } + private fun test_lambda_symbol_param1$lambda$1(x: u64): u64 { + x + } + private fun test_lambda_symbol_param2$lambda$1(x: u64): u64 { + x + } + private fun test_lambda_symbol_param2$lambda$2(x: u64): u64 { + x + } + private fun test_lambda_symbol_param2$lambda$3(x: u64): u64 { + x + } +} // end 0x42::LambdaParam + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/lambda_param.move:3:2 + │ +3 │ f(b) + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/lambda_param.move:19:24 + │ +19 │ let a = inline_apply2(|x| x, 3); + │ ^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/lambda_param.move:24:24 + │ +24 │ let a = inline_apply2(|x| x, 3); + │ ^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/lambda_param.move:26:23 + │ +26 │ let b = inline_apply(|x| x, 3); + │ ^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/lambda_param.move:28:24 + │ +28 │ let b = inline_apply3(|x| x, 3); + │ ^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param.move new file mode 100644 index 00000000000000..af1abb2b2aec8f --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param.move @@ -0,0 +1,31 @@ +module 0x42::LambdaParam { + public fun inline_apply(f: |u64|u64, b: u64) : u64 { + f(b) + } + + public fun inline_apply2(f: |u64|u64, b: u64) : u64 { + inline_apply(f, b) + } + + public fun inline_apply3(f: |u64|u64, b: u64) : u64 { + inline_apply4(f, b) + } + + public fun inline_apply4(_f: |u64|u64, b: u64) : u64 { + b + } + + fun test_lambda_symbol_param1() { + let a = inline_apply2(|x| x, 3); + assert!(a == 3, 0); + } + + fun test_lambda_symbol_param2() { + let a = inline_apply2(|x| x, 3); + assert!(a == 3, 0); + let b = inline_apply(|x| x, 3); + assert!(b == 3, 0); + let b = inline_apply3(|x| x, 3); + assert!(b == 3, 0); + } +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.exp new file mode 100644 index 00000000000000..33468b26f118d7 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.exp @@ -0,0 +1,10 @@ + +Diagnostics: +error: cannot pass `|u64|u64` to a function which expects argument of type `|u64|` + ┌─ tests/lambda/inline-parity/lambda_param_mismatch.move:20:32 + │ +20 │ vector_for_each(input, |item| { + │ ╭────────────────────────────────^ +21 │ │ vector::remove(&mut mut_ref.inner, item) +22 │ │ }) + │ ╰─────────^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.lambda.exp new file mode 100644 index 00000000000000..33468b26f118d7 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.lambda.exp @@ -0,0 +1,10 @@ + +Diagnostics: +error: cannot pass `|u64|u64` to a function which expects argument of type `|u64|` + ┌─ tests/lambda/inline-parity/lambda_param_mismatch.move:20:32 + │ +20 │ vector_for_each(input, |item| { + │ ╭────────────────────────────────^ +21 │ │ vector::remove(&mut mut_ref.inner, item) +22 │ │ }) + │ ╰─────────^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.move new file mode 100644 index 00000000000000..4bc45138a5a0d3 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.move @@ -0,0 +1,24 @@ +module 0x42::LambdaParam { + use std::vector; + use std::signer; + + struct VectorExample has key { + inner: vector + } + + fun vector_for_each(v: vector, f: |Element|) { + vector::reverse(&mut v); // We need to reverse the vector to consume it efficiently + while (!vector::is_empty(&v)) { + let e = vector::pop_back(&mut v); + f(e); + }; + } + + entry fun remove_vector(caller: &signer, input: vector) acquires VectorExample { + let caller_add = signer::address_of(caller); + let mut_ref = borrow_global_mut(caller_add); + vector_for_each(input, |item| { + vector::remove(&mut mut_ref.inner, item) + }) + } +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_typed.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_typed.exp new file mode 100644 index 00000000000000..aa45b4ca4179f2 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/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/lambda/inline-parity/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/lambda/inline-parity/lambda_param_typed.move:11:16 + │ +11 │ inline_apply4(f, b) + │ ^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_typed.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_typed.lambda.exp new file mode 100644 index 00000000000000..06d68ac437dd49 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_typed.lambda.exp @@ -0,0 +1,398 @@ +// -- Model dump before env processor pipeline: +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 { + LambdaParam::inline_apply(f, b) + } + public inline fun inline_apply3(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply4(f, b) + } + public inline fun inline_apply4(_f: |u64|u64,b: u64): u64 { + b + } + private fun test_lambda_symbol_param1() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + private fun test_lambda_symbol_param2() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply3(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + } + } +} // end 0x42::LambdaParam + + +// -- Model dump after env processor unused checks: +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 { + LambdaParam::inline_apply(f, b) + } + public inline fun inline_apply3(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply4(f, b) + } + public inline fun inline_apply4(_f: |u64|u64,b: u64): u64 { + b + } + private fun test_lambda_symbol_param1() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + private fun test_lambda_symbol_param2() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply3(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + } + } +} // end 0x42::LambdaParam + + +// -- Model dump after env processor type parameter check: +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 { + LambdaParam::inline_apply(f, b) + } + public inline fun inline_apply3(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply4(f, b) + } + public inline fun inline_apply4(_f: |u64|u64,b: u64): u64 { + b + } + private fun test_lambda_symbol_param1() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + private fun test_lambda_symbol_param2() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply3(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + } + } +} // end 0x42::LambdaParam + + +// -- Model dump after env processor check recursive struct definition: +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 { + LambdaParam::inline_apply(f, b) + } + public inline fun inline_apply3(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply4(f, b) + } + public inline fun inline_apply4(_f: |u64|u64,b: u64): u64 { + b + } + private fun test_lambda_symbol_param1() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + private fun test_lambda_symbol_param2() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply3(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + } + } +} // end 0x42::LambdaParam + + +// -- Model dump after env processor check cyclic type instantiation: +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 { + LambdaParam::inline_apply(f, b) + } + public inline fun inline_apply3(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply4(f, b) + } + public inline fun inline_apply4(_f: |u64|u64,b: u64): u64 { + b + } + private fun test_lambda_symbol_param1() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + private fun test_lambda_symbol_param2() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply3(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + } + } +} // end 0x42::LambdaParam + + +// -- Model dump after env processor unused struct params check: +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 { + LambdaParam::inline_apply(f, b) + } + public inline fun inline_apply3(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply4(f, b) + } + public inline fun inline_apply4(_f: |u64|u64,b: u64): u64 { + b + } + private fun test_lambda_symbol_param1() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + private fun test_lambda_symbol_param2() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply3(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + } + } +} // end 0x42::LambdaParam + + +// -- Model dump after env processor access and use check before inlining: +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 { + LambdaParam::inline_apply(f, b) + } + public inline fun inline_apply3(f: |u64|u64,b: u64): u64 { + LambdaParam::inline_apply4(f, b) + } + public inline fun inline_apply4(_f: |u64|u64,b: u64): u64 { + b + } + private fun test_lambda_symbol_param1() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + private fun test_lambda_symbol_param2() { + { + let a: u64 = LambdaParam::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + { + let b: u64 = LambdaParam::inline_apply3(|x: u64| x, 3); + if Eq(b, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + } + } +} // end 0x42::LambdaParam + + + +Diagnostics: +error: Currently, a function-typed parameter to an inline function must be a literal lambda expression + ┌─ tests/lambda/inline-parity/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/lambda/inline-parity/lambda_param_typed.move:11:16 + │ +11 │ inline_apply4(f, b) + │ ^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_typed.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_typed.move new file mode 100644 index 00000000000000..98e5b59e65ddb6 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/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/lambda/inline-parity/lambda_return.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_return.exp new file mode 100644 index 00000000000000..a4ecd07b9563cc --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_return.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `LambdaReturn::inline_apply2` has a function parameter: + ┌─ tests/lambda/inline-parity/lambda_return.move:2:16 + │ +2 │ public fun inline_apply2(f: |u64|u64, b: u64) : u64 { + │ ^^^^^^^^^^^^^ - Parameter `f` has function-valued type `|u64|u64`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_return.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_return.lambda.exp new file mode 100644 index 00000000000000..2b9ffb4ba41606 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_return.lambda.exp @@ -0,0 +1,288 @@ +// -- Model dump before env processor pipeline: +module 0x42::LambdaReturn { + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + return (f)(b) + } + private fun test_lambda_symbol_param() { + { + let a: u64 = LambdaReturn::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaReturn + + +// -- Model dump after env processor unused checks: +module 0x42::LambdaReturn { + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + return (f)(b) + } + private fun test_lambda_symbol_param() { + { + let a: u64 = LambdaReturn::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaReturn + + +// -- Model dump after env processor type parameter check: +module 0x42::LambdaReturn { + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + return (f)(b) + } + private fun test_lambda_symbol_param() { + { + let a: u64 = LambdaReturn::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaReturn + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::LambdaReturn { + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + return (f)(b) + } + private fun test_lambda_symbol_param() { + { + let a: u64 = LambdaReturn::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaReturn + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::LambdaReturn { + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + return (f)(b) + } + private fun test_lambda_symbol_param() { + { + let a: u64 = LambdaReturn::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaReturn + + +// -- Model dump after env processor unused struct params check: +module 0x42::LambdaReturn { + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + return (f)(b) + } + private fun test_lambda_symbol_param() { + { + let a: u64 = LambdaReturn::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaReturn + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::LambdaReturn { + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + return (f)(b) + } + private fun test_lambda_symbol_param() { + { + let a: u64 = LambdaReturn::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaReturn + + +// -- Model dump after env processor inlining: +module 0x42::LambdaReturn { + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + return (f)(b) + } + private fun test_lambda_symbol_param() { + { + let a: u64 = LambdaReturn::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaReturn + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::LambdaReturn { + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + return (f)(b) + } + private fun test_lambda_symbol_param() { + { + let a: u64 = LambdaReturn::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaReturn + + +// -- Model dump after env processor acquires check: +module 0x42::LambdaReturn { + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + return (f)(b) + } + private fun test_lambda_symbol_param() { + { + let a: u64 = LambdaReturn::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaReturn + + +// -- Model dump after env processor simplifier: +module 0x42::LambdaReturn { + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + return (f)(b) + } + private fun test_lambda_symbol_param() { + { + let a: u64 = LambdaReturn::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaReturn + + +// -- Model dump after env processor lambda-lifting: +module 0x42::LambdaReturn { + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + return (f)(b) + } + private fun test_lambda_symbol_param() { + { + let a: u64 = LambdaReturn::inline_apply2(closure LambdaReturn::test_lambda_symbol_param$lambda$1(), 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + private fun test_lambda_symbol_param$lambda$1(x: u64): u64 { + x + } +} // end 0x42::LambdaReturn + + +// -- Model dump after env processor specification checker: +module 0x42::LambdaReturn { + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + return (f)(b) + } + private fun test_lambda_symbol_param() { + { + let a: u64 = LambdaReturn::inline_apply2(closure LambdaReturn::test_lambda_symbol_param$lambda$1(), 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + private fun test_lambda_symbol_param$lambda$1(x: u64): u64 { + x + } +} // end 0x42::LambdaReturn + + +// -- Model dump after env processor specification rewriter: +module 0x42::LambdaReturn { + public fun inline_apply2(f: |u64|u64,b: u64): u64 { + return (f)(b) + } + private fun test_lambda_symbol_param() { + { + let a: u64 = LambdaReturn::inline_apply2(closure LambdaReturn::test_lambda_symbol_param$lambda$1(), 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } + private fun test_lambda_symbol_param$lambda$1(x: u64): u64 { + x + } +} // end 0x42::LambdaReturn + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/lambda_return.move:3:9 + │ +3 │ return f(b) + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/lambda_return.move:7:24 + │ +7 │ let a = inline_apply2(|x| { x }, 3); + │ ^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_return.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_return.move new file mode 100644 index 00000000000000..a773d9be9941a2 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_return.move @@ -0,0 +1,10 @@ +module 0x42::LambdaReturn { + public fun inline_apply2(f: |u64|u64, b: u64) : u64 { + return f(b) + } + + fun test_lambda_symbol_param() { + let a = inline_apply2(|x| { x }, 3); + assert!(a == 3, 0); + } +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_return_typed.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_return_typed.exp new file mode 100644 index 00000000000000..441eefbd8cb9c9 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_return_typed.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Return not currently supported in inline functions + ┌─ tests/lambda/inline-parity/lambda_return_typed.move:3:2 + │ +3 │ return f(b) + │ ^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_return_typed.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_return_typed.lambda.exp new file mode 100644 index 00000000000000..5fd4d9134b3d01 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_return_typed.lambda.exp @@ -0,0 +1,140 @@ +// -- Model dump before env processor pipeline: +module 0x42::LambdaReturn { + public inline fun inline_apply2(f: |u64|u64,b: u64): u64 { + return (f)(b) + } + private fun test_lambda_symbol_param() { + { + let a: u64 = LambdaReturn::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaReturn + + +// -- Model dump after env processor unused checks: +module 0x42::LambdaReturn { + public inline fun inline_apply2(f: |u64|u64,b: u64): u64 { + return (f)(b) + } + private fun test_lambda_symbol_param() { + { + let a: u64 = LambdaReturn::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaReturn + + +// -- Model dump after env processor type parameter check: +module 0x42::LambdaReturn { + public inline fun inline_apply2(f: |u64|u64,b: u64): u64 { + return (f)(b) + } + private fun test_lambda_symbol_param() { + { + let a: u64 = LambdaReturn::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaReturn + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::LambdaReturn { + public inline fun inline_apply2(f: |u64|u64,b: u64): u64 { + return (f)(b) + } + private fun test_lambda_symbol_param() { + { + let a: u64 = LambdaReturn::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaReturn + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::LambdaReturn { + public inline fun inline_apply2(f: |u64|u64,b: u64): u64 { + return (f)(b) + } + private fun test_lambda_symbol_param() { + { + let a: u64 = LambdaReturn::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaReturn + + +// -- Model dump after env processor unused struct params check: +module 0x42::LambdaReturn { + public inline fun inline_apply2(f: |u64|u64,b: u64): u64 { + return (f)(b) + } + private fun test_lambda_symbol_param() { + { + let a: u64 = LambdaReturn::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaReturn + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::LambdaReturn { + public inline fun inline_apply2(f: |u64|u64,b: u64): u64 { + return (f)(b) + } + private fun test_lambda_symbol_param() { + { + let a: u64 = LambdaReturn::inline_apply2(|x: u64| x, 3); + if Eq(a, 3) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaReturn + + + +Diagnostics: +error: Return not currently supported in inline functions + ┌─ tests/lambda/inline-parity/lambda_return_typed.move:3:2 + │ +3 │ return f(b) + │ ^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_return_typed.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_return_typed.move new file mode 100644 index 00000000000000..1ea4d58270306d --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/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/lambda/inline-parity/lambda_typed.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_typed.exp new file mode 100644 index 00000000000000..11a8de528f5cb6 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/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/lambda/inline-parity/lambda_typed.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_typed.lambda.exp new file mode 100644 index 00000000000000..06f283c33248f2 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_typed.lambda.exp @@ -0,0 +1,1609 @@ +// -- Model dump before env processor 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 { + LambdaTest1::inline_mul(Add((f)(b), 1), LambdaTest1::inline_mul(3, 4)) + } + 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(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 { + 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 v: vector = Vector(1, 2, 3); + { + let product: u64 = 1; + LambdaTest2::foreach(Borrow(Immutable)(v), |e: &u64| product: u64 = LambdaTest1::inline_mul(product, Deref(e))); + 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 { + Add(LambdaTest2::inline_apply2(|x: u64| Add(x, 1), 3), LambdaTest2::inline_apply2(|x: u64| Mul(x, x), LambdaTest::inline_apply(|y: u64| y, 3))) + } + private fun test_lambda() { + { + let a: u64 = LambdaTest::inline_apply_test(); + if Eq(a, 1) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaTest + + +// -- Model dump after env processor unused checks: +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 { + LambdaTest1::inline_mul(Add((f)(b), 1), LambdaTest1::inline_mul(3, 4)) + } + 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(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 { + 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 v: vector = Vector(1, 2, 3); + { + let product: u64 = 1; + LambdaTest2::foreach(Borrow(Immutable)(v), |e: &u64| product: u64 = LambdaTest1::inline_mul(product, Deref(e))); + 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 { + Add(LambdaTest2::inline_apply2(|x: u64| Add(x, 1), 3), LambdaTest2::inline_apply2(|x: u64| Mul(x, x), LambdaTest::inline_apply(|y: u64| y, 3))) + } + private fun test_lambda() { + { + let a: u64 = LambdaTest::inline_apply_test(); + if Eq(a, 1) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaTest + + +// -- Model dump after env processor type parameter check: +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 { + LambdaTest1::inline_mul(Add((f)(b), 1), LambdaTest1::inline_mul(3, 4)) + } + 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(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 { + 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 v: vector = Vector(1, 2, 3); + { + let product: u64 = 1; + LambdaTest2::foreach(Borrow(Immutable)(v), |e: &u64| product: u64 = LambdaTest1::inline_mul(product, Deref(e))); + 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 { + Add(LambdaTest2::inline_apply2(|x: u64| Add(x, 1), 3), LambdaTest2::inline_apply2(|x: u64| Mul(x, x), LambdaTest::inline_apply(|y: u64| y, 3))) + } + private fun test_lambda() { + { + let a: u64 = LambdaTest::inline_apply_test(); + if Eq(a, 1) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaTest + + +// -- Model dump after env processor check recursive struct definition: +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 { + LambdaTest1::inline_mul(Add((f)(b), 1), LambdaTest1::inline_mul(3, 4)) + } + 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(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 { + 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 v: vector = Vector(1, 2, 3); + { + let product: u64 = 1; + LambdaTest2::foreach(Borrow(Immutable)(v), |e: &u64| product: u64 = LambdaTest1::inline_mul(product, Deref(e))); + 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 { + Add(LambdaTest2::inline_apply2(|x: u64| Add(x, 1), 3), LambdaTest2::inline_apply2(|x: u64| Mul(x, x), LambdaTest::inline_apply(|y: u64| y, 3))) + } + private fun test_lambda() { + { + let a: u64 = LambdaTest::inline_apply_test(); + if Eq(a, 1) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaTest + + +// -- Model dump after env processor check cyclic type instantiation: +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 { + LambdaTest1::inline_mul(Add((f)(b), 1), LambdaTest1::inline_mul(3, 4)) + } + 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(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 { + 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 v: vector = Vector(1, 2, 3); + { + let product: u64 = 1; + LambdaTest2::foreach(Borrow(Immutable)(v), |e: &u64| product: u64 = LambdaTest1::inline_mul(product, Deref(e))); + 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 { + Add(LambdaTest2::inline_apply2(|x: u64| Add(x, 1), 3), LambdaTest2::inline_apply2(|x: u64| Mul(x, x), LambdaTest::inline_apply(|y: u64| y, 3))) + } + private fun test_lambda() { + { + let a: u64 = LambdaTest::inline_apply_test(); + if Eq(a, 1) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaTest + + +// -- Model dump after env processor unused struct params check: +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 { + LambdaTest1::inline_mul(Add((f)(b), 1), LambdaTest1::inline_mul(3, 4)) + } + 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(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 { + 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 v: vector = Vector(1, 2, 3); + { + let product: u64 = 1; + LambdaTest2::foreach(Borrow(Immutable)(v), |e: &u64| product: u64 = LambdaTest1::inline_mul(product, Deref(e))); + 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 { + Add(LambdaTest2::inline_apply2(|x: u64| Add(x, 1), 3), LambdaTest2::inline_apply2(|x: u64| Mul(x, x), LambdaTest::inline_apply(|y: u64| y, 3))) + } + private fun test_lambda() { + { + let a: u64 = LambdaTest::inline_apply_test(); + if Eq(a, 1) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaTest + + +// -- Model dump after env processor access and use check before inlining: +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 { + LambdaTest1::inline_mul(Add((f)(b), 1), LambdaTest1::inline_mul(3, 4)) + } + 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(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 { + 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 v: vector = Vector(1, 2, 3); + { + let product: u64 = 1; + LambdaTest2::foreach(Borrow(Immutable)(v), |e: &u64| product: u64 = LambdaTest1::inline_mul(product, Deref(e))); + 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 { + Add(LambdaTest2::inline_apply2(|x: u64| Add(x, 1), 3), LambdaTest2::inline_apply2(|x: u64| Mul(x, x), LambdaTest::inline_apply(|y: u64| y, 3))) + } + private fun test_lambda() { + { + let a: u64 = LambdaTest::inline_apply_test(); + if Eq(a, 1) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaTest + + +// -- Model dump after env processor inlining: +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), { + let (a: u64, b: u64): (u64, u64) = Tuple(3, 4); + Mul(a, b) + }); + Mul(a, b) + } + } + 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, { + let (b: u64): (u64) = Tuple(3); + { + let (x: u64): (u64) = Tuple(b); + x + } + }); + Mul(a, b) + })); + { + let (a: u64, b: u64): (u64, u64) = Tuple(Add({ + let (z: u64): (u64) = Tuple(b); + z + }, 1), { + let (a: u64, b: u64): (u64, u64) = Tuple(3, 4); + Mul(a, b) + }); + Mul(a, b) + } + }, 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 v: vector = Vector(1, 2, 3); + { + let product: u64 = 1; + { + let (v: &vector): (&vector) = Tuple(Borrow(Immutable)(v)); + { + 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 { + Add({ + let (c: u64): (u64) = Tuple(3); + Add({ + let (b: u64): (u64) = Tuple({ + let (x: u64): (u64) = Tuple({ + let (a: u64, b: u64): (u64, u64) = Tuple(c, { + let (b: u64): (u64) = Tuple(3); + { + let (x: u64): (u64) = Tuple(b); + x + } + }); + Mul(a, b) + }); + Add(x, 1) + }); + { + let (a: u64, b: u64): (u64, u64) = Tuple(Add({ + let (z: u64): (u64) = Tuple(b); + z + }, 1), { + let (a: u64, b: u64): (u64, u64) = Tuple(3, 4); + Mul(a, b) + }); + Mul(a, b) + } + }, 2) + }, { + let (c: u64): (u64) = Tuple({ + let (b: u64): (u64) = Tuple(3); + { + let (y: u64): (u64) = Tuple(b); + y + } + }); + Add({ + let (b: u64): (u64) = Tuple({ + let (x: u64): (u64) = Tuple({ + let (a: u64, b: u64): (u64, u64) = Tuple(c, { + let (b: u64): (u64) = Tuple(3); + { + let (x: u64): (u64) = Tuple(b); + x + } + }); + Mul(a, b) + }); + Mul(x, x) + }); + { + let (a: u64, b: u64): (u64, u64) = Tuple(Add({ + let (z: u64): (u64) = Tuple(b); + z + }, 1), { + let (a: u64, b: u64): (u64, u64) = Tuple(3, 4); + Mul(a, b) + }); + Mul(a, b) + } + }, 2) + }) + } + private fun test_lambda() { + { + let a: u64 = { + let (): (); + Add({ + let (c: u64): (u64) = Tuple(3); + Add({ + let (b: u64): (u64) = Tuple({ + let (x: u64): (u64) = Tuple({ + let (a: u64, b: u64): (u64, u64) = Tuple(c, { + let (b: u64): (u64) = Tuple(3); + { + let (x: u64): (u64) = Tuple(b); + x + } + }); + Mul(a, b) + }); + Add(x, 1) + }); + { + let (a: u64, b: u64): (u64, u64) = Tuple(Add({ + let (z: u64): (u64) = Tuple(b); + z + }, 1), { + let (a: u64, b: u64): (u64, u64) = Tuple(3, 4); + Mul(a, b) + }); + Mul(a, b) + } + }, 2) + }, { + let (c: u64): (u64) = Tuple({ + let (b: u64): (u64) = Tuple(3); + { + let (y: u64): (u64) = Tuple(b); + y + } + }); + Add({ + let (b: u64): (u64) = Tuple({ + let (x: u64): (u64) = Tuple({ + let (a: u64, b: u64): (u64, u64) = Tuple(c, { + let (b: u64): (u64) = Tuple(3); + { + let (x: u64): (u64) = Tuple(b); + x + } + }); + Mul(a, b) + }); + Mul(x, x) + }); + { + let (a: u64, b: u64): (u64, u64) = Tuple(Add({ + let (z: u64): (u64) = Tuple(b); + z + }, 1), { + let (a: u64, b: u64): (u64, u64) = Tuple(3, 4); + Mul(a, b) + }); + Mul(a, b) + } + }, 2) + }) + }; + if Eq(a, 1) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaTest + + +// -- Model dump after env processor access and use check after inlining: +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), { + let (a: u64, b: u64): (u64, u64) = Tuple(3, 4); + Mul(a, b) + }); + Mul(a, b) + } + } + 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, { + let (b: u64): (u64) = Tuple(3); + { + let (x: u64): (u64) = Tuple(b); + x + } + }); + Mul(a, b) + })); + { + let (a: u64, b: u64): (u64, u64) = Tuple(Add({ + let (z: u64): (u64) = Tuple(b); + z + }, 1), { + let (a: u64, b: u64): (u64, u64) = Tuple(3, 4); + Mul(a, b) + }); + Mul(a, b) + } + }, 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 v: vector = Vector(1, 2, 3); + { + let product: u64 = 1; + { + let (v: &vector): (&vector) = Tuple(Borrow(Immutable)(v)); + { + 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 { + Add({ + let (c: u64): (u64) = Tuple(3); + Add({ + let (b: u64): (u64) = Tuple({ + let (x: u64): (u64) = Tuple({ + let (a: u64, b: u64): (u64, u64) = Tuple(c, { + let (b: u64): (u64) = Tuple(3); + { + let (x: u64): (u64) = Tuple(b); + x + } + }); + Mul(a, b) + }); + Add(x, 1) + }); + { + let (a: u64, b: u64): (u64, u64) = Tuple(Add({ + let (z: u64): (u64) = Tuple(b); + z + }, 1), { + let (a: u64, b: u64): (u64, u64) = Tuple(3, 4); + Mul(a, b) + }); + Mul(a, b) + } + }, 2) + }, { + let (c: u64): (u64) = Tuple({ + let (b: u64): (u64) = Tuple(3); + { + let (y: u64): (u64) = Tuple(b); + y + } + }); + Add({ + let (b: u64): (u64) = Tuple({ + let (x: u64): (u64) = Tuple({ + let (a: u64, b: u64): (u64, u64) = Tuple(c, { + let (b: u64): (u64) = Tuple(3); + { + let (x: u64): (u64) = Tuple(b); + x + } + }); + Mul(a, b) + }); + Mul(x, x) + }); + { + let (a: u64, b: u64): (u64, u64) = Tuple(Add({ + let (z: u64): (u64) = Tuple(b); + z + }, 1), { + let (a: u64, b: u64): (u64, u64) = Tuple(3, 4); + Mul(a, b) + }); + Mul(a, b) + } + }, 2) + }) + } + private fun test_lambda() { + { + let a: u64 = { + let (): (); + Add({ + let (c: u64): (u64) = Tuple(3); + Add({ + let (b: u64): (u64) = Tuple({ + let (x: u64): (u64) = Tuple({ + let (a: u64, b: u64): (u64, u64) = Tuple(c, { + let (b: u64): (u64) = Tuple(3); + { + let (x: u64): (u64) = Tuple(b); + x + } + }); + Mul(a, b) + }); + Add(x, 1) + }); + { + let (a: u64, b: u64): (u64, u64) = Tuple(Add({ + let (z: u64): (u64) = Tuple(b); + z + }, 1), { + let (a: u64, b: u64): (u64, u64) = Tuple(3, 4); + Mul(a, b) + }); + Mul(a, b) + } + }, 2) + }, { + let (c: u64): (u64) = Tuple({ + let (b: u64): (u64) = Tuple(3); + { + let (y: u64): (u64) = Tuple(b); + y + } + }); + Add({ + let (b: u64): (u64) = Tuple({ + let (x: u64): (u64) = Tuple({ + let (a: u64, b: u64): (u64, u64) = Tuple(c, { + let (b: u64): (u64) = Tuple(3); + { + let (x: u64): (u64) = Tuple(b); + x + } + }); + Mul(a, b) + }); + Mul(x, x) + }); + { + let (a: u64, b: u64): (u64, u64) = Tuple(Add({ + let (z: u64): (u64) = Tuple(b); + z + }, 1), { + let (a: u64, b: u64): (u64, u64) = Tuple(3, 4); + Mul(a, b) + }); + Mul(a, b) + } + }, 2) + }) + }; + if Eq(a, 1) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaTest + + +// -- Model dump after env processor acquires check: +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), { + let (a: u64, b: u64): (u64, u64) = Tuple(3, 4); + Mul(a, b) + }); + Mul(a, b) + } + } + 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, { + let (b: u64): (u64) = Tuple(3); + { + let (x: u64): (u64) = Tuple(b); + x + } + }); + Mul(a, b) + })); + { + let (a: u64, b: u64): (u64, u64) = Tuple(Add({ + let (z: u64): (u64) = Tuple(b); + z + }, 1), { + let (a: u64, b: u64): (u64, u64) = Tuple(3, 4); + Mul(a, b) + }); + Mul(a, b) + } + }, 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 v: vector = Vector(1, 2, 3); + { + let product: u64 = 1; + { + let (v: &vector): (&vector) = Tuple(Borrow(Immutable)(v)); + { + 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 { + Add({ + let (c: u64): (u64) = Tuple(3); + Add({ + let (b: u64): (u64) = Tuple({ + let (x: u64): (u64) = Tuple({ + let (a: u64, b: u64): (u64, u64) = Tuple(c, { + let (b: u64): (u64) = Tuple(3); + { + let (x: u64): (u64) = Tuple(b); + x + } + }); + Mul(a, b) + }); + Add(x, 1) + }); + { + let (a: u64, b: u64): (u64, u64) = Tuple(Add({ + let (z: u64): (u64) = Tuple(b); + z + }, 1), { + let (a: u64, b: u64): (u64, u64) = Tuple(3, 4); + Mul(a, b) + }); + Mul(a, b) + } + }, 2) + }, { + let (c: u64): (u64) = Tuple({ + let (b: u64): (u64) = Tuple(3); + { + let (y: u64): (u64) = Tuple(b); + y + } + }); + Add({ + let (b: u64): (u64) = Tuple({ + let (x: u64): (u64) = Tuple({ + let (a: u64, b: u64): (u64, u64) = Tuple(c, { + let (b: u64): (u64) = Tuple(3); + { + let (x: u64): (u64) = Tuple(b); + x + } + }); + Mul(a, b) + }); + Mul(x, x) + }); + { + let (a: u64, b: u64): (u64, u64) = Tuple(Add({ + let (z: u64): (u64) = Tuple(b); + z + }, 1), { + let (a: u64, b: u64): (u64, u64) = Tuple(3, 4); + Mul(a, b) + }); + Mul(a, b) + } + }, 2) + }) + } + private fun test_lambda() { + { + let a: u64 = { + let (): (); + Add({ + let (c: u64): (u64) = Tuple(3); + Add({ + let (b: u64): (u64) = Tuple({ + let (x: u64): (u64) = Tuple({ + let (a: u64, b: u64): (u64, u64) = Tuple(c, { + let (b: u64): (u64) = Tuple(3); + { + let (x: u64): (u64) = Tuple(b); + x + } + }); + Mul(a, b) + }); + Add(x, 1) + }); + { + let (a: u64, b: u64): (u64, u64) = Tuple(Add({ + let (z: u64): (u64) = Tuple(b); + z + }, 1), { + let (a: u64, b: u64): (u64, u64) = Tuple(3, 4); + Mul(a, b) + }); + Mul(a, b) + } + }, 2) + }, { + let (c: u64): (u64) = Tuple({ + let (b: u64): (u64) = Tuple(3); + { + let (y: u64): (u64) = Tuple(b); + y + } + }); + Add({ + let (b: u64): (u64) = Tuple({ + let (x: u64): (u64) = Tuple({ + let (a: u64, b: u64): (u64, u64) = Tuple(c, { + let (b: u64): (u64) = Tuple(3); + { + let (x: u64): (u64) = Tuple(b); + x + } + }); + Mul(a, b) + }); + Mul(x, x) + }); + { + let (a: u64, b: u64): (u64, u64) = Tuple(Add({ + let (z: u64): (u64) = Tuple(b); + z + }, 1), { + let (a: u64, b: u64): (u64, u64) = Tuple(3, 4); + Mul(a, b) + }); + Mul(a, b) + } + }, 2) + }) + }; + if Eq(a, 1) { + Tuple() + } else { + Abort(0) + }; + Tuple() + } + } +} // end 0x42::LambdaTest + + +// -- Model dump after env processor simplifier: +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 + + +// -- Model dump after env processor lambda-lifting: +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(closure LambdaTest2::inline_apply3$lambda$2(), 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() + } + } + private fun inline_apply3$lambda$1(y: u64): u64 { + y + } + private fun inline_apply3$lambda$2(x: u64): u64 { + LambdaTest1::inline_apply(closure LambdaTest2::inline_apply3$lambda$1(), x) + } +} // 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 + + +// -- Model dump after env processor specification checker: +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(closure LambdaTest2::inline_apply3$lambda$2(), 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() + } + } + private fun inline_apply3$lambda$1(y: u64): u64 { + y + } + private fun inline_apply3$lambda$2(x: u64): u64 { + LambdaTest1::inline_apply(closure LambdaTest2::inline_apply3$lambda$1(), x) + } +} // 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 + + +// -- Model dump after env processor specification rewriter: +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(closure LambdaTest2::inline_apply3$lambda$2(), 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() + } + } + private fun inline_apply3$lambda$1(y: u64): u64 { + y + } + private fun inline_apply3$lambda$2(x: u64): u64 { + LambdaTest1::inline_apply(closure LambdaTest2::inline_apply3$lambda$1(), x) + } +} // 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 + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/lambda_typed.move:11:2 + │ +11 │ f(b) + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/lambda_typed.move:40:29 + │ +40 │ LambdaTest1::inline_apply(|y: u64|y, x) + │ ^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_typed.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_typed.move new file mode 100644 index 00000000000000..e690fc4ffec92a --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/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/lambda/inline-parity/masking.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/masking.exp new file mode 100644 index 00000000000000..5b6f51172d8f03 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/masking.exp @@ -0,0 +1,9 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `Test::foo` has function parameters: + ┌─ tests/lambda/inline-parity/masking.move:3:9 + │ +3 │ fun foo(f:|u64, u64| u64, g: |u64, u64| u64, x: u64, _y: u64): u64 { + │ ^^^ - - Parameter `g` has function-valued type `|(u64, u64)|u64`. + │ │ + │ Parameter `f` has function-valued type `|(u64, u64)|u64`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/masking.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/masking.lambda.exp new file mode 100644 index 00000000000000..a89c6271195d1a --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/masking.lambda.exp @@ -0,0 +1,215 @@ +// -- Model dump before env processor pipeline: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun main(): u64 { + Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor unused checks: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun main(): u64 { + Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor type parameter check: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun main(): u64 { + Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun main(): u64 { + Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun main(): u64 { + Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor unused struct params check: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun main(): u64 { + Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun main(): u64 { + Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor inlining: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun main(): u64 { + Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun main(): u64 { + Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor acquires check: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun main(): u64 { + Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor simplifier: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun main(): u64 { + Test::foo(|(x: u64, _: u64): (u64, u64)| x, |(_: u64, y: u64): (u64, u64)| y, 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor lambda-lifting: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun main(): u64 { + Test::foo(closure Test::main$lambda$1(), closure Test::main$lambda$2(), 10, 100) + } + private fun main$lambda$1(x: u64,param$1: u64): u64 { + { + let _: u64 = param$1; + x + } + } + private fun main$lambda$2(param$0: u64,y: u64): u64 { + { + let _: u64 = param$0; + y + } + } +} // end 0x42::Test + + +// -- Model dump after env processor specification checker: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun main(): u64 { + Test::foo(closure Test::main$lambda$1(), closure Test::main$lambda$2(), 10, 100) + } + private fun main$lambda$1(x: u64,param$1: u64): u64 { + { + let _: u64 = param$1; + x + } + } + private fun main$lambda$2(param$0: u64,y: u64): u64 { + { + let _: u64 = param$0; + y + } + } +} // end 0x42::Test + + +// -- Model dump after env processor specification rewriter: +module 0x42::Test { + private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { + Add((f)(x, _y), (g)(x, _y)) + } + public fun main(): u64 { + Test::foo(closure Test::main$lambda$1(), closure Test::main$lambda$2(), 10, 100) + } + private fun main$lambda$1(x: u64,param$1: u64): u64 { + { + let _: u64 = param$1; + x + } + } + private fun main$lambda$2(param$0: u64,y: u64): u64 { + { + let _: u64 = param$0; + y + } + } +} // end 0x42::Test + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/masking.move:4:9 + │ +4 │ f(x, _y) + g(x, _y) + │ ^ + +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/masking.move:4:20 + │ +4 │ f(x, _y) + g(x, _y) + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/masking.move:8:13 + │ +8 │ foo(|x, _| x, |_, y| y, 10, 100) + │ ^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/masking.move:8:23 + │ +8 │ foo(|x, _| x, |_, y| y, 10, 100) + │ ^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/masking.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/masking.move new file mode 100644 index 00000000000000..134b14c53945b1 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/masking.move @@ -0,0 +1,12 @@ +//# publish +module 0x42::Test { + 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, _| x, |_, y| y, 10, 100) + } +} + +//# run 0x42::Test::main diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/multi_param.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/multi_param.exp new file mode 100644 index 00000000000000..ccc35bcfbdb5e8 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/multi_param.exp @@ -0,0 +1,13 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `Test::for_each_ref_mut` has a function parameter: + ┌─ tests/lambda/inline-parity/multi_param.move:7:16 + │ +7 │ public fun for_each_ref_mut(v: &mut vector, f: |&mut Element|) { + │ ^^^^^^^^^^^^^^^^ - Parameter `f` has function-valued type `|&mut Element|`. + +error: Only inline functions may have function-typed parameters, but non-inline function `Test::elem_for_each_ref` has a function parameter: + ┌─ tests/lambda/inline-parity/multi_param.move:17:16 + │ +17 │ public fun elem_for_each_ref(v: &mut vector>, f: |&K, &mut V|u64): u64 { + │ ^^^^^^^^^^^^^^^^^ - Parameter `f` has function-valued type `|(&K, &mut V)|u64`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/multi_param.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/multi_param.lambda.exp new file mode 100644 index 00000000000000..1c08fafc289340 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/multi_param.lambda.exp @@ -0,0 +1,458 @@ +// -- Model dump before env processor pipeline: +module 0x42::Test { + use 0x1::vector as V; // resolved as: 0x1::vector + struct Elem { + k: K, + v: V, + } + public fun elem_for_each_ref(v: &mut vector>,f: |(�, &mut #1)|u64): u64 { + { + let result: u64 = 0; + Test::for_each_ref_mut>(v, |elem: &mut Test::Elem| { + let elem: &mut Test::Elem = elem; + result: u64 = Add(result, (f)(Borrow(Immutable)(select Test::Elem.k<&mut Test::Elem>(elem)), Borrow(Mutable)(select Test::Elem.v<&mut Test::Elem>(elem)))); + Tuple() + }); + result + } + } + public fun for_each_ref_mut(v: &mut vector<#0>,f: |&mut #0|) { + { + let i: u64 = 0; + loop { + if Lt(i, vector::length(Freeze(false)(v))) { + (f)(vector::borrow_mut(v, i)); + i: u64 = Add(i, 1) + } else { + break + } + } + } + } + public fun test() { + if Eq(Test::elem_for_each_ref(Borrow(Mutable)(Vector>(pack Test::Elem(1, 2))), |(x: &u64, y: &mut u64): (&u64, &mut u64)| Add(Deref(x), Deref(y))), 3) { + Tuple() + } else { + Abort(0) + } + } +} // end 0x42::Test + + +// -- Model dump after env processor unused checks: +module 0x42::Test { + use 0x1::vector as V; // resolved as: 0x1::vector + struct Elem { + k: K, + v: V, + } + public fun elem_for_each_ref(v: &mut vector>,f: |(�, &mut #1)|u64): u64 { + { + let result: u64 = 0; + Test::for_each_ref_mut>(v, |elem: &mut Test::Elem| { + let elem: &mut Test::Elem = elem; + result: u64 = Add(result, (f)(Borrow(Immutable)(select Test::Elem.k<&mut Test::Elem>(elem)), Borrow(Mutable)(select Test::Elem.v<&mut Test::Elem>(elem)))); + Tuple() + }); + result + } + } + public fun for_each_ref_mut(v: &mut vector<#0>,f: |&mut #0|) { + { + let i: u64 = 0; + loop { + if Lt(i, vector::length(Freeze(false)(v))) { + (f)(vector::borrow_mut(v, i)); + i: u64 = Add(i, 1) + } else { + break + } + } + } + } + public fun test() { + if Eq(Test::elem_for_each_ref(Borrow(Mutable)(Vector>(pack Test::Elem(1, 2))), |(x: &u64, y: &mut u64): (&u64, &mut u64)| Add(Deref(x), Deref(y))), 3) { + Tuple() + } else { + Abort(0) + } + } +} // end 0x42::Test + + +// -- Model dump after env processor type parameter check: +module 0x42::Test { + use 0x1::vector as V; // resolved as: 0x1::vector + struct Elem { + k: K, + v: V, + } + public fun elem_for_each_ref(v: &mut vector>,f: |(�, &mut #1)|u64): u64 { + { + let result: u64 = 0; + Test::for_each_ref_mut>(v, |elem: &mut Test::Elem| { + let elem: &mut Test::Elem = elem; + result: u64 = Add(result, (f)(Borrow(Immutable)(select Test::Elem.k<&mut Test::Elem>(elem)), Borrow(Mutable)(select Test::Elem.v<&mut Test::Elem>(elem)))); + Tuple() + }); + result + } + } + public fun for_each_ref_mut(v: &mut vector<#0>,f: |&mut #0|) { + { + let i: u64 = 0; + loop { + if Lt(i, vector::length(Freeze(false)(v))) { + (f)(vector::borrow_mut(v, i)); + i: u64 = Add(i, 1) + } else { + break + } + } + } + } + public fun test() { + if Eq(Test::elem_for_each_ref(Borrow(Mutable)(Vector>(pack Test::Elem(1, 2))), |(x: &u64, y: &mut u64): (&u64, &mut u64)| Add(Deref(x), Deref(y))), 3) { + Tuple() + } else { + Abort(0) + } + } +} // end 0x42::Test + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::Test { + use 0x1::vector as V; // resolved as: 0x1::vector + struct Elem { + k: K, + v: V, + } + public fun elem_for_each_ref(v: &mut vector>,f: |(�, &mut #1)|u64): u64 { + { + let result: u64 = 0; + Test::for_each_ref_mut>(v, |elem: &mut Test::Elem| { + let elem: &mut Test::Elem = elem; + result: u64 = Add(result, (f)(Borrow(Immutable)(select Test::Elem.k<&mut Test::Elem>(elem)), Borrow(Mutable)(select Test::Elem.v<&mut Test::Elem>(elem)))); + Tuple() + }); + result + } + } + public fun for_each_ref_mut(v: &mut vector<#0>,f: |&mut #0|) { + { + let i: u64 = 0; + loop { + if Lt(i, vector::length(Freeze(false)(v))) { + (f)(vector::borrow_mut(v, i)); + i: u64 = Add(i, 1) + } else { + break + } + } + } + } + public fun test() { + if Eq(Test::elem_for_each_ref(Borrow(Mutable)(Vector>(pack Test::Elem(1, 2))), |(x: &u64, y: &mut u64): (&u64, &mut u64)| Add(Deref(x), Deref(y))), 3) { + Tuple() + } else { + Abort(0) + } + } +} // end 0x42::Test + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::Test { + use 0x1::vector as V; // resolved as: 0x1::vector + struct Elem { + k: K, + v: V, + } + public fun elem_for_each_ref(v: &mut vector>,f: |(�, &mut #1)|u64): u64 { + { + let result: u64 = 0; + Test::for_each_ref_mut>(v, |elem: &mut Test::Elem| { + let elem: &mut Test::Elem = elem; + result: u64 = Add(result, (f)(Borrow(Immutable)(select Test::Elem.k<&mut Test::Elem>(elem)), Borrow(Mutable)(select Test::Elem.v<&mut Test::Elem>(elem)))); + Tuple() + }); + result + } + } + public fun for_each_ref_mut(v: &mut vector<#0>,f: |&mut #0|) { + { + let i: u64 = 0; + loop { + if Lt(i, vector::length(Freeze(false)(v))) { + (f)(vector::borrow_mut(v, i)); + i: u64 = Add(i, 1) + } else { + break + } + } + } + } + public fun test() { + if Eq(Test::elem_for_each_ref(Borrow(Mutable)(Vector>(pack Test::Elem(1, 2))), |(x: &u64, y: &mut u64): (&u64, &mut u64)| Add(Deref(x), Deref(y))), 3) { + Tuple() + } else { + Abort(0) + } + } +} // end 0x42::Test + + +// -- Model dump after env processor unused struct params check: +module 0x42::Test { + use 0x1::vector as V; // resolved as: 0x1::vector + struct Elem { + k: K, + v: V, + } + public fun elem_for_each_ref(v: &mut vector>,f: |(�, &mut #1)|u64): u64 { + { + let result: u64 = 0; + Test::for_each_ref_mut>(v, |elem: &mut Test::Elem| { + let elem: &mut Test::Elem = elem; + result: u64 = Add(result, (f)(Borrow(Immutable)(select Test::Elem.k<&mut Test::Elem>(elem)), Borrow(Mutable)(select Test::Elem.v<&mut Test::Elem>(elem)))); + Tuple() + }); + result + } + } + public fun for_each_ref_mut(v: &mut vector<#0>,f: |&mut #0|) { + { + let i: u64 = 0; + loop { + if Lt(i, vector::length(Freeze(false)(v))) { + (f)(vector::borrow_mut(v, i)); + i: u64 = Add(i, 1) + } else { + break + } + } + } + } + public fun test() { + if Eq(Test::elem_for_each_ref(Borrow(Mutable)(Vector>(pack Test::Elem(1, 2))), |(x: &u64, y: &mut u64): (&u64, &mut u64)| Add(Deref(x), Deref(y))), 3) { + Tuple() + } else { + Abort(0) + } + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::Test { + use 0x1::vector as V; // resolved as: 0x1::vector + struct Elem { + k: K, + v: V, + } + public fun elem_for_each_ref(v: &mut vector>,f: |(�, &mut #1)|u64): u64 { + { + let result: u64 = 0; + Test::for_each_ref_mut>(v, |elem: &mut Test::Elem| { + let elem: &mut Test::Elem = elem; + result: u64 = Add(result, (f)(Borrow(Immutable)(select Test::Elem.k<&mut Test::Elem>(elem)), Borrow(Mutable)(select Test::Elem.v<&mut Test::Elem>(elem)))); + Tuple() + }); + result + } + } + public fun for_each_ref_mut(v: &mut vector<#0>,f: |&mut #0|) { + { + let i: u64 = 0; + loop { + if Lt(i, vector::length(Freeze(false)(v))) { + (f)(vector::borrow_mut(v, i)); + i: u64 = Add(i, 1) + } else { + break + } + } + } + } + public fun test() { + if Eq(Test::elem_for_each_ref(Borrow(Mutable)(Vector>(pack Test::Elem(1, 2))), |(x: &u64, y: &mut u64): (&u64, &mut u64)| Add(Deref(x), Deref(y))), 3) { + Tuple() + } else { + Abort(0) + } + } +} // end 0x42::Test + + +// -- Model dump after env processor inlining: +module 0x42::Test { + use 0x1::vector as V; // resolved as: 0x1::vector + struct Elem { + k: K, + v: V, + } + public fun elem_for_each_ref(v: &mut vector>,f: |(�, &mut #1)|u64): u64 { + { + let result: u64 = 0; + Test::for_each_ref_mut>(v, |elem: &mut Test::Elem| { + let elem: &mut Test::Elem = elem; + result: u64 = Add(result, (f)(Borrow(Immutable)(select Test::Elem.k<&mut Test::Elem>(elem)), Borrow(Mutable)(select Test::Elem.v<&mut Test::Elem>(elem)))); + Tuple() + }); + result + } + } + public fun for_each_ref_mut(v: &mut vector<#0>,f: |&mut #0|) { + { + let i: u64 = 0; + loop { + if Lt(i, vector::length(Freeze(false)(v))) { + (f)(vector::borrow_mut(v, i)); + i: u64 = Add(i, 1) + } else { + break + } + } + } + } + public fun test() { + if Eq(Test::elem_for_each_ref(Borrow(Mutable)(Vector>(pack Test::Elem(1, 2))), |(x: &u64, y: &mut u64): (&u64, &mut u64)| Add(Deref(x), Deref(y))), 3) { + Tuple() + } else { + Abort(0) + } + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::Test { + use 0x1::vector as V; // resolved as: 0x1::vector + struct Elem { + k: K, + v: V, + } + public fun elem_for_each_ref(v: &mut vector>,f: |(�, &mut #1)|u64): u64 { + { + let result: u64 = 0; + Test::for_each_ref_mut>(v, |elem: &mut Test::Elem| { + let elem: &mut Test::Elem = elem; + result: u64 = Add(result, (f)(Borrow(Immutable)(select Test::Elem.k<&mut Test::Elem>(elem)), Borrow(Mutable)(select Test::Elem.v<&mut Test::Elem>(elem)))); + Tuple() + }); + result + } + } + public fun for_each_ref_mut(v: &mut vector<#0>,f: |&mut #0|) { + { + let i: u64 = 0; + loop { + if Lt(i, vector::length(Freeze(false)(v))) { + (f)(vector::borrow_mut(v, i)); + i: u64 = Add(i, 1) + } else { + break + } + } + } + } + public fun test() { + if Eq(Test::elem_for_each_ref(Borrow(Mutable)(Vector>(pack Test::Elem(1, 2))), |(x: &u64, y: &mut u64): (&u64, &mut u64)| Add(Deref(x), Deref(y))), 3) { + Tuple() + } else { + Abort(0) + } + } +} // end 0x42::Test + + +// -- Model dump after env processor acquires check: +module 0x42::Test { + use 0x1::vector as V; // resolved as: 0x1::vector + struct Elem { + k: K, + v: V, + } + public fun elem_for_each_ref(v: &mut vector>,f: |(�, &mut #1)|u64): u64 { + { + let result: u64 = 0; + Test::for_each_ref_mut>(v, |elem: &mut Test::Elem| { + let elem: &mut Test::Elem = elem; + result: u64 = Add(result, (f)(Borrow(Immutable)(select Test::Elem.k<&mut Test::Elem>(elem)), Borrow(Mutable)(select Test::Elem.v<&mut Test::Elem>(elem)))); + Tuple() + }); + result + } + } + public fun for_each_ref_mut(v: &mut vector<#0>,f: |&mut #0|) { + { + let i: u64 = 0; + loop { + if Lt(i, vector::length(Freeze(false)(v))) { + (f)(vector::borrow_mut(v, i)); + i: u64 = Add(i, 1) + } else { + break + } + } + } + } + public fun test() { + if Eq(Test::elem_for_each_ref(Borrow(Mutable)(Vector>(pack Test::Elem(1, 2))), |(x: &u64, y: &mut u64): (&u64, &mut u64)| Add(Deref(x), Deref(y))), 3) { + Tuple() + } else { + Abort(0) + } + } +} // end 0x42::Test + + +// -- Model dump after env processor simplifier: +module 0x42::Test { + use 0x1::vector as V; // resolved as: 0x1::vector + struct Elem { + k: K, + v: V, + } + public fun elem_for_each_ref(v: &mut vector>,f: |(�, &mut #1)|u64): u64 { + { + let result: u64 = 0; + Test::for_each_ref_mut>(v, |elem: &mut Test::Elem| { + let elem: &mut Test::Elem = elem; + result: u64 = Add(result, (f)(Borrow(Immutable)(select Test::Elem.k<&mut Test::Elem>(elem)), Borrow(Mutable)(select Test::Elem.v<&mut Test::Elem>(elem)))); + Tuple() + }); + result + } + } + public fun for_each_ref_mut(v: &mut vector<#0>,f: |&mut #0|) { + { + let i: u64 = 0; + loop { + if Lt(i, vector::length(Freeze(false)(v))) { + (f)(vector::borrow_mut(v, i)); + i: u64 = Add(i, 1) + } else { + break + } + } + } + } + public fun test() { + if Eq(Test::elem_for_each_ref(Borrow(Mutable)(Vector>(pack Test::Elem(1, 2))), |(x: &u64, y: &mut u64): (&u64, &mut u64)| Add(Deref(x), Deref(y))), 3) { + Tuple() + } else { + Abort(0) + } + } +} // end 0x42::Test + + + +Diagnostics: +error: captured variable `result` cannot be modified inside of a lambda + ┌─ tests/lambda/inline-parity/multi_param.move:21:13 + │ +21 │ result = result + f(&elem.k, &mut elem.v); + │ ^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/multi_param.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/multi_param.move new file mode 100644 index 00000000000000..586ce139bd6652 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/multi_param.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 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 fun elem_for_each_ref(v: &mut vector>, f: |&K, &mut V|u64): u64 { + let result = 0; + for_each_ref_mut(v, |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,y| *x + *y) == 3, 0) + } +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda.exp new file mode 100644 index 00000000000000..a05ca52c1544fa --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `Test::apply` has a function parameter: + ┌─ tests/lambda/inline-parity/nested_lambda.move:4:16 + │ +4 │ public fun apply(f: |u64, u64|u64, x: u64, y: u64): u64 { + │ ^^^^^ - Parameter `f` has function-valued type `|(u64, u64)|u64`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda.lambda.exp new file mode 100644 index 00000000000000..019feaaebebc4d --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda.lambda.exp @@ -0,0 +1,191 @@ +// -- Model dump before env processor pipeline: +module 0x42::Test { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun test(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| Add(x, y), 1, Test::apply(|(x: u64, y: u64): (u64, u64)| Mul(x, y), 2, 1)) + } +} // end 0x42::Test + + +// -- Model dump after env processor unused checks: +module 0x42::Test { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun test(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| Add(x, y), 1, Test::apply(|(x: u64, y: u64): (u64, u64)| Mul(x, y), 2, 1)) + } +} // end 0x42::Test + + +// -- Model dump after env processor type parameter check: +module 0x42::Test { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun test(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| Add(x, y), 1, Test::apply(|(x: u64, y: u64): (u64, u64)| Mul(x, y), 2, 1)) + } +} // end 0x42::Test + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::Test { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun test(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| Add(x, y), 1, Test::apply(|(x: u64, y: u64): (u64, u64)| Mul(x, y), 2, 1)) + } +} // end 0x42::Test + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::Test { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun test(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| Add(x, y), 1, Test::apply(|(x: u64, y: u64): (u64, u64)| Mul(x, y), 2, 1)) + } +} // end 0x42::Test + + +// -- Model dump after env processor unused struct params check: +module 0x42::Test { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun test(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| Add(x, y), 1, Test::apply(|(x: u64, y: u64): (u64, u64)| Mul(x, y), 2, 1)) + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::Test { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun test(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| Add(x, y), 1, Test::apply(|(x: u64, y: u64): (u64, u64)| Mul(x, y), 2, 1)) + } +} // end 0x42::Test + + +// -- Model dump after env processor inlining: +module 0x42::Test { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun test(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| Add(x, y), 1, Test::apply(|(x: u64, y: u64): (u64, u64)| Mul(x, y), 2, 1)) + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::Test { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun test(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| Add(x, y), 1, Test::apply(|(x: u64, y: u64): (u64, u64)| Mul(x, y), 2, 1)) + } +} // end 0x42::Test + + +// -- Model dump after env processor acquires check: +module 0x42::Test { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun test(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| Add(x, y), 1, Test::apply(|(x: u64, y: u64): (u64, u64)| Mul(x, y), 2, 1)) + } +} // end 0x42::Test + + +// -- Model dump after env processor simplifier: +module 0x42::Test { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun test(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| Add(x, y), 1, Test::apply(|(x: u64, y: u64): (u64, u64)| Mul(x, y), 2, 1)) + } +} // end 0x42::Test + + +// -- Model dump after env processor lambda-lifting: +module 0x42::Test { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun test(): u64 { + Test::apply(closure Test::test$lambda$1(), 1, Test::apply(closure Test::test$lambda$2(), 2, 1)) + } + private fun test$lambda$1(x: u64,y: u64): u64 { + Add(x, y) + } + private fun test$lambda$2(x: u64,y: u64): u64 { + Mul(x, y) + } +} // end 0x42::Test + + +// -- Model dump after env processor specification checker: +module 0x42::Test { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun test(): u64 { + Test::apply(closure Test::test$lambda$1(), 1, Test::apply(closure Test::test$lambda$2(), 2, 1)) + } + private fun test$lambda$1(x: u64,y: u64): u64 { + Add(x, y) + } + private fun test$lambda$2(x: u64,y: u64): u64 { + Mul(x, y) + } +} // end 0x42::Test + + +// -- Model dump after env processor specification rewriter: +module 0x42::Test { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun test(): u64 { + Test::apply(closure Test::test$lambda$1(), 1, Test::apply(closure Test::test$lambda$2(), 2, 1)) + } + private fun test$lambda$1(x: u64,y: u64): u64 { + Add(x, y) + } + private fun test$lambda$2(x: u64,y: u64): u64 { + Mul(x, y) + } +} // end 0x42::Test + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/nested_lambda.move:5:9 + │ +5 │ f(x, y) + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/nested_lambda.move:9:15 + │ +9 │ apply(|x, y| x + y, 1, apply(|x, y| x * y, 2, 1)) + │ ^^^^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/nested_lambda.move:9:38 + │ +9 │ apply(|x, y| x + y, 1, apply(|x, y| x * y, 2, 1)) + │ ^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda.move new file mode 100644 index 00000000000000..dd6740b8434cfb --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda.move @@ -0,0 +1,13 @@ +//# publish +module 0x42::Test { + + public fun apply(f: |u64, u64|u64, x: u64, y: u64): u64 { + f(x, y) + } + + public fun test(): u64 { + apply(|x, y| x + y, 1, apply(|x, y| x * y, 2, 1)) + } +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda_module.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda_module.exp new file mode 100644 index 00000000000000..98c3d75616e85e --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda_module.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `Test1::apply` has a function parameter: + ┌─ tests/lambda/inline-parity/nested_lambda_module.move:3:16 + │ +3 │ public fun apply(f: |u64, u64|u64, x: u64, y: u64): u64 { + │ ^^^^^ - Parameter `f` has function-valued type `|(u64, u64)|u64`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda_module.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda_module.lambda.exp new file mode 100644 index 00000000000000..f5ed4cea4f2830 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda_module.lambda.exp @@ -0,0 +1,233 @@ +// -- Model dump before env processor pipeline: +module 0x42::Test1 { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } +} // end 0x42::Test1 +module 0x42::Test { + use 0x42::Test1; // resolved as: 0x42::Test1 + public fun test(): u64 { + Test1::apply(|(x: u64, y: u64): (u64, u64)| Add(x, y), 1, Test1::apply(|(x: u64, y: u64): (u64, u64)| Mul(x, y), 2, 1)) + } +} // end 0x42::Test + + +// -- Model dump after env processor unused checks: +module 0x42::Test1 { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } +} // end 0x42::Test1 +module 0x42::Test { + use 0x42::Test1; // resolved as: 0x42::Test1 + public fun test(): u64 { + Test1::apply(|(x: u64, y: u64): (u64, u64)| Add(x, y), 1, Test1::apply(|(x: u64, y: u64): (u64, u64)| Mul(x, y), 2, 1)) + } +} // end 0x42::Test + + +// -- Model dump after env processor type parameter check: +module 0x42::Test1 { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } +} // end 0x42::Test1 +module 0x42::Test { + use 0x42::Test1; // resolved as: 0x42::Test1 + public fun test(): u64 { + Test1::apply(|(x: u64, y: u64): (u64, u64)| Add(x, y), 1, Test1::apply(|(x: u64, y: u64): (u64, u64)| Mul(x, y), 2, 1)) + } +} // end 0x42::Test + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::Test1 { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } +} // end 0x42::Test1 +module 0x42::Test { + use 0x42::Test1; // resolved as: 0x42::Test1 + public fun test(): u64 { + Test1::apply(|(x: u64, y: u64): (u64, u64)| Add(x, y), 1, Test1::apply(|(x: u64, y: u64): (u64, u64)| Mul(x, y), 2, 1)) + } +} // end 0x42::Test + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::Test1 { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } +} // end 0x42::Test1 +module 0x42::Test { + use 0x42::Test1; // resolved as: 0x42::Test1 + public fun test(): u64 { + Test1::apply(|(x: u64, y: u64): (u64, u64)| Add(x, y), 1, Test1::apply(|(x: u64, y: u64): (u64, u64)| Mul(x, y), 2, 1)) + } +} // end 0x42::Test + + +// -- Model dump after env processor unused struct params check: +module 0x42::Test1 { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } +} // end 0x42::Test1 +module 0x42::Test { + use 0x42::Test1; // resolved as: 0x42::Test1 + public fun test(): u64 { + Test1::apply(|(x: u64, y: u64): (u64, u64)| Add(x, y), 1, Test1::apply(|(x: u64, y: u64): (u64, u64)| Mul(x, y), 2, 1)) + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::Test1 { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } +} // end 0x42::Test1 +module 0x42::Test { + use 0x42::Test1; // resolved as: 0x42::Test1 + public fun test(): u64 { + Test1::apply(|(x: u64, y: u64): (u64, u64)| Add(x, y), 1, Test1::apply(|(x: u64, y: u64): (u64, u64)| Mul(x, y), 2, 1)) + } +} // end 0x42::Test + + +// -- Model dump after env processor inlining: +module 0x42::Test1 { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } +} // end 0x42::Test1 +module 0x42::Test { + use 0x42::Test1; // resolved as: 0x42::Test1 + public fun test(): u64 { + Test1::apply(|(x: u64, y: u64): (u64, u64)| Add(x, y), 1, Test1::apply(|(x: u64, y: u64): (u64, u64)| Mul(x, y), 2, 1)) + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::Test1 { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } +} // end 0x42::Test1 +module 0x42::Test { + use 0x42::Test1; // resolved as: 0x42::Test1 + public fun test(): u64 { + Test1::apply(|(x: u64, y: u64): (u64, u64)| Add(x, y), 1, Test1::apply(|(x: u64, y: u64): (u64, u64)| Mul(x, y), 2, 1)) + } +} // end 0x42::Test + + +// -- Model dump after env processor acquires check: +module 0x42::Test1 { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } +} // end 0x42::Test1 +module 0x42::Test { + use 0x42::Test1; // resolved as: 0x42::Test1 + public fun test(): u64 { + Test1::apply(|(x: u64, y: u64): (u64, u64)| Add(x, y), 1, Test1::apply(|(x: u64, y: u64): (u64, u64)| Mul(x, y), 2, 1)) + } +} // end 0x42::Test + + +// -- Model dump after env processor simplifier: +module 0x42::Test1 { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } +} // end 0x42::Test1 +module 0x42::Test { + use 0x42::Test1; // resolved as: 0x42::Test1 + public fun test(): u64 { + Test1::apply(|(x: u64, y: u64): (u64, u64)| Add(x, y), 1, Test1::apply(|(x: u64, y: u64): (u64, u64)| Mul(x, y), 2, 1)) + } +} // end 0x42::Test + + +// -- Model dump after env processor lambda-lifting: +module 0x42::Test1 { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } +} // end 0x42::Test1 +module 0x42::Test { + use 0x42::Test1; // resolved as: 0x42::Test1 + public fun test(): u64 { + Test1::apply(closure Test::test$lambda$1(), 1, Test1::apply(closure Test::test$lambda$2(), 2, 1)) + } + private fun test$lambda$1(x: u64,y: u64): u64 { + Add(x, y) + } + private fun test$lambda$2(x: u64,y: u64): u64 { + Mul(x, y) + } +} // end 0x42::Test + + +// -- Model dump after env processor specification checker: +module 0x42::Test1 { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } +} // end 0x42::Test1 +module 0x42::Test { + use 0x42::Test1; // resolved as: 0x42::Test1 + public fun test(): u64 { + Test1::apply(closure Test::test$lambda$1(), 1, Test1::apply(closure Test::test$lambda$2(), 2, 1)) + } + private fun test$lambda$1(x: u64,y: u64): u64 { + Add(x, y) + } + private fun test$lambda$2(x: u64,y: u64): u64 { + Mul(x, y) + } +} // end 0x42::Test + + +// -- Model dump after env processor specification rewriter: +module 0x42::Test1 { + public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } +} // end 0x42::Test1 +module 0x42::Test { + use 0x42::Test1; // resolved as: 0x42::Test1 + public fun test(): u64 { + Test1::apply(closure Test::test$lambda$1(), 1, Test1::apply(closure Test::test$lambda$2(), 2, 1)) + } + private fun test$lambda$1(x: u64,y: u64): u64 { + Add(x, y) + } + private fun test$lambda$2(x: u64,y: u64): u64 { + Mul(x, y) + } +} // end 0x42::Test + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/nested_lambda_module.move:4:9 + │ +4 │ f(x, y) + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/nested_lambda_module.move:13:22 + │ +13 │ Test1::apply(|x, y| x + y, 1, Test1::apply(|x, y| x * y, 2, 1)) + │ ^^^^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/nested_lambda_module.move:13:52 + │ +13 │ Test1::apply(|x, y| x + y, 1, Test1::apply(|x, y| x * y, 2, 1)) + │ ^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda_module.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda_module.move new file mode 100644 index 00000000000000..306c667f5a9563 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda_module.move @@ -0,0 +1,17 @@ +//# publish +module 0x42::Test1 { + public 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, y| x + y, 1, Test1::apply(|x, y| x * y, 2, 1)) + } +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/non_lambda_arg.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/non_lambda_arg.exp new file mode 100644 index 00000000000000..4f886c402ddfcd --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/non_lambda_arg.exp @@ -0,0 +1,13 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `sort::incorrect_sort` has a function parameter: + ┌─ tests/lambda/inline-parity/non_lambda_arg.move:4:16 + │ +4 │ public fun incorrect_sort(arr: &mut vector, a_less_b: |T, T| bool) { + │ ^^^^^^^^^^^^^^ -------- Parameter `a_less_b` has function-valued type `|(T, T)|bool`. + +error: Only inline functions may have function-typed parameters, but non-inline function `sort::incorrect_sort_recursive` has a function parameter: + ┌─ tests/lambda/inline-parity/non_lambda_arg.move:9:16 + │ +9 │ public fun incorrect_sort_recursive(arr: &mut vector, low: u64, high: u64, a_less_b: |T, T| bool) { + │ ^^^^^^^^^^^^^^^^^^^^^^^^ -------- Parameter `a_less_b` has function-valued type `|(T, T)|bool`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/non_lambda_arg.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/non_lambda_arg.lambda.exp new file mode 100644 index 00000000000000..d1a4f258f342f3 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/non_lambda_arg.lambda.exp @@ -0,0 +1,416 @@ +// -- Model dump before env processor pipeline: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor unused checks: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor type parameter check: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor unused struct params check: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor inlining: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor acquires check: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor simplifier: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor lambda-lifting: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor specification checker: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor specification rewriter: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +============ initial bytecode ================ + +[variant baseline] +public fun sort::incorrect_sort<#0>($t0: &mut vector<#0>, $t1: |(#0, #0)|bool) { + var $t2: u64 + var $t3: &vector<#0> + var $t4: u64 + var $t5: u64 + var $t6: u64 + 0: $t3 := freeze_ref(implicit)($t0) + 1: $t2 := vector::length<#0>($t3) + 2: $t4 := 0 + 3: $t6 := 1 + 4: $t5 := -($t2, $t6) + 5: sort::incorrect_sort_recursive<#0>($t0, $t4, $t5, $t1) + 6: return () +} + + +[variant baseline] +public fun sort::incorrect_sort_recursive<#0>($t0: &mut vector<#0>, $t1: u64, $t2: u64, $t3: |(#0, #0)|bool) { + var $t4: bool + var $t5: u64 + var $t6: u64 + var $t7: u64 + var $t8: u64 + var $t9: u64 + var $t10: u64 + var $t11: u64 + 0: $t4 := <($t1, $t2) + 1: if ($t4) goto 2 else goto 13 + 2: label L0 + 3: $t7 := 2 + 4: $t6 := /($t2, $t7) + 5: $t5 := +($t1, $t6) + 6: $t9 := 1 + 7: $t8 := -($t5, $t9) + 8: sort::incorrect_sort_recursive<#0>($t0, $t1, $t8, $t3) + 9: $t11 := 1 + 10: $t10 := +($t5, $t11) + 11: sort::incorrect_sort_recursive<#0>($t0, $t10, $t2, $t3) + 12: goto 14 + 13: label L1 + 14: label L2 + 15: return () +} + + +Diagnostics: +error: local `a_less_b` of type `|(T, T)|bool` does not have the `copy` ability + ┌─ tests/lambda/inline-parity/non_lambda_arg.move:12:13 + │ +12 │ incorrect_sort_recursive(arr, low, pi - 1, a_less_b); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ copy needed here because value is still in use +13 │ incorrect_sort_recursive(arr, pi + 1, high, a_less_b); + │ ----------------------------------------------------- used here + +error: local `a_less_b` of type `|(T, T)|bool` does not have the `drop` ability + ┌─ tests/lambda/inline-parity/non_lambda_arg.move:10:9 + │ +10 │ ╭ if (low < high) { +11 │ │ let pi = low + high / 2; +12 │ │ incorrect_sort_recursive(arr, low, pi - 1, a_less_b); +13 │ │ incorrect_sort_recursive(arr, pi + 1, high, a_less_b); +14 │ │ }; + │ ╰─────────^ implicitly dropped here since it is no longer used diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/non_lambda_arg.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/non_lambda_arg.move new file mode 100644 index 00000000000000..83e9d4027661da --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/non_lambda_arg.move @@ -0,0 +1,17 @@ +module 0x42::sort { + use std::vector; + + public fun incorrect_sort(arr: &mut vector, a_less_b: |T, T| bool) { + let n = vector::length(arr); + incorrect_sort_recursive(arr, 0, n - 1, a_less_b) + } + + public fun incorrect_sort_recursive(arr: &mut vector, low: u64, high: u64, a_less_b: |T, T| bool) { + if (low < high) { + let pi = low + high / 2; + incorrect_sort_recursive(arr, low, pi - 1, a_less_b); + incorrect_sort_recursive(arr, pi + 1, high, a_less_b); + }; + } + +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/op_with_side_effect_49.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/op_with_side_effect_49.exp new file mode 100644 index 00000000000000..b9f8a28daa2e7d --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/op_with_side_effect_49.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `m::call` has a function parameter: + ┌─ tests/lambda/inline-parity/op_with_side_effect_49.move:3:9 + │ +3 │ fun call(f: ||u64): u64 { + │ ^^^^ - Parameter `f` has function-valued type `|()|u64`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/op_with_side_effect_49.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/op_with_side_effect_49.lambda.exp new file mode 100644 index 00000000000000..a9a1dc063d69f6 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/op_with_side_effect_49.lambda.exp @@ -0,0 +1,189 @@ +// -- Model dump before env processor pipeline: +module 0xc0ffee::m { + private fun call(f: |()|u64): u64 { + (f)() + } + public fun test(): u64 { + { + let x: u64 = 1; + Add(Add(x, m::call(|(): ()| x: u64 = Add(x, 1); + x)), m::call(|(): ()| x: u64 = Add(x, 7); + x)) + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor unused checks: +module 0xc0ffee::m { + private fun call(f: |()|u64): u64 { + (f)() + } + public fun test(): u64 { + { + let x: u64 = 1; + Add(Add(x, m::call(|(): ()| x: u64 = Add(x, 1); + x)), m::call(|(): ()| x: u64 = Add(x, 7); + x)) + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor type parameter check: +module 0xc0ffee::m { + private fun call(f: |()|u64): u64 { + (f)() + } + public fun test(): u64 { + { + let x: u64 = 1; + Add(Add(x, m::call(|(): ()| x: u64 = Add(x, 1); + x)), m::call(|(): ()| x: u64 = Add(x, 7); + x)) + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor check recursive struct definition: +module 0xc0ffee::m { + private fun call(f: |()|u64): u64 { + (f)() + } + public fun test(): u64 { + { + let x: u64 = 1; + Add(Add(x, m::call(|(): ()| x: u64 = Add(x, 1); + x)), m::call(|(): ()| x: u64 = Add(x, 7); + x)) + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor check cyclic type instantiation: +module 0xc0ffee::m { + private fun call(f: |()|u64): u64 { + (f)() + } + public fun test(): u64 { + { + let x: u64 = 1; + Add(Add(x, m::call(|(): ()| x: u64 = Add(x, 1); + x)), m::call(|(): ()| x: u64 = Add(x, 7); + x)) + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor unused struct params check: +module 0xc0ffee::m { + private fun call(f: |()|u64): u64 { + (f)() + } + public fun test(): u64 { + { + let x: u64 = 1; + Add(Add(x, m::call(|(): ()| x: u64 = Add(x, 1); + x)), m::call(|(): ()| x: u64 = Add(x, 7); + x)) + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor access and use check before inlining: +module 0xc0ffee::m { + private fun call(f: |()|u64): u64 { + (f)() + } + public fun test(): u64 { + { + let x: u64 = 1; + Add(Add(x, m::call(|(): ()| x: u64 = Add(x, 1); + x)), m::call(|(): ()| x: u64 = Add(x, 7); + x)) + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor inlining: +module 0xc0ffee::m { + private fun call(f: |()|u64): u64 { + (f)() + } + public fun test(): u64 { + { + let x: u64 = 1; + Add(Add(x, m::call(|(): ()| x: u64 = Add(x, 1); + x)), m::call(|(): ()| x: u64 = Add(x, 7); + x)) + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor access and use check after inlining: +module 0xc0ffee::m { + private fun call(f: |()|u64): u64 { + (f)() + } + public fun test(): u64 { + { + let x: u64 = 1; + Add(Add(x, m::call(|(): ()| x: u64 = Add(x, 1); + x)), m::call(|(): ()| x: u64 = Add(x, 7); + x)) + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor acquires check: +module 0xc0ffee::m { + private fun call(f: |()|u64): u64 { + (f)() + } + public fun test(): u64 { + { + let x: u64 = 1; + Add(Add(x, m::call(|(): ()| x: u64 = Add(x, 1); + x)), m::call(|(): ()| x: u64 = Add(x, 7); + x)) + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor simplifier: +module 0xc0ffee::m { + private fun call(f: |()|u64): u64 { + (f)() + } + public fun test(): u64 { + { + let x: u64 = 1; + Add(Add(x, m::call(|(): ()| x: u64 = Add(x, 1); + x)), m::call(|(): ()| x: u64 = Add(x, 7); + x)) + } + } +} // end 0xc0ffee::m + + + +Diagnostics: +error: captured variable `x` cannot be modified inside of a lambda + ┌─ tests/lambda/inline-parity/op_with_side_effect_49.move:9:22 + │ +9 │ x + call(|| {x = x + 1; x}) + call(|| {x = x + 7; x}) + │ ^ + +error: captured variable `x` cannot be modified inside of a lambda + ┌─ tests/lambda/inline-parity/op_with_side_effect_49.move:9:48 + │ +9 │ x + call(|| {x = x + 1; x}) + call(|| {x = x + 7; x}) + │ ^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/op_with_side_effect_49.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/op_with_side_effect_49.move new file mode 100644 index 00000000000000..63bed7ba14a75b --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/op_with_side_effect_49.move @@ -0,0 +1,13 @@ +//# publish +module 0xc0ffee::m { + fun call(f: ||u64): u64 { + f() + } + + public fun test(): u64 { + let x = 1; + x + call(|| {x = x + 1; x}) + call(|| {x = x + 7; x}) + } +} + +//# run 0xc0ffee::m::test diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/options.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/options.exp new file mode 100644 index 00000000000000..04ec0a6a32fe8b --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/options.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `map_opt::map` has a function parameter: + ┌─ tests/lambda/inline-parity/options.move:5:16 + │ +5 │ public fun map(t: option::Option, f: |Element|OtherElement): option::Option { + │ ^^^ - Parameter `f` has function-valued type `|Element|OtherElement`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/options.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/options.lambda.exp new file mode 100644 index 00000000000000..52ab5de445a188 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/options.lambda.exp @@ -0,0 +1,386 @@ +// -- Model dump before env processor pipeline: +module 0x42::map_opt { + use std::option; + public fun map(t: option::Option<#0>,f: |#0|#1): option::Option<#1> { + if option::is_some(Borrow(Immutable)(t)) { + option::some((f)(option::extract(Borrow(Mutable)(t)))) + } else { + option::none() + } + } +} // end 0x42::map_opt +module 0x42::Test { + use std::option; + use 0x42::map_opt; // resolved as: 0x42::map_opt + public fun test(): u64 { + { + let t: option::Option = option::some(1); + { + let x: option::Option = map_opt::map(t, |e: u64| Add(e, 1)); + option::extract(Borrow(Mutable)(x)) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor unused checks: +module 0x42::map_opt { + use std::option; + public fun map(t: option::Option<#0>,f: |#0|#1): option::Option<#1> { + if option::is_some(Borrow(Immutable)(t)) { + option::some((f)(option::extract(Borrow(Mutable)(t)))) + } else { + option::none() + } + } +} // end 0x42::map_opt +module 0x42::Test { + use std::option; + use 0x42::map_opt; // resolved as: 0x42::map_opt + public fun test(): u64 { + { + let t: option::Option = option::some(1); + { + let x: option::Option = map_opt::map(t, |e: u64| Add(e, 1)); + option::extract(Borrow(Mutable)(x)) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor type parameter check: +module 0x42::map_opt { + use std::option; + public fun map(t: option::Option<#0>,f: |#0|#1): option::Option<#1> { + if option::is_some(Borrow(Immutable)(t)) { + option::some((f)(option::extract(Borrow(Mutable)(t)))) + } else { + option::none() + } + } +} // end 0x42::map_opt +module 0x42::Test { + use std::option; + use 0x42::map_opt; // resolved as: 0x42::map_opt + public fun test(): u64 { + { + let t: option::Option = option::some(1); + { + let x: option::Option = map_opt::map(t, |e: u64| Add(e, 1)); + option::extract(Borrow(Mutable)(x)) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::map_opt { + use std::option; + public fun map(t: option::Option<#0>,f: |#0|#1): option::Option<#1> { + if option::is_some(Borrow(Immutable)(t)) { + option::some((f)(option::extract(Borrow(Mutable)(t)))) + } else { + option::none() + } + } +} // end 0x42::map_opt +module 0x42::Test { + use std::option; + use 0x42::map_opt; // resolved as: 0x42::map_opt + public fun test(): u64 { + { + let t: option::Option = option::some(1); + { + let x: option::Option = map_opt::map(t, |e: u64| Add(e, 1)); + option::extract(Borrow(Mutable)(x)) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::map_opt { + use std::option; + public fun map(t: option::Option<#0>,f: |#0|#1): option::Option<#1> { + if option::is_some(Borrow(Immutable)(t)) { + option::some((f)(option::extract(Borrow(Mutable)(t)))) + } else { + option::none() + } + } +} // end 0x42::map_opt +module 0x42::Test { + use std::option; + use 0x42::map_opt; // resolved as: 0x42::map_opt + public fun test(): u64 { + { + let t: option::Option = option::some(1); + { + let x: option::Option = map_opt::map(t, |e: u64| Add(e, 1)); + option::extract(Borrow(Mutable)(x)) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor unused struct params check: +module 0x42::map_opt { + use std::option; + public fun map(t: option::Option<#0>,f: |#0|#1): option::Option<#1> { + if option::is_some(Borrow(Immutable)(t)) { + option::some((f)(option::extract(Borrow(Mutable)(t)))) + } else { + option::none() + } + } +} // end 0x42::map_opt +module 0x42::Test { + use std::option; + use 0x42::map_opt; // resolved as: 0x42::map_opt + public fun test(): u64 { + { + let t: option::Option = option::some(1); + { + let x: option::Option = map_opt::map(t, |e: u64| Add(e, 1)); + option::extract(Borrow(Mutable)(x)) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::map_opt { + use std::option; + public fun map(t: option::Option<#0>,f: |#0|#1): option::Option<#1> { + if option::is_some(Borrow(Immutable)(t)) { + option::some((f)(option::extract(Borrow(Mutable)(t)))) + } else { + option::none() + } + } +} // end 0x42::map_opt +module 0x42::Test { + use std::option; + use 0x42::map_opt; // resolved as: 0x42::map_opt + public fun test(): u64 { + { + let t: option::Option = option::some(1); + { + let x: option::Option = map_opt::map(t, |e: u64| Add(e, 1)); + option::extract(Borrow(Mutable)(x)) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor inlining: +module 0x42::map_opt { + use std::option; + public fun map(t: option::Option<#0>,f: |#0|#1): option::Option<#1> { + if option::is_some(Borrow(Immutable)(t)) { + option::some((f)(option::extract(Borrow(Mutable)(t)))) + } else { + option::none() + } + } +} // end 0x42::map_opt +module 0x42::Test { + use std::option; + use 0x42::map_opt; // resolved as: 0x42::map_opt + public fun test(): u64 { + { + let t: option::Option = option::some(1); + { + let x: option::Option = map_opt::map(t, |e: u64| Add(e, 1)); + option::extract(Borrow(Mutable)(x)) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::map_opt { + use std::option; + public fun map(t: option::Option<#0>,f: |#0|#1): option::Option<#1> { + if option::is_some(Borrow(Immutable)(t)) { + option::some((f)(option::extract(Borrow(Mutable)(t)))) + } else { + option::none() + } + } +} // end 0x42::map_opt +module 0x42::Test { + use std::option; + use 0x42::map_opt; // resolved as: 0x42::map_opt + public fun test(): u64 { + { + let t: option::Option = option::some(1); + { + let x: option::Option = map_opt::map(t, |e: u64| Add(e, 1)); + option::extract(Borrow(Mutable)(x)) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor acquires check: +module 0x42::map_opt { + use std::option; + public fun map(t: option::Option<#0>,f: |#0|#1): option::Option<#1> { + if option::is_some(Borrow(Immutable)(t)) { + option::some((f)(option::extract(Borrow(Mutable)(t)))) + } else { + option::none() + } + } +} // end 0x42::map_opt +module 0x42::Test { + use std::option; + use 0x42::map_opt; // resolved as: 0x42::map_opt + public fun test(): u64 { + { + let t: option::Option = option::some(1); + { + let x: option::Option = map_opt::map(t, |e: u64| Add(e, 1)); + option::extract(Borrow(Mutable)(x)) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor simplifier: +module 0x42::map_opt { + use std::option; + public fun map(t: option::Option<#0>,f: |#0|#1): option::Option<#1> { + if option::is_some(Borrow(Immutable)(t)) { + option::some((f)(option::extract(Borrow(Mutable)(t)))) + } else { + option::none() + } + } +} // end 0x42::map_opt +module 0x42::Test { + use std::option; + use 0x42::map_opt; // resolved as: 0x42::map_opt + public fun test(): u64 { + { + let t: option::Option = option::some(1); + { + let x: option::Option = map_opt::map(t, |e: u64| Add(e, 1)); + option::extract(Borrow(Mutable)(x)) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor lambda-lifting: +module 0x42::map_opt { + use std::option; + public fun map(t: option::Option<#0>,f: |#0|#1): option::Option<#1> { + if option::is_some(Borrow(Immutable)(t)) { + option::some((f)(option::extract(Borrow(Mutable)(t)))) + } else { + option::none() + } + } +} // end 0x42::map_opt +module 0x42::Test { + use std::option; + use 0x42::map_opt; // resolved as: 0x42::map_opt + public fun test(): u64 { + { + let t: option::Option = option::some(1); + { + let x: option::Option = map_opt::map(t, closure Test::test$lambda$1()); + option::extract(Borrow(Mutable)(x)) + } + } + } + private fun test$lambda$1(e: u64): u64 { + Add(e, 1) + } +} // end 0x42::Test + + +// -- Model dump after env processor specification checker: +module 0x42::map_opt { + use std::option; + public fun map(t: option::Option<#0>,f: |#0|#1): option::Option<#1> { + if option::is_some(Borrow(Immutable)(t)) { + option::some((f)(option::extract(Borrow(Mutable)(t)))) + } else { + option::none() + } + } +} // end 0x42::map_opt +module 0x42::Test { + use std::option; + use 0x42::map_opt; // resolved as: 0x42::map_opt + public fun test(): u64 { + { + let t: option::Option = option::some(1); + { + let x: option::Option = map_opt::map(t, closure Test::test$lambda$1()); + option::extract(Borrow(Mutable)(x)) + } + } + } + private fun test$lambda$1(e: u64): u64 { + Add(e, 1) + } +} // end 0x42::Test + + +// -- Model dump after env processor specification rewriter: +module 0x42::map_opt { + use std::option; + public fun map(t: option::Option<#0>,f: |#0|#1): option::Option<#1> { + if option::is_some(Borrow(Immutable)(t)) { + option::some((f)(option::extract(Borrow(Mutable)(t)))) + } else { + option::none() + } + } +} // end 0x42::map_opt +module 0x42::Test { + use std::option; + use 0x42::map_opt; // resolved as: 0x42::map_opt + public fun test(): u64 { + { + let t: option::Option = option::some(1); + { + let x: option::Option = map_opt::map(t, closure Test::test$lambda$1()); + option::extract(Borrow(Mutable)(x)) + } + } + } + private fun test$lambda$1(e: u64): u64 { + Add(e, 1) + } +} // end 0x42::Test + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/options.move:7:26 + │ +7 │ option::some(f(option::extract(&mut t))) + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/options.move:22:33 + │ +22 │ let x = map_opt::map(t, |e| e + 1); + │ ^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/options.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/options.move new file mode 100644 index 00000000000000..6e2858811097f0 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/options.move @@ -0,0 +1,27 @@ +//# publish +module 0x42::map_opt { + use std::option; + /// Maps the content of an option + public 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| e + 1); + option::extract(&mut x) + } +} + +//# run 0x42::Test::test diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda.exp new file mode 100644 index 00000000000000..15f7595d4ddefa --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `Test::apply` has a function parameter: + ┌─ tests/lambda/inline-parity/return_in_lambda.move:3:9 + │ +3 │ fun apply(f:|u64, u64| u64, x: u64, y: u64): u64 { + │ ^^^^^ - Parameter `f` has function-valued type `|(u64, u64)|u64`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda.lambda.exp new file mode 100644 index 00000000000000..bf94c6a9de6536 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda.lambda.exp @@ -0,0 +1,221 @@ +// -- Model dump before env processor pipeline: +module 0x42::Test { + private fun adder(x: u64,y: u64): u64 { + Add(x, y) + } + private fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun main(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor unused checks: +module 0x42::Test { + private fun adder(x: u64,y: u64): u64 { + Add(x, y) + } + private fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun main(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor type parameter check: +module 0x42::Test { + private fun adder(x: u64,y: u64): u64 { + Add(x, y) + } + private fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun main(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::Test { + private fun adder(x: u64,y: u64): u64 { + Add(x, y) + } + private fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun main(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::Test { + private fun adder(x: u64,y: u64): u64 { + Add(x, y) + } + private fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun main(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor unused struct params check: +module 0x42::Test { + private fun adder(x: u64,y: u64): u64 { + Add(x, y) + } + private fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun main(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::Test { + private fun adder(x: u64,y: u64): u64 { + Add(x, y) + } + private fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun main(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor inlining: +module 0x42::Test { + private fun adder(x: u64,y: u64): u64 { + Add(x, y) + } + private fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun main(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::Test { + private fun adder(x: u64,y: u64): u64 { + Add(x, y) + } + private fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun main(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor acquires check: +module 0x42::Test { + private fun adder(x: u64,y: u64): u64 { + Add(x, y) + } + private fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun main(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor simplifier: +module 0x42::Test { + private fun adder(x: u64,y: u64): u64 { + Add(x, y) + } + private fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun main(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor lambda-lifting: +module 0x42::Test { + private fun adder(x: u64,y: u64): u64 { + Add(x, y) + } + private fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun main(): u64 { + Test::apply(closure Test::main$lambda$1(), 10, 100) + } + private fun main$lambda$1(x: u64,y: u64): u64 { + return Test::adder(x, y) + } +} // end 0x42::Test + + +// -- Model dump after env processor specification checker: +module 0x42::Test { + private fun adder(x: u64,y: u64): u64 { + Add(x, y) + } + private fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun main(): u64 { + Test::apply(closure Test::main$lambda$1(), 10, 100) + } + private fun main$lambda$1(x: u64,y: u64): u64 { + return Test::adder(x, y) + } +} // end 0x42::Test + + +// -- Model dump after env processor specification rewriter: +module 0x42::Test { + private fun adder(x: u64,y: u64): u64 { + Add(x, y) + } + private fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun main(): u64 { + Test::apply(closure Test::main$lambda$1(), 10, 100) + } + private fun main$lambda$1(x: u64,y: u64): u64 { + return Test::adder(x, y) + } +} // end 0x42::Test + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/return_in_lambda.move:4:9 + │ +4 │ f(x, y) + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/return_in_lambda.move:12:15 + │ +12 │ apply(|x, y| { + │ ╭───────────────^ +13 │ │ return adder(x, y) +14 │ │ }, 10, 100) + │ ╰─────────^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda.move new file mode 100644 index 00000000000000..7569b0ad224dc4 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda.move @@ -0,0 +1,16 @@ +module 0x42::Test { + + fun apply(f:|u64, u64| u64, x: u64, y: u64): u64 { + f(x, y) + } + + fun adder(x: u64, y: u64): u64 { + x + y + } + + public fun main(): u64 { + apply(|x, y| { + return adder(x, y) + }, 10, 100) + } +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda_typed.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda_typed.exp new file mode 100644 index 00000000000000..b73d94965e8442 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda_typed.exp @@ -0,0 +1,19 @@ + +Diagnostics: +error: Return not currently supported in function-typed arguments (lambda expressions) + ┌─ tests/lambda/inline-parity/return_in_lambda_typed.move:13:13 + │ +13 │ return adder(x, y) + │ ^^^^^^^^^^^^^^^^^^ + +error: Return not currently supported in function-typed arguments (lambda expressions) + ┌─ tests/lambda/inline-parity/return_in_lambda_typed.move:16:13 + │ +16 │ return adder(x, y) + │ ^^^^^^^^^^^^^^^^^^ + +error: Return not currently supported in function-typed arguments (lambda expressions) + ┌─ tests/lambda/inline-parity/return_in_lambda_typed.move:19:13 + │ +19 │ return adder(x, y) + │ ^^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda_typed.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda_typed.lambda.exp new file mode 100644 index 00000000000000..1b2616f347de8c --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda_typed.lambda.exp @@ -0,0 +1,131 @@ +// -- Model dump before env processor pipeline: +module 0x42::Test { + private inline fun adder(x: u64,y: u64): u64 { + Add(x, y) + } + private inline fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun main(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100); + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100); + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor unused checks: +module 0x42::Test { + private inline fun adder(x: u64,y: u64): u64 { + Add(x, y) + } + private inline fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun main(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100); + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100); + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor type parameter check: +module 0x42::Test { + private inline fun adder(x: u64,y: u64): u64 { + Add(x, y) + } + private inline fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun main(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100); + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100); + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::Test { + private inline fun adder(x: u64,y: u64): u64 { + Add(x, y) + } + private inline fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun main(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100); + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100); + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::Test { + private inline fun adder(x: u64,y: u64): u64 { + Add(x, y) + } + private inline fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun main(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100); + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100); + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor unused struct params check: +module 0x42::Test { + private inline fun adder(x: u64,y: u64): u64 { + Add(x, y) + } + private inline fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun main(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100); + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100); + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100) + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::Test { + private inline fun adder(x: u64,y: u64): u64 { + Add(x, y) + } + private inline fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { + (f)(x, y) + } + public fun main(): u64 { + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100); + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100); + Test::apply(|(x: u64, y: u64): (u64, u64)| return Test::adder(x, y), 10, 100) + } +} // end 0x42::Test + + + +Diagnostics: +error: Return not currently supported in function-typed arguments (lambda expressions) + ┌─ tests/lambda/inline-parity/return_in_lambda_typed.move:13:13 + │ +13 │ return adder(x, y) + │ ^^^^^^^^^^^^^^^^^^ + +error: Return not currently supported in function-typed arguments (lambda expressions) + ┌─ tests/lambda/inline-parity/return_in_lambda_typed.move:16:13 + │ +16 │ return adder(x, y) + │ ^^^^^^^^^^^^^^^^^^ + +error: Return not currently supported in function-typed arguments (lambda expressions) + ┌─ tests/lambda/inline-parity/return_in_lambda_typed.move:19:13 + │ +19 │ return adder(x, y) + │ ^^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda_typed.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda_typed.move new file mode 100644 index 00000000000000..c59650aec47342 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/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/lambda/inline-parity/same_names.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/same_names.exp new file mode 100644 index 00000000000000..089b3b5b4073fc --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/same_names.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `c::foo` has a function parameter: + ┌─ tests/lambda/inline-parity/same_names.move:23:9 + │ +23 │ fun foo(f: |a::MyList, b::MyOtherList|, x: a::MyList, y: b::MyOtherList) { + │ ^^^ - Parameter `f` has function-valued type `|(a::MyList, b::MyOtherList)|`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/same_names.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/same_names.lambda.exp new file mode 100644 index 00000000000000..a5144fc3139860 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/same_names.lambda.exp @@ -0,0 +1,484 @@ +// -- Model dump before env processor 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 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) { + c::foo(|(x: a::MyList, y: b::MyOtherList): (a::MyList, b::MyOtherList)| if Eq(Add(a::len(Borrow(Immutable)(x)), b::len(Borrow(Immutable)(y))), 1) { + Tuple() + } else { + Abort(1) + }, x, y) + } +} // end 0x42::c + + +// -- Model dump after env processor unused checks: +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 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) { + c::foo(|(x: a::MyList, y: b::MyOtherList): (a::MyList, b::MyOtherList)| if Eq(Add(a::len(Borrow(Immutable)(x)), b::len(Borrow(Immutable)(y))), 1) { + Tuple() + } else { + Abort(1) + }, x, y) + } +} // end 0x42::c + + +// -- Model dump after env processor type parameter check: +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 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) { + c::foo(|(x: a::MyList, y: b::MyOtherList): (a::MyList, b::MyOtherList)| if Eq(Add(a::len(Borrow(Immutable)(x)), b::len(Borrow(Immutable)(y))), 1) { + Tuple() + } else { + Abort(1) + }, x, y) + } +} // end 0x42::c + + +// -- Model dump after env processor check recursive struct definition: +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 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) { + c::foo(|(x: a::MyList, y: b::MyOtherList): (a::MyList, b::MyOtherList)| if Eq(Add(a::len(Borrow(Immutable)(x)), b::len(Borrow(Immutable)(y))), 1) { + Tuple() + } else { + Abort(1) + }, x, y) + } +} // end 0x42::c + + +// -- Model dump after env processor check cyclic type instantiation: +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 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) { + c::foo(|(x: a::MyList, y: b::MyOtherList): (a::MyList, b::MyOtherList)| if Eq(Add(a::len(Borrow(Immutable)(x)), b::len(Borrow(Immutable)(y))), 1) { + Tuple() + } else { + Abort(1) + }, x, y) + } +} // end 0x42::c + + +// -- Model dump after env processor unused struct params check: +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 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) { + c::foo(|(x: a::MyList, y: b::MyOtherList): (a::MyList, b::MyOtherList)| if Eq(Add(a::len(Borrow(Immutable)(x)), b::len(Borrow(Immutable)(y))), 1) { + Tuple() + } else { + Abort(1) + }, x, y) + } +} // end 0x42::c + + +// -- Model dump after env processor access and use check before inlining: +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 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) { + c::foo(|(x: a::MyList, y: b::MyOtherList): (a::MyList, b::MyOtherList)| if Eq(Add(a::len(Borrow(Immutable)(x)), b::len(Borrow(Immutable)(y))), 1) { + Tuple() + } else { + Abort(1) + }, x, y) + } +} // end 0x42::c + + +// -- Model dump after env processor inlining: +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 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) { + c::foo(|(x: a::MyList, y: b::MyOtherList): (a::MyList, b::MyOtherList)| if Eq(Add(a::len(Borrow(Immutable)(x)), b::len(Borrow(Immutable)(y))), 1) { + Tuple() + } else { + Abort(1) + }, x, y) + } +} // end 0x42::c + + +// -- Model dump after env processor access and use check after inlining: +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 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) { + c::foo(|(x: a::MyList, y: b::MyOtherList): (a::MyList, b::MyOtherList)| if Eq(Add(a::len(Borrow(Immutable)(x)), b::len(Borrow(Immutable)(y))), 1) { + Tuple() + } else { + Abort(1) + }, x, y) + } +} // end 0x42::c + + +// -- Model dump after env processor acquires check: +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 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) { + c::foo(|(x: a::MyList, y: b::MyOtherList): (a::MyList, b::MyOtherList)| if Eq(Add(a::len(Borrow(Immutable)(x)), b::len(Borrow(Immutable)(y))), 1) { + Tuple() + } else { + Abort(1) + }, x, y) + } +} // end 0x42::c + + +// -- Model dump after env processor simplifier: +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 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) { + c::foo(|(x: a::MyList, y: b::MyOtherList): (a::MyList, b::MyOtherList)| if Eq(Add(a::len(Borrow(Immutable)(x)), b::len(Borrow(Immutable)(y))), 1) { + Tuple() + } else { + Abort(1) + }, x, y) + } +} // end 0x42::c + + +// -- Model dump after env processor lambda-lifting: +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 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) { + c::foo(closure c::test$lambda$1(), x, y) + } + private fun test$lambda$1(x: a::MyList,y: b::MyOtherList) { + if Eq(Add(a::len(Borrow(Immutable)(x)), b::len(Borrow(Immutable)(y))), 1) { + Tuple() + } else { + Abort(1) + } + } +} // end 0x42::c + + +// -- Model dump after env processor specification checker: +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 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) { + c::foo(closure c::test$lambda$1(), x, y) + } + private fun test$lambda$1(x: a::MyList,y: b::MyOtherList) { + if Eq(Add(a::len(Borrow(Immutable)(x)), b::len(Borrow(Immutable)(y))), 1) { + Tuple() + } else { + Abort(1) + } + } +} // end 0x42::c + + +// -- Model dump after env processor specification rewriter: +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 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) { + c::foo(closure c::test$lambda$1(), x, y) + } + private fun test$lambda$1(x: a::MyList,y: b::MyOtherList) { + if Eq(Add(a::len(Borrow(Immutable)(x)), b::len(Borrow(Immutable)(y))), 1) { + Tuple() + } else { + Abort(1) + } + } +} // end 0x42::c + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/same_names.move:24:9 + │ +24 │ f(x, y) + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/same_names.move:30:13 + │ +30 │ foo(|x, y| { assert!(x.len() + y.len() == 1, 1) }, x, y) + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/same_names.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/same_names.move new file mode 100644 index 00000000000000..96da2dced213fa --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/same_names.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; + + 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, y| { assert!(x.len() + y.len() == 1, 1) }, x, y) + } +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing.exp new file mode 100644 index 00000000000000..58180b821d64fc --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `Test::foo` has a function parameter: + ┌─ tests/lambda/inline-parity/shadowing.move:4:16 + │ +4 │ public fun foo(f:|u64|) { + │ ^^^ - Parameter `f` has function-valued type `|u64|`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing.lambda.exp new file mode 100644 index 00000000000000..813306a5f3a941 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing.lambda.exp @@ -0,0 +1,257 @@ +// -- Model dump before env processor pipeline: +module 0x42::Test { + public fun foo(f: |u64|) { + { + let _x: u64 = 3; + (f)(_x); + Tuple() + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + Test::foo(|y: u64| _x: u64 = y); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor unused checks: +module 0x42::Test { + public fun foo(f: |u64|) { + { + let _x: u64 = 3; + (f)(_x); + Tuple() + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + Test::foo(|y: u64| _x: u64 = y); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor type parameter check: +module 0x42::Test { + public fun foo(f: |u64|) { + { + let _x: u64 = 3; + (f)(_x); + Tuple() + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + Test::foo(|y: u64| _x: u64 = y); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::Test { + public fun foo(f: |u64|) { + { + let _x: u64 = 3; + (f)(_x); + Tuple() + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + Test::foo(|y: u64| _x: u64 = y); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::Test { + public fun foo(f: |u64|) { + { + let _x: u64 = 3; + (f)(_x); + Tuple() + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + Test::foo(|y: u64| _x: u64 = y); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor unused struct params check: +module 0x42::Test { + public fun foo(f: |u64|) { + { + let _x: u64 = 3; + (f)(_x); + Tuple() + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + Test::foo(|y: u64| _x: u64 = y); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::Test { + public fun foo(f: |u64|) { + { + let _x: u64 = 3; + (f)(_x); + Tuple() + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + Test::foo(|y: u64| _x: u64 = y); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor inlining: +module 0x42::Test { + public fun foo(f: |u64|) { + { + let _x: u64 = 3; + (f)(_x); + Tuple() + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + Test::foo(|y: u64| _x: u64 = y); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::Test { + public fun foo(f: |u64|) { + { + let _x: u64 = 3; + (f)(_x); + Tuple() + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + Test::foo(|y: u64| _x: u64 = y); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor acquires check: +module 0x42::Test { + public fun foo(f: |u64|) { + { + let _x: u64 = 3; + (f)(_x); + Tuple() + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + Test::foo(|y: u64| _x: u64 = y); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor simplifier: +module 0x42::Test { + public fun foo(f: |u64|) { + (f)(3); + Tuple() + } + public fun test_shadowing() { + { + let _x: u64 = 1; + Test::foo(|y: u64| _x: u64 = y); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + + +Diagnostics: +error: captured variable `_x` cannot be modified inside of a lambda + ┌─ tests/lambda/inline-parity/shadowing.move:12:13 + │ +12 │ _x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would + │ ^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing.move new file mode 100644 index 00000000000000..1819450ab9a6ca --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing.move @@ -0,0 +1,21 @@ +//# publish +module 0x42::Test { + + public fun foo(f:|u64|) { + let _x = 3; + f(_x); + } + + public fun test_shadowing() { + let _x = 1; + foo(|y| { + _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/tests/lambda/inline-parity/shadowing_renamed.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed.exp new file mode 100644 index 00000000000000..7b595fd63e9516 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `Test::foo` has a function parameter: + ┌─ tests/lambda/inline-parity/shadowing_renamed.move:4:16 + │ +4 │ public fun foo(f:|u64|) { + │ ^^^ - Parameter `f` has function-valued type `|u64|`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed.lambda.exp new file mode 100644 index 00000000000000..57fbdb400d0028 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed.lambda.exp @@ -0,0 +1,257 @@ +// -- Model dump before env processor pipeline: +module 0x42::Test { + public fun foo(f: |u64|) { + { + let x: u64 = 3; + (f)(x); + Tuple() + } + } + public fun test_shadowing() { + { + let x: u64 = 1; + Test::foo(|y: u64| x: u64 = y); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor unused checks: +module 0x42::Test { + public fun foo(f: |u64|) { + { + let x: u64 = 3; + (f)(x); + Tuple() + } + } + public fun test_shadowing() { + { + let x: u64 = 1; + Test::foo(|y: u64| x: u64 = y); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor type parameter check: +module 0x42::Test { + public fun foo(f: |u64|) { + { + let x: u64 = 3; + (f)(x); + Tuple() + } + } + public fun test_shadowing() { + { + let x: u64 = 1; + Test::foo(|y: u64| x: u64 = y); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::Test { + public fun foo(f: |u64|) { + { + let x: u64 = 3; + (f)(x); + Tuple() + } + } + public fun test_shadowing() { + { + let x: u64 = 1; + Test::foo(|y: u64| x: u64 = y); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::Test { + public fun foo(f: |u64|) { + { + let x: u64 = 3; + (f)(x); + Tuple() + } + } + public fun test_shadowing() { + { + let x: u64 = 1; + Test::foo(|y: u64| x: u64 = y); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor unused struct params check: +module 0x42::Test { + public fun foo(f: |u64|) { + { + let x: u64 = 3; + (f)(x); + Tuple() + } + } + public fun test_shadowing() { + { + let x: u64 = 1; + Test::foo(|y: u64| x: u64 = y); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::Test { + public fun foo(f: |u64|) { + { + let x: u64 = 3; + (f)(x); + Tuple() + } + } + public fun test_shadowing() { + { + let x: u64 = 1; + Test::foo(|y: u64| x: u64 = y); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor inlining: +module 0x42::Test { + public fun foo(f: |u64|) { + { + let x: u64 = 3; + (f)(x); + Tuple() + } + } + public fun test_shadowing() { + { + let x: u64 = 1; + Test::foo(|y: u64| x: u64 = y); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::Test { + public fun foo(f: |u64|) { + { + let x: u64 = 3; + (f)(x); + Tuple() + } + } + public fun test_shadowing() { + { + let x: u64 = 1; + Test::foo(|y: u64| x: u64 = y); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor acquires check: +module 0x42::Test { + public fun foo(f: |u64|) { + { + let x: u64 = 3; + (f)(x); + Tuple() + } + } + public fun test_shadowing() { + { + let x: u64 = 1; + Test::foo(|y: u64| x: u64 = y); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor simplifier: +module 0x42::Test { + public fun foo(f: |u64|) { + (f)(3); + Tuple() + } + public fun test_shadowing() { + { + let x: u64 = 1; + Test::foo(|y: u64| x: u64 = y); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + + +Diagnostics: +error: captured variable `x` cannot be modified inside of a lambda + ┌─ tests/lambda/inline-parity/shadowing_renamed.move:12:13 + │ +12 │ x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would + │ ^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed.move new file mode 100644 index 00000000000000..39d928dd78722b --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed.move @@ -0,0 +1,21 @@ +//# publish +module 0x42::Test { + + public fun foo(f:|u64|) { + let x = 3; + f(x); + } + + public fun test_shadowing() { + let x = 1; + foo(|y| { + 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/tests/lambda/inline-parity/shadowing_renamed_param.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed_param.exp new file mode 100644 index 00000000000000..b4a20c8a70bd1e --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed_param.exp @@ -0,0 +1,13 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `Test::foo` has a function parameter: + ┌─ tests/lambda/inline-parity/shadowing_renamed_param.move:4:16 + │ +4 │ public fun foo(f:|u64|, x:u64) { + │ ^^^ - Parameter `f` has function-valued type `|u64|`. + +error: Only inline functions may have function-typed parameters, but non-inline function `Test::foo2` has a function parameter: + ┌─ tests/lambda/inline-parity/shadowing_renamed_param.move:8:16 + │ +8 │ public fun foo2(f:|u64|, x:u64) { + │ ^^^^ - Parameter `f` has function-valued type `|u64|`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed_param.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed_param.lambda.exp new file mode 100644 index 00000000000000..bf8fa10008821b --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed_param.lambda.exp @@ -0,0 +1,586 @@ +// -- Model dump before env processor pipeline: +module 0x42::Test { + public fun foo(f: |u64|,x: u64) { + (f)(x); + Tuple() + } + public fun foo2(f: |u64|,x: u64) { + { + let x: u64 = x; + (f)(x); + Tuple() + } + } + public fun test_shadowing(x: u64) { + Test::foo(|y: u64| x: u64 = y, 3); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + }; + Test::foo2(|y: u64| x: u64 = y, 5); + if Eq(x, 5) { + Tuple() + } else { + Abort(0) + } + } + public fun test_shadowing2(q: u64) { + { + let x: u64 = q; + Test::foo(|y: u64| x: u64 = y, 3); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + }; + Test::foo2(|y: u64| x: u64 = y, 5); + if Eq(x, 5) { + Tuple() + } else { + Abort(0) + } + } + } + private fun test_shadowing_entry() { + Test::test_shadowing(1); + Test::test_shadowing2(1) + } +} // end 0x42::Test + + +// -- Model dump after env processor unused checks: +module 0x42::Test { + public fun foo(f: |u64|,x: u64) { + (f)(x); + Tuple() + } + public fun foo2(f: |u64|,x: u64) { + { + let x: u64 = x; + (f)(x); + Tuple() + } + } + public fun test_shadowing(x: u64) { + Test::foo(|y: u64| x: u64 = y, 3); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + }; + Test::foo2(|y: u64| x: u64 = y, 5); + if Eq(x, 5) { + Tuple() + } else { + Abort(0) + } + } + public fun test_shadowing2(q: u64) { + { + let x: u64 = q; + Test::foo(|y: u64| x: u64 = y, 3); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + }; + Test::foo2(|y: u64| x: u64 = y, 5); + if Eq(x, 5) { + Tuple() + } else { + Abort(0) + } + } + } + private fun test_shadowing_entry() { + Test::test_shadowing(1); + Test::test_shadowing2(1) + } +} // end 0x42::Test + + +// -- Model dump after env processor type parameter check: +module 0x42::Test { + public fun foo(f: |u64|,x: u64) { + (f)(x); + Tuple() + } + public fun foo2(f: |u64|,x: u64) { + { + let x: u64 = x; + (f)(x); + Tuple() + } + } + public fun test_shadowing(x: u64) { + Test::foo(|y: u64| x: u64 = y, 3); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + }; + Test::foo2(|y: u64| x: u64 = y, 5); + if Eq(x, 5) { + Tuple() + } else { + Abort(0) + } + } + public fun test_shadowing2(q: u64) { + { + let x: u64 = q; + Test::foo(|y: u64| x: u64 = y, 3); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + }; + Test::foo2(|y: u64| x: u64 = y, 5); + if Eq(x, 5) { + Tuple() + } else { + Abort(0) + } + } + } + private fun test_shadowing_entry() { + Test::test_shadowing(1); + Test::test_shadowing2(1) + } +} // end 0x42::Test + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::Test { + public fun foo(f: |u64|,x: u64) { + (f)(x); + Tuple() + } + public fun foo2(f: |u64|,x: u64) { + { + let x: u64 = x; + (f)(x); + Tuple() + } + } + public fun test_shadowing(x: u64) { + Test::foo(|y: u64| x: u64 = y, 3); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + }; + Test::foo2(|y: u64| x: u64 = y, 5); + if Eq(x, 5) { + Tuple() + } else { + Abort(0) + } + } + public fun test_shadowing2(q: u64) { + { + let x: u64 = q; + Test::foo(|y: u64| x: u64 = y, 3); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + }; + Test::foo2(|y: u64| x: u64 = y, 5); + if Eq(x, 5) { + Tuple() + } else { + Abort(0) + } + } + } + private fun test_shadowing_entry() { + Test::test_shadowing(1); + Test::test_shadowing2(1) + } +} // end 0x42::Test + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::Test { + public fun foo(f: |u64|,x: u64) { + (f)(x); + Tuple() + } + public fun foo2(f: |u64|,x: u64) { + { + let x: u64 = x; + (f)(x); + Tuple() + } + } + public fun test_shadowing(x: u64) { + Test::foo(|y: u64| x: u64 = y, 3); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + }; + Test::foo2(|y: u64| x: u64 = y, 5); + if Eq(x, 5) { + Tuple() + } else { + Abort(0) + } + } + public fun test_shadowing2(q: u64) { + { + let x: u64 = q; + Test::foo(|y: u64| x: u64 = y, 3); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + }; + Test::foo2(|y: u64| x: u64 = y, 5); + if Eq(x, 5) { + Tuple() + } else { + Abort(0) + } + } + } + private fun test_shadowing_entry() { + Test::test_shadowing(1); + Test::test_shadowing2(1) + } +} // end 0x42::Test + + +// -- Model dump after env processor unused struct params check: +module 0x42::Test { + public fun foo(f: |u64|,x: u64) { + (f)(x); + Tuple() + } + public fun foo2(f: |u64|,x: u64) { + { + let x: u64 = x; + (f)(x); + Tuple() + } + } + public fun test_shadowing(x: u64) { + Test::foo(|y: u64| x: u64 = y, 3); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + }; + Test::foo2(|y: u64| x: u64 = y, 5); + if Eq(x, 5) { + Tuple() + } else { + Abort(0) + } + } + public fun test_shadowing2(q: u64) { + { + let x: u64 = q; + Test::foo(|y: u64| x: u64 = y, 3); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + }; + Test::foo2(|y: u64| x: u64 = y, 5); + if Eq(x, 5) { + Tuple() + } else { + Abort(0) + } + } + } + private fun test_shadowing_entry() { + Test::test_shadowing(1); + Test::test_shadowing2(1) + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::Test { + public fun foo(f: |u64|,x: u64) { + (f)(x); + Tuple() + } + public fun foo2(f: |u64|,x: u64) { + { + let x: u64 = x; + (f)(x); + Tuple() + } + } + public fun test_shadowing(x: u64) { + Test::foo(|y: u64| x: u64 = y, 3); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + }; + Test::foo2(|y: u64| x: u64 = y, 5); + if Eq(x, 5) { + Tuple() + } else { + Abort(0) + } + } + public fun test_shadowing2(q: u64) { + { + let x: u64 = q; + Test::foo(|y: u64| x: u64 = y, 3); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + }; + Test::foo2(|y: u64| x: u64 = y, 5); + if Eq(x, 5) { + Tuple() + } else { + Abort(0) + } + } + } + private fun test_shadowing_entry() { + Test::test_shadowing(1); + Test::test_shadowing2(1) + } +} // end 0x42::Test + + +// -- Model dump after env processor inlining: +module 0x42::Test { + public fun foo(f: |u64|,x: u64) { + (f)(x); + Tuple() + } + public fun foo2(f: |u64|,x: u64) { + { + let x: u64 = x; + (f)(x); + Tuple() + } + } + public fun test_shadowing(x: u64) { + Test::foo(|y: u64| x: u64 = y, 3); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + }; + Test::foo2(|y: u64| x: u64 = y, 5); + if Eq(x, 5) { + Tuple() + } else { + Abort(0) + } + } + public fun test_shadowing2(q: u64) { + { + let x: u64 = q; + Test::foo(|y: u64| x: u64 = y, 3); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + }; + Test::foo2(|y: u64| x: u64 = y, 5); + if Eq(x, 5) { + Tuple() + } else { + Abort(0) + } + } + } + private fun test_shadowing_entry() { + Test::test_shadowing(1); + Test::test_shadowing2(1) + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::Test { + public fun foo(f: |u64|,x: u64) { + (f)(x); + Tuple() + } + public fun foo2(f: |u64|,x: u64) { + { + let x: u64 = x; + (f)(x); + Tuple() + } + } + public fun test_shadowing(x: u64) { + Test::foo(|y: u64| x: u64 = y, 3); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + }; + Test::foo2(|y: u64| x: u64 = y, 5); + if Eq(x, 5) { + Tuple() + } else { + Abort(0) + } + } + public fun test_shadowing2(q: u64) { + { + let x: u64 = q; + Test::foo(|y: u64| x: u64 = y, 3); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + }; + Test::foo2(|y: u64| x: u64 = y, 5); + if Eq(x, 5) { + Tuple() + } else { + Abort(0) + } + } + } + private fun test_shadowing_entry() { + Test::test_shadowing(1); + Test::test_shadowing2(1) + } +} // end 0x42::Test + + +// -- Model dump after env processor acquires check: +module 0x42::Test { + public fun foo(f: |u64|,x: u64) { + (f)(x); + Tuple() + } + public fun foo2(f: |u64|,x: u64) { + { + let x: u64 = x; + (f)(x); + Tuple() + } + } + public fun test_shadowing(x: u64) { + Test::foo(|y: u64| x: u64 = y, 3); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + }; + Test::foo2(|y: u64| x: u64 = y, 5); + if Eq(x, 5) { + Tuple() + } else { + Abort(0) + } + } + public fun test_shadowing2(q: u64) { + { + let x: u64 = q; + Test::foo(|y: u64| x: u64 = y, 3); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + }; + Test::foo2(|y: u64| x: u64 = y, 5); + if Eq(x, 5) { + Tuple() + } else { + Abort(0) + } + } + } + private fun test_shadowing_entry() { + Test::test_shadowing(1); + Test::test_shadowing2(1) + } +} // end 0x42::Test + + +// -- Model dump after env processor simplifier: +module 0x42::Test { + public fun foo(f: |u64|,x: u64) { + (f)(x); + Tuple() + } + public fun foo2(f: |u64|,x: u64) { + { + let x: u64 = x; + (f)(x); + Tuple() + } + } + public fun test_shadowing(x: u64) { + Test::foo(|y: u64| x: u64 = y, 3); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + }; + Test::foo2(|y: u64| x: u64 = y, 5); + if Eq(x, 5) { + Tuple() + } else { + Abort(0) + } + } + public fun test_shadowing2(q: u64) { + { + let x: u64 = q; + Test::foo(|y: u64| x: u64 = y, 3); + if Eq(x, 3) { + Tuple() + } else { + Abort(0) + }; + Test::foo2(|y: u64| x: u64 = y, 5); + if Eq(x, 5) { + Tuple() + } else { + Abort(0) + } + } + } + private fun test_shadowing_entry() { + Test::test_shadowing(1); + Test::test_shadowing2(1) + } +} // end 0x42::Test + + + +Diagnostics: +error: captured variable `x` cannot be modified inside of a lambda + ┌─ tests/lambda/inline-parity/shadowing_renamed_param.move:15:13 + │ +15 │ x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would + │ ^ + +error: captured variable `x` cannot be modified inside of a lambda + ┌─ tests/lambda/inline-parity/shadowing_renamed_param.move:21:13 + │ +21 │ x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would + │ ^ + +error: captured variable `x` cannot be modified inside of a lambda + ┌─ tests/lambda/inline-parity/shadowing_renamed_param.move:30:13 + │ +30 │ x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would + │ ^ + +error: captured variable `x` cannot be modified inside of a lambda + ┌─ tests/lambda/inline-parity/shadowing_renamed_param.move:36:13 + │ +36 │ x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would + │ ^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed_param.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed_param.move new file mode 100644 index 00000000000000..12c3e77c622c2d --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed_param.move @@ -0,0 +1,48 @@ +//# publish +module 0x42::Test { + + public fun foo(f:|u64|, x:u64) { + f(x); + } + + public fun foo2(f:|u64|, x:u64) { + let x = x; + f(x); + } + + public fun test_shadowing(x: u64) { + foo(|y| { + 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| { + 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| { + 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| { + 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/tests/lambda/inline-parity/shadowing_unused.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused.exp new file mode 100644 index 00000000000000..1f16e989885609 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused.exp @@ -0,0 +1,13 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `Test::quux` has a function parameter: + ┌─ tests/lambda/inline-parity/shadowing_unused.move:4:16 + │ +4 │ public fun quux(f:|u64, u64|, _z: u64) { + │ ^^^^ - Parameter `f` has function-valued type `|(u64, u64)|`. + +error: Only inline functions may have function-typed parameters, but non-inline function `Test::foo` has a function parameter: + ┌─ tests/lambda/inline-parity/shadowing_unused.move:10:16 + │ +10 │ public fun foo(f:|u64, u64|, z: u64) { + │ ^^^ - Parameter `f` has function-valued type `|(u64, u64)|`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused.lambda.exp new file mode 100644 index 00000000000000..7c4b85b3b42918 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused.lambda.exp @@ -0,0 +1,518 @@ +// -- Model dump before env processor pipeline: +module 0x42::Test { + public fun foo(f: |(u64, u64)|,z: u64) { + Test::quux(|(a: u64, b: u64): (u64, u64)| (f)(a, b), z); + Tuple() + } + public fun quux(f: |(u64, u64)|,_z: u64) { + { + let x: u64 = 3; + { + let q: u64 = 5; + (f)(x, q); + Tuple() + } + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::foo(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } + public fun test_shadowing2() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::quux(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor unused checks: +module 0x42::Test { + public fun foo(f: |(u64, u64)|,z: u64) { + Test::quux(|(a: u64, b: u64): (u64, u64)| (f)(a, b), z); + Tuple() + } + public fun quux(f: |(u64, u64)|,_z: u64) { + { + let x: u64 = 3; + { + let q: u64 = 5; + (f)(x, q); + Tuple() + } + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::foo(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } + public fun test_shadowing2() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::quux(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor type parameter check: +module 0x42::Test { + public fun foo(f: |(u64, u64)|,z: u64) { + Test::quux(|(a: u64, b: u64): (u64, u64)| (f)(a, b), z); + Tuple() + } + public fun quux(f: |(u64, u64)|,_z: u64) { + { + let x: u64 = 3; + { + let q: u64 = 5; + (f)(x, q); + Tuple() + } + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::foo(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } + public fun test_shadowing2() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::quux(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::Test { + public fun foo(f: |(u64, u64)|,z: u64) { + Test::quux(|(a: u64, b: u64): (u64, u64)| (f)(a, b), z); + Tuple() + } + public fun quux(f: |(u64, u64)|,_z: u64) { + { + let x: u64 = 3; + { + let q: u64 = 5; + (f)(x, q); + Tuple() + } + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::foo(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } + public fun test_shadowing2() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::quux(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::Test { + public fun foo(f: |(u64, u64)|,z: u64) { + Test::quux(|(a: u64, b: u64): (u64, u64)| (f)(a, b), z); + Tuple() + } + public fun quux(f: |(u64, u64)|,_z: u64) { + { + let x: u64 = 3; + { + let q: u64 = 5; + (f)(x, q); + Tuple() + } + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::foo(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } + public fun test_shadowing2() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::quux(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor unused struct params check: +module 0x42::Test { + public fun foo(f: |(u64, u64)|,z: u64) { + Test::quux(|(a: u64, b: u64): (u64, u64)| (f)(a, b), z); + Tuple() + } + public fun quux(f: |(u64, u64)|,_z: u64) { + { + let x: u64 = 3; + { + let q: u64 = 5; + (f)(x, q); + Tuple() + } + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::foo(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } + public fun test_shadowing2() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::quux(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::Test { + public fun foo(f: |(u64, u64)|,z: u64) { + Test::quux(|(a: u64, b: u64): (u64, u64)| (f)(a, b), z); + Tuple() + } + public fun quux(f: |(u64, u64)|,_z: u64) { + { + let x: u64 = 3; + { + let q: u64 = 5; + (f)(x, q); + Tuple() + } + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::foo(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } + public fun test_shadowing2() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::quux(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor inlining: +module 0x42::Test { + public fun foo(f: |(u64, u64)|,z: u64) { + Test::quux(|(a: u64, b: u64): (u64, u64)| (f)(a, b), z); + Tuple() + } + public fun quux(f: |(u64, u64)|,_z: u64) { + { + let x: u64 = 3; + { + let q: u64 = 5; + (f)(x, q); + Tuple() + } + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::foo(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } + public fun test_shadowing2() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::quux(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::Test { + public fun foo(f: |(u64, u64)|,z: u64) { + Test::quux(|(a: u64, b: u64): (u64, u64)| (f)(a, b), z); + Tuple() + } + public fun quux(f: |(u64, u64)|,_z: u64) { + { + let x: u64 = 3; + { + let q: u64 = 5; + (f)(x, q); + Tuple() + } + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::foo(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } + public fun test_shadowing2() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::quux(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor acquires check: +module 0x42::Test { + public fun foo(f: |(u64, u64)|,z: u64) { + Test::quux(|(a: u64, b: u64): (u64, u64)| (f)(a, b), z); + Tuple() + } + public fun quux(f: |(u64, u64)|,_z: u64) { + { + let x: u64 = 3; + { + let q: u64 = 5; + (f)(x, q); + Tuple() + } + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::foo(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } + public fun test_shadowing2() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::quux(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor simplifier: +module 0x42::Test { + public fun foo(f: |(u64, u64)|,z: u64) { + Test::quux(|(a: u64, b: u64): (u64, u64)| (f)(a, b), z); + Tuple() + } + public fun quux(f: |(u64, u64)|,_z: u64) { + (f)(3, 5); + Tuple() + } + public fun test_shadowing() { + { + let _x: u64 = 1; + Test::foo(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, 4); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + public fun test_shadowing2() { + { + let _x: u64 = 1; + Test::quux(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, 4); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + + +Diagnostics: +error: captured variable `_x` cannot be modified inside of a lambda + ┌─ tests/lambda/inline-parity/shadowing_unused.move:18:13 + │ +18 │ _x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would + │ ^^ + +error: captured variable `_x` cannot be modified inside of a lambda + ┌─ tests/lambda/inline-parity/shadowing_unused.move:28:13 + │ +28 │ _x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would + │ ^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused.move new file mode 100644 index 00000000000000..9a7cfdf859b865 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused.move @@ -0,0 +1,35 @@ +//# publish +module 0x42::Test { + + public fun quux(f:|u64, u64|, _z: u64) { + let x = 3; + let q = 5; + f(x, q); + } + + public fun foo(f:|u64, u64|, z: u64) { + quux(|a, b| f(a, b), z); + } + + public fun test_shadowing() { + let _x = 1; + let z = 4; + foo(|y, _q| { + _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, _q| { + _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/lambda/inline-parity/shadowing_unused_nodecl.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused_nodecl.exp new file mode 100644 index 00000000000000..1bbf57a5862b5c --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused_nodecl.exp @@ -0,0 +1,19 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `Test::quux` has a function parameter: + ┌─ tests/lambda/inline-parity/shadowing_unused_nodecl.move:6:16 + │ +6 │ public fun quux(f:|u64, u64|, z: u64) { + │ ^^^^ - Parameter `f` has function-valued type `|(u64, u64)|`. + +warning: Unused parameter `z`. Consider removing or prefixing with an underscore: `_z` + ┌─ tests/lambda/inline-parity/shadowing_unused_nodecl.move:6:35 + │ +6 │ public fun quux(f:|u64, u64|, z: u64) { + │ ^ + +error: Only inline functions may have function-typed parameters, but non-inline function `Test::foo` has a function parameter: + ┌─ tests/lambda/inline-parity/shadowing_unused_nodecl.move:12:16 + │ +12 │ public fun foo(f:|u64, u64|, z: u64) { + │ ^^^ - Parameter `f` has function-valued type `|(u64, u64)|`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused_nodecl.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused_nodecl.lambda.exp new file mode 100644 index 00000000000000..ccbae64fbd2f77 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused_nodecl.lambda.exp @@ -0,0 +1,524 @@ +// -- Model dump before env processor pipeline: +module 0x42::Test { + public fun foo(f: |(u64, u64)|,z: u64) { + Test::quux(|(a: u64, b: u64): (u64, u64)| (f)(a, b), z); + Tuple() + } + public fun quux(f: |(u64, u64)|,z: u64) { + { + let x: u64 = 3; + { + let q: u64 = 5; + (f)(x, q); + Tuple() + } + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::foo(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } + public fun test_shadowing2() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::quux(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor unused checks: +module 0x42::Test { + public fun foo(f: |(u64, u64)|,z: u64) { + Test::quux(|(a: u64, b: u64): (u64, u64)| (f)(a, b), z); + Tuple() + } + public fun quux(f: |(u64, u64)|,z: u64) { + { + let x: u64 = 3; + { + let q: u64 = 5; + (f)(x, q); + Tuple() + } + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::foo(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } + public fun test_shadowing2() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::quux(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor type parameter check: +module 0x42::Test { + public fun foo(f: |(u64, u64)|,z: u64) { + Test::quux(|(a: u64, b: u64): (u64, u64)| (f)(a, b), z); + Tuple() + } + public fun quux(f: |(u64, u64)|,z: u64) { + { + let x: u64 = 3; + { + let q: u64 = 5; + (f)(x, q); + Tuple() + } + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::foo(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } + public fun test_shadowing2() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::quux(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::Test { + public fun foo(f: |(u64, u64)|,z: u64) { + Test::quux(|(a: u64, b: u64): (u64, u64)| (f)(a, b), z); + Tuple() + } + public fun quux(f: |(u64, u64)|,z: u64) { + { + let x: u64 = 3; + { + let q: u64 = 5; + (f)(x, q); + Tuple() + } + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::foo(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } + public fun test_shadowing2() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::quux(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::Test { + public fun foo(f: |(u64, u64)|,z: u64) { + Test::quux(|(a: u64, b: u64): (u64, u64)| (f)(a, b), z); + Tuple() + } + public fun quux(f: |(u64, u64)|,z: u64) { + { + let x: u64 = 3; + { + let q: u64 = 5; + (f)(x, q); + Tuple() + } + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::foo(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } + public fun test_shadowing2() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::quux(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor unused struct params check: +module 0x42::Test { + public fun foo(f: |(u64, u64)|,z: u64) { + Test::quux(|(a: u64, b: u64): (u64, u64)| (f)(a, b), z); + Tuple() + } + public fun quux(f: |(u64, u64)|,z: u64) { + { + let x: u64 = 3; + { + let q: u64 = 5; + (f)(x, q); + Tuple() + } + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::foo(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } + public fun test_shadowing2() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::quux(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::Test { + public fun foo(f: |(u64, u64)|,z: u64) { + Test::quux(|(a: u64, b: u64): (u64, u64)| (f)(a, b), z); + Tuple() + } + public fun quux(f: |(u64, u64)|,z: u64) { + { + let x: u64 = 3; + { + let q: u64 = 5; + (f)(x, q); + Tuple() + } + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::foo(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } + public fun test_shadowing2() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::quux(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor inlining: +module 0x42::Test { + public fun foo(f: |(u64, u64)|,z: u64) { + Test::quux(|(a: u64, b: u64): (u64, u64)| (f)(a, b), z); + Tuple() + } + public fun quux(f: |(u64, u64)|,z: u64) { + { + let x: u64 = 3; + { + let q: u64 = 5; + (f)(x, q); + Tuple() + } + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::foo(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } + public fun test_shadowing2() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::quux(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::Test { + public fun foo(f: |(u64, u64)|,z: u64) { + Test::quux(|(a: u64, b: u64): (u64, u64)| (f)(a, b), z); + Tuple() + } + public fun quux(f: |(u64, u64)|,z: u64) { + { + let x: u64 = 3; + { + let q: u64 = 5; + (f)(x, q); + Tuple() + } + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::foo(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } + public fun test_shadowing2() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::quux(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor acquires check: +module 0x42::Test { + public fun foo(f: |(u64, u64)|,z: u64) { + Test::quux(|(a: u64, b: u64): (u64, u64)| (f)(a, b), z); + Tuple() + } + public fun quux(f: |(u64, u64)|,z: u64) { + { + let x: u64 = 3; + { + let q: u64 = 5; + (f)(x, q); + Tuple() + } + } + } + public fun test_shadowing() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::foo(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } + public fun test_shadowing2() { + { + let _x: u64 = 1; + { + let z: u64 = 4; + Test::quux(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, z); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor simplifier: +module 0x42::Test { + public fun foo(f: |(u64, u64)|,z: u64) { + Test::quux(|(a: u64, b: u64): (u64, u64)| (f)(a, b), z); + Tuple() + } + public fun quux(f: |(u64, u64)|,z: u64) { + (f)(3, 5); + Tuple() + } + public fun test_shadowing() { + { + let _x: u64 = 1; + Test::foo(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, 4); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } + public fun test_shadowing2() { + { + let _x: u64 = 1; + Test::quux(|(y: u64, _q: u64): (u64, u64)| _x: u64 = y, 4); + if Eq(_x, 3) { + Tuple() + } else { + Abort(0) + } + } + } +} // end 0x42::Test + + + +Diagnostics: +warning: Unused parameter `z`. Consider removing or prefixing with an underscore: `_z` + ┌─ tests/lambda/inline-parity/shadowing_unused_nodecl.move:6:35 + │ +6 │ public fun quux(f:|u64, u64|, z: u64) { + │ ^ + +error: captured variable `_x` cannot be modified inside of a lambda + ┌─ tests/lambda/inline-parity/shadowing_unused_nodecl.move:20:13 + │ +20 │ _x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would + │ ^^ + +error: captured variable `_x` cannot be modified inside of a lambda + ┌─ tests/lambda/inline-parity/shadowing_unused_nodecl.move:30:13 + │ +30 │ _x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would + │ ^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused_nodecl.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused_nodecl.move new file mode 100644 index 00000000000000..0d1795333ca718 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused_nodecl.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 fun quux(f:|u64, u64|, z: u64) { + let x = 3; + let q = 5; + f(x, q); + } + + public fun foo(f:|u64, u64|, z: u64) { + quux(|a, b| f(a, b), z); + } + + public fun test_shadowing() { + let _x = 1; + let z = 4; + foo(|y, _q| { + _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, _q| { + _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/lambda/inline-parity/simple_map_keys.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/simple_map_keys.exp new file mode 100644 index 00000000000000..97df3c0dbcda6a --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/simple_map_keys.exp @@ -0,0 +1,16 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `simple_map::map_ref` has a function parameter: + ┌─ tests/lambda/inline-parity/simple_map_keys.move:23:15 + │ +23 │ public fun map_ref( + │ ^^^^^^^ +24 │ v: &vector, +25 │ f: |&Element|NewElement + │ - Parameter `f` has function-valued type `|&Element|NewElement`. + +error: Only inline functions may have function-typed parameters, but non-inline function `simple_map::for_each_ref` has a function parameter: + ┌─ tests/lambda/inline-parity/simple_map_keys.move:32:16 + │ +32 │ public fun for_each_ref(v: &vector, f: |&Element|) { + │ ^^^^^^^^^^^^ - Parameter `f` has function-valued type `|&Element|`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/simple_map_keys.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/simple_map_keys.lambda.exp new file mode 100644 index 00000000000000..a5c919527a57e4 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/simple_map_keys.lambda.exp @@ -0,0 +1,689 @@ +// -- Model dump before env processor pipeline: +module 0x42::simple_map { + use 0x1::vector; // resolved as: 0x1::vector + struct Element { + key: Key, + value: Value, + } + struct SimpleMap { + data: vector>, + } + public fun for_each_ref(v: &vector<#0>,f: |�|) { + { + let i: u64 = 0; + { + let len: u64 = vector::length(v); + loop { + if Lt(i, len) { + (f)(vector::borrow(v, i)); + i: u64 = Add(i, 1) + } else { + break + } + } + } + } + } + public fun keys(map: &simple_map::SimpleMap<#0, #1>): vector<#0> { + simple_map::map_ref, Key>(Borrow(Immutable)(select simple_map::SimpleMap.data<&simple_map::SimpleMap>(map)), |e: &simple_map::Element| { + let e: &simple_map::Element = e; + select simple_map::Element.key<&simple_map::Element>(e) + }) + } + public fun map_ref(v: &vector<#0>,f: |�|#1): vector<#1> { + { + let result: vector = Vector(); + simple_map::for_each_ref(v, |elem: &Element| vector::push_back(Borrow(Mutable)(result), (f)(elem))); + result + } + } + public fun run() { + { + let entry: simple_map::Element = pack simple_map::Element(1, 2); + { + let data: vector> = Vector>(entry, entry, entry); + { + let map: simple_map::SimpleMap = pack simple_map::SimpleMap(data); + { + let keys: vector = simple_map::keys(Borrow(Immutable)(map)); + if Eq>(keys, Vector(1, 1, 1)) { + Tuple() + } else { + Abort(33) + }; + Tuple() + } + } + } + } + } +} // end 0x42::simple_map + + +// -- Model dump after env processor unused checks: +module 0x42::simple_map { + use 0x1::vector; // resolved as: 0x1::vector + struct Element { + key: Key, + value: Value, + } + struct SimpleMap { + data: vector>, + } + public fun for_each_ref(v: &vector<#0>,f: |�|) { + { + let i: u64 = 0; + { + let len: u64 = vector::length(v); + loop { + if Lt(i, len) { + (f)(vector::borrow(v, i)); + i: u64 = Add(i, 1) + } else { + break + } + } + } + } + } + public fun keys(map: &simple_map::SimpleMap<#0, #1>): vector<#0> { + simple_map::map_ref, Key>(Borrow(Immutable)(select simple_map::SimpleMap.data<&simple_map::SimpleMap>(map)), |e: &simple_map::Element| { + let e: &simple_map::Element = e; + select simple_map::Element.key<&simple_map::Element>(e) + }) + } + public fun map_ref(v: &vector<#0>,f: |�|#1): vector<#1> { + { + let result: vector = Vector(); + simple_map::for_each_ref(v, |elem: &Element| vector::push_back(Borrow(Mutable)(result), (f)(elem))); + result + } + } + public fun run() { + { + let entry: simple_map::Element = pack simple_map::Element(1, 2); + { + let data: vector> = Vector>(entry, entry, entry); + { + let map: simple_map::SimpleMap = pack simple_map::SimpleMap(data); + { + let keys: vector = simple_map::keys(Borrow(Immutable)(map)); + if Eq>(keys, Vector(1, 1, 1)) { + Tuple() + } else { + Abort(33) + }; + Tuple() + } + } + } + } + } +} // end 0x42::simple_map + + +// -- Model dump after env processor type parameter check: +module 0x42::simple_map { + use 0x1::vector; // resolved as: 0x1::vector + struct Element { + key: Key, + value: Value, + } + struct SimpleMap { + data: vector>, + } + public fun for_each_ref(v: &vector<#0>,f: |�|) { + { + let i: u64 = 0; + { + let len: u64 = vector::length(v); + loop { + if Lt(i, len) { + (f)(vector::borrow(v, i)); + i: u64 = Add(i, 1) + } else { + break + } + } + } + } + } + public fun keys(map: &simple_map::SimpleMap<#0, #1>): vector<#0> { + simple_map::map_ref, Key>(Borrow(Immutable)(select simple_map::SimpleMap.data<&simple_map::SimpleMap>(map)), |e: &simple_map::Element| { + let e: &simple_map::Element = e; + select simple_map::Element.key<&simple_map::Element>(e) + }) + } + public fun map_ref(v: &vector<#0>,f: |�|#1): vector<#1> { + { + let result: vector = Vector(); + simple_map::for_each_ref(v, |elem: &Element| vector::push_back(Borrow(Mutable)(result), (f)(elem))); + result + } + } + public fun run() { + { + let entry: simple_map::Element = pack simple_map::Element(1, 2); + { + let data: vector> = Vector>(entry, entry, entry); + { + let map: simple_map::SimpleMap = pack simple_map::SimpleMap(data); + { + let keys: vector = simple_map::keys(Borrow(Immutable)(map)); + if Eq>(keys, Vector(1, 1, 1)) { + Tuple() + } else { + Abort(33) + }; + Tuple() + } + } + } + } + } +} // end 0x42::simple_map + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::simple_map { + use 0x1::vector; // resolved as: 0x1::vector + struct Element { + key: Key, + value: Value, + } + struct SimpleMap { + data: vector>, + } + public fun for_each_ref(v: &vector<#0>,f: |�|) { + { + let i: u64 = 0; + { + let len: u64 = vector::length(v); + loop { + if Lt(i, len) { + (f)(vector::borrow(v, i)); + i: u64 = Add(i, 1) + } else { + break + } + } + } + } + } + public fun keys(map: &simple_map::SimpleMap<#0, #1>): vector<#0> { + simple_map::map_ref, Key>(Borrow(Immutable)(select simple_map::SimpleMap.data<&simple_map::SimpleMap>(map)), |e: &simple_map::Element| { + let e: &simple_map::Element = e; + select simple_map::Element.key<&simple_map::Element>(e) + }) + } + public fun map_ref(v: &vector<#0>,f: |�|#1): vector<#1> { + { + let result: vector = Vector(); + simple_map::for_each_ref(v, |elem: &Element| vector::push_back(Borrow(Mutable)(result), (f)(elem))); + result + } + } + public fun run() { + { + let entry: simple_map::Element = pack simple_map::Element(1, 2); + { + let data: vector> = Vector>(entry, entry, entry); + { + let map: simple_map::SimpleMap = pack simple_map::SimpleMap(data); + { + let keys: vector = simple_map::keys(Borrow(Immutable)(map)); + if Eq>(keys, Vector(1, 1, 1)) { + Tuple() + } else { + Abort(33) + }; + Tuple() + } + } + } + } + } +} // end 0x42::simple_map + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::simple_map { + use 0x1::vector; // resolved as: 0x1::vector + struct Element { + key: Key, + value: Value, + } + struct SimpleMap { + data: vector>, + } + public fun for_each_ref(v: &vector<#0>,f: |�|) { + { + let i: u64 = 0; + { + let len: u64 = vector::length(v); + loop { + if Lt(i, len) { + (f)(vector::borrow(v, i)); + i: u64 = Add(i, 1) + } else { + break + } + } + } + } + } + public fun keys(map: &simple_map::SimpleMap<#0, #1>): vector<#0> { + simple_map::map_ref, Key>(Borrow(Immutable)(select simple_map::SimpleMap.data<&simple_map::SimpleMap>(map)), |e: &simple_map::Element| { + let e: &simple_map::Element = e; + select simple_map::Element.key<&simple_map::Element>(e) + }) + } + public fun map_ref(v: &vector<#0>,f: |�|#1): vector<#1> { + { + let result: vector = Vector(); + simple_map::for_each_ref(v, |elem: &Element| vector::push_back(Borrow(Mutable)(result), (f)(elem))); + result + } + } + public fun run() { + { + let entry: simple_map::Element = pack simple_map::Element(1, 2); + { + let data: vector> = Vector>(entry, entry, entry); + { + let map: simple_map::SimpleMap = pack simple_map::SimpleMap(data); + { + let keys: vector = simple_map::keys(Borrow(Immutable)(map)); + if Eq>(keys, Vector(1, 1, 1)) { + Tuple() + } else { + Abort(33) + }; + Tuple() + } + } + } + } + } +} // end 0x42::simple_map + + +// -- Model dump after env processor unused struct params check: +module 0x42::simple_map { + use 0x1::vector; // resolved as: 0x1::vector + struct Element { + key: Key, + value: Value, + } + struct SimpleMap { + data: vector>, + } + public fun for_each_ref(v: &vector<#0>,f: |�|) { + { + let i: u64 = 0; + { + let len: u64 = vector::length(v); + loop { + if Lt(i, len) { + (f)(vector::borrow(v, i)); + i: u64 = Add(i, 1) + } else { + break + } + } + } + } + } + public fun keys(map: &simple_map::SimpleMap<#0, #1>): vector<#0> { + simple_map::map_ref, Key>(Borrow(Immutable)(select simple_map::SimpleMap.data<&simple_map::SimpleMap>(map)), |e: &simple_map::Element| { + let e: &simple_map::Element = e; + select simple_map::Element.key<&simple_map::Element>(e) + }) + } + public fun map_ref(v: &vector<#0>,f: |�|#1): vector<#1> { + { + let result: vector = Vector(); + simple_map::for_each_ref(v, |elem: &Element| vector::push_back(Borrow(Mutable)(result), (f)(elem))); + result + } + } + public fun run() { + { + let entry: simple_map::Element = pack simple_map::Element(1, 2); + { + let data: vector> = Vector>(entry, entry, entry); + { + let map: simple_map::SimpleMap = pack simple_map::SimpleMap(data); + { + let keys: vector = simple_map::keys(Borrow(Immutable)(map)); + if Eq>(keys, Vector(1, 1, 1)) { + Tuple() + } else { + Abort(33) + }; + Tuple() + } + } + } + } + } +} // end 0x42::simple_map + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::simple_map { + use 0x1::vector; // resolved as: 0x1::vector + struct Element { + key: Key, + value: Value, + } + struct SimpleMap { + data: vector>, + } + public fun for_each_ref(v: &vector<#0>,f: |�|) { + { + let i: u64 = 0; + { + let len: u64 = vector::length(v); + loop { + if Lt(i, len) { + (f)(vector::borrow(v, i)); + i: u64 = Add(i, 1) + } else { + break + } + } + } + } + } + public fun keys(map: &simple_map::SimpleMap<#0, #1>): vector<#0> { + simple_map::map_ref, Key>(Borrow(Immutable)(select simple_map::SimpleMap.data<&simple_map::SimpleMap>(map)), |e: &simple_map::Element| { + let e: &simple_map::Element = e; + select simple_map::Element.key<&simple_map::Element>(e) + }) + } + public fun map_ref(v: &vector<#0>,f: |�|#1): vector<#1> { + { + let result: vector = Vector(); + simple_map::for_each_ref(v, |elem: &Element| vector::push_back(Borrow(Mutable)(result), (f)(elem))); + result + } + } + public fun run() { + { + let entry: simple_map::Element = pack simple_map::Element(1, 2); + { + let data: vector> = Vector>(entry, entry, entry); + { + let map: simple_map::SimpleMap = pack simple_map::SimpleMap(data); + { + let keys: vector = simple_map::keys(Borrow(Immutable)(map)); + if Eq>(keys, Vector(1, 1, 1)) { + Tuple() + } else { + Abort(33) + }; + Tuple() + } + } + } + } + } +} // end 0x42::simple_map + + +// -- Model dump after env processor inlining: +module 0x42::simple_map { + use 0x1::vector; // resolved as: 0x1::vector + struct Element { + key: Key, + value: Value, + } + struct SimpleMap { + data: vector>, + } + public fun for_each_ref(v: &vector<#0>,f: |�|) { + { + let i: u64 = 0; + { + let len: u64 = vector::length(v); + loop { + if Lt(i, len) { + (f)(vector::borrow(v, i)); + i: u64 = Add(i, 1) + } else { + break + } + } + } + } + } + public fun keys(map: &simple_map::SimpleMap<#0, #1>): vector<#0> { + simple_map::map_ref, Key>(Borrow(Immutable)(select simple_map::SimpleMap.data<&simple_map::SimpleMap>(map)), |e: &simple_map::Element| { + let e: &simple_map::Element = e; + select simple_map::Element.key<&simple_map::Element>(e) + }) + } + public fun map_ref(v: &vector<#0>,f: |�|#1): vector<#1> { + { + let result: vector = Vector(); + simple_map::for_each_ref(v, |elem: &Element| vector::push_back(Borrow(Mutable)(result), (f)(elem))); + result + } + } + public fun run() { + { + let entry: simple_map::Element = pack simple_map::Element(1, 2); + { + let data: vector> = Vector>(entry, entry, entry); + { + let map: simple_map::SimpleMap = pack simple_map::SimpleMap(data); + { + let keys: vector = simple_map::keys(Borrow(Immutable)(map)); + if Eq>(keys, Vector(1, 1, 1)) { + Tuple() + } else { + Abort(33) + }; + Tuple() + } + } + } + } + } +} // end 0x42::simple_map + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::simple_map { + use 0x1::vector; // resolved as: 0x1::vector + struct Element { + key: Key, + value: Value, + } + struct SimpleMap { + data: vector>, + } + public fun for_each_ref(v: &vector<#0>,f: |�|) { + { + let i: u64 = 0; + { + let len: u64 = vector::length(v); + loop { + if Lt(i, len) { + (f)(vector::borrow(v, i)); + i: u64 = Add(i, 1) + } else { + break + } + } + } + } + } + public fun keys(map: &simple_map::SimpleMap<#0, #1>): vector<#0> { + simple_map::map_ref, Key>(Borrow(Immutable)(select simple_map::SimpleMap.data<&simple_map::SimpleMap>(map)), |e: &simple_map::Element| { + let e: &simple_map::Element = e; + select simple_map::Element.key<&simple_map::Element>(e) + }) + } + public fun map_ref(v: &vector<#0>,f: |�|#1): vector<#1> { + { + let result: vector = Vector(); + simple_map::for_each_ref(v, |elem: &Element| vector::push_back(Borrow(Mutable)(result), (f)(elem))); + result + } + } + public fun run() { + { + let entry: simple_map::Element = pack simple_map::Element(1, 2); + { + let data: vector> = Vector>(entry, entry, entry); + { + let map: simple_map::SimpleMap = pack simple_map::SimpleMap(data); + { + let keys: vector = simple_map::keys(Borrow(Immutable)(map)); + if Eq>(keys, Vector(1, 1, 1)) { + Tuple() + } else { + Abort(33) + }; + Tuple() + } + } + } + } + } +} // end 0x42::simple_map + + +// -- Model dump after env processor acquires check: +module 0x42::simple_map { + use 0x1::vector; // resolved as: 0x1::vector + struct Element { + key: Key, + value: Value, + } + struct SimpleMap { + data: vector>, + } + public fun for_each_ref(v: &vector<#0>,f: |�|) { + { + let i: u64 = 0; + { + let len: u64 = vector::length(v); + loop { + if Lt(i, len) { + (f)(vector::borrow(v, i)); + i: u64 = Add(i, 1) + } else { + break + } + } + } + } + } + public fun keys(map: &simple_map::SimpleMap<#0, #1>): vector<#0> { + simple_map::map_ref, Key>(Borrow(Immutable)(select simple_map::SimpleMap.data<&simple_map::SimpleMap>(map)), |e: &simple_map::Element| { + let e: &simple_map::Element = e; + select simple_map::Element.key<&simple_map::Element>(e) + }) + } + public fun map_ref(v: &vector<#0>,f: |�|#1): vector<#1> { + { + let result: vector = Vector(); + simple_map::for_each_ref(v, |elem: &Element| vector::push_back(Borrow(Mutable)(result), (f)(elem))); + result + } + } + public fun run() { + { + let entry: simple_map::Element = pack simple_map::Element(1, 2); + { + let data: vector> = Vector>(entry, entry, entry); + { + let map: simple_map::SimpleMap = pack simple_map::SimpleMap(data); + { + let keys: vector = simple_map::keys(Borrow(Immutable)(map)); + if Eq>(keys, Vector(1, 1, 1)) { + Tuple() + } else { + Abort(33) + }; + Tuple() + } + } + } + } + } +} // end 0x42::simple_map + + +// -- Model dump after env processor simplifier: +module 0x42::simple_map { + use 0x1::vector; // resolved as: 0x1::vector + struct Element { + key: Key, + value: Value, + } + struct SimpleMap { + data: vector>, + } + public fun for_each_ref(v: &vector<#0>,f: |�|) { + { + let i: u64 = 0; + { + let len: u64 = vector::length(v); + loop { + if Lt(i, len) { + (f)(vector::borrow(v, i)); + i: u64 = Add(i, 1) + } else { + break + } + } + } + } + } + public fun keys(map: &simple_map::SimpleMap<#0, #1>): vector<#0> { + simple_map::map_ref, Key>(Borrow(Immutable)(select simple_map::SimpleMap.data<&simple_map::SimpleMap>(map)), |e: &simple_map::Element| { + let e: &simple_map::Element = e; + select simple_map::Element.key<&simple_map::Element>(e) + }) + } + public fun map_ref(v: &vector<#0>,f: |�|#1): vector<#1> { + { + let result: vector = Vector(); + simple_map::for_each_ref(v, |elem: &Element| vector::push_back(Borrow(Mutable)(result), (f)(elem))); + result + } + } + public fun run() { + { + let entry: simple_map::Element = pack simple_map::Element(1, 2); + { + let data: vector> = Vector>(entry, entry, entry); + { + let map: simple_map::SimpleMap = pack simple_map::SimpleMap(data); + { + let keys: vector = simple_map::keys(Borrow(Immutable)(map)); + if Eq>(keys, [Number(1), Number(1), Number(1)]) { + Tuple() + } else { + Abort(33) + }; + Tuple() + } + } + } + } + } +} // end 0x42::simple_map + + + +Diagnostics: +error: captured variable `result` cannot be modified inside of a lambda + ┌─ tests/lambda/inline-parity/simple_map_keys.move:28:55 + │ +28 │ for_each_ref(v, |elem| vector::push_back(&mut result, f(elem))); + │ ^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/simple_map_keys.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/simple_map_keys.move new file mode 100644 index 00000000000000..8a9b5fcbc05241 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/simple_map_keys.move @@ -0,0 +1,50 @@ +//# 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| { + let e: &Element = e; + e.key + }) + } + + public fun map_ref( + v: &vector, + f: |&Element|NewElement + ): vector { + let result = vector[]; + for_each_ref(v, |elem| vector::push_back(&mut result, f(elem))); + result + } + + public 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/tests/lambda/inline-parity/spec_inlining.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/spec_inlining.exp new file mode 100644 index 00000000000000..23d44c6e86b4a1 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/spec_inlining.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `Test::apply` has a function parameter: + ┌─ tests/lambda/inline-parity/spec_inlining.move:2:9 + │ +2 │ fun apply(v: u64, predicate: |u64| bool): bool { + │ ^^^^^ --------- Parameter `predicate` has function-valued type `|u64|bool`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/spec_inlining.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/spec_inlining.lambda.exp new file mode 100644 index 00000000000000..82da96e292c71f --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/spec_inlining.lambda.exp @@ -0,0 +1,583 @@ +// -- Model dump before env processor pipeline: +module 0x42::Test { + private fun apply(v: u64,predicate: |u64|bool): bool { + spec { + assert Ge($t0, 0); + } + ; + (predicate)(v) + } + public fun test_apply(x: u64) { + { + let r1: bool = Test::apply(x, |v: u64| Ge(v, 0)); + spec { + assert r1; + } + ; + if r1 { + Tuple() + } else { + Abort(1) + }; + { + let r2: bool = Test::apply(x, |v: u64| Neq(v, 0)); + spec { + assert r2; + } + ; + if r2 { + Tuple() + } else { + Abort(2) + }; + Tuple() + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor unused checks: +module 0x42::Test { + private fun apply(v: u64,predicate: |u64|bool): bool { + spec { + assert Ge($t0, 0); + } + ; + (predicate)(v) + } + public fun test_apply(x: u64) { + { + let r1: bool = Test::apply(x, |v: u64| Ge(v, 0)); + spec { + assert r1; + } + ; + if r1 { + Tuple() + } else { + Abort(1) + }; + { + let r2: bool = Test::apply(x, |v: u64| Neq(v, 0)); + spec { + assert r2; + } + ; + if r2 { + Tuple() + } else { + Abort(2) + }; + Tuple() + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor type parameter check: +module 0x42::Test { + private fun apply(v: u64,predicate: |u64|bool): bool { + spec { + assert Ge($t0, 0); + } + ; + (predicate)(v) + } + public fun test_apply(x: u64) { + { + let r1: bool = Test::apply(x, |v: u64| Ge(v, 0)); + spec { + assert r1; + } + ; + if r1 { + Tuple() + } else { + Abort(1) + }; + { + let r2: bool = Test::apply(x, |v: u64| Neq(v, 0)); + spec { + assert r2; + } + ; + if r2 { + Tuple() + } else { + Abort(2) + }; + Tuple() + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::Test { + private fun apply(v: u64,predicate: |u64|bool): bool { + spec { + assert Ge($t0, 0); + } + ; + (predicate)(v) + } + public fun test_apply(x: u64) { + { + let r1: bool = Test::apply(x, |v: u64| Ge(v, 0)); + spec { + assert r1; + } + ; + if r1 { + Tuple() + } else { + Abort(1) + }; + { + let r2: bool = Test::apply(x, |v: u64| Neq(v, 0)); + spec { + assert r2; + } + ; + if r2 { + Tuple() + } else { + Abort(2) + }; + Tuple() + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::Test { + private fun apply(v: u64,predicate: |u64|bool): bool { + spec { + assert Ge($t0, 0); + } + ; + (predicate)(v) + } + public fun test_apply(x: u64) { + { + let r1: bool = Test::apply(x, |v: u64| Ge(v, 0)); + spec { + assert r1; + } + ; + if r1 { + Tuple() + } else { + Abort(1) + }; + { + let r2: bool = Test::apply(x, |v: u64| Neq(v, 0)); + spec { + assert r2; + } + ; + if r2 { + Tuple() + } else { + Abort(2) + }; + Tuple() + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor unused struct params check: +module 0x42::Test { + private fun apply(v: u64,predicate: |u64|bool): bool { + spec { + assert Ge($t0, 0); + } + ; + (predicate)(v) + } + public fun test_apply(x: u64) { + { + let r1: bool = Test::apply(x, |v: u64| Ge(v, 0)); + spec { + assert r1; + } + ; + if r1 { + Tuple() + } else { + Abort(1) + }; + { + let r2: bool = Test::apply(x, |v: u64| Neq(v, 0)); + spec { + assert r2; + } + ; + if r2 { + Tuple() + } else { + Abort(2) + }; + Tuple() + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::Test { + private fun apply(v: u64,predicate: |u64|bool): bool { + spec { + assert Ge($t0, 0); + } + ; + (predicate)(v) + } + public fun test_apply(x: u64) { + { + let r1: bool = Test::apply(x, |v: u64| Ge(v, 0)); + spec { + assert r1; + } + ; + if r1 { + Tuple() + } else { + Abort(1) + }; + { + let r2: bool = Test::apply(x, |v: u64| Neq(v, 0)); + spec { + assert r2; + } + ; + if r2 { + Tuple() + } else { + Abort(2) + }; + Tuple() + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor inlining: +module 0x42::Test { + private fun apply(v: u64,predicate: |u64|bool): bool { + spec { + assert Ge($t0, 0); + } + ; + (predicate)(v) + } + public fun test_apply(x: u64) { + { + let r1: bool = Test::apply(x, |v: u64| Ge(v, 0)); + spec { + assert r1; + } + ; + if r1 { + Tuple() + } else { + Abort(1) + }; + { + let r2: bool = Test::apply(x, |v: u64| Neq(v, 0)); + spec { + assert r2; + } + ; + if r2 { + Tuple() + } else { + Abort(2) + }; + Tuple() + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::Test { + private fun apply(v: u64,predicate: |u64|bool): bool { + spec { + assert Ge($t0, 0); + } + ; + (predicate)(v) + } + public fun test_apply(x: u64) { + { + let r1: bool = Test::apply(x, |v: u64| Ge(v, 0)); + spec { + assert r1; + } + ; + if r1 { + Tuple() + } else { + Abort(1) + }; + { + let r2: bool = Test::apply(x, |v: u64| Neq(v, 0)); + spec { + assert r2; + } + ; + if r2 { + Tuple() + } else { + Abort(2) + }; + Tuple() + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor acquires check: +module 0x42::Test { + private fun apply(v: u64,predicate: |u64|bool): bool { + spec { + assert Ge($t0, 0); + } + ; + (predicate)(v) + } + public fun test_apply(x: u64) { + { + let r1: bool = Test::apply(x, |v: u64| Ge(v, 0)); + spec { + assert r1; + } + ; + if r1 { + Tuple() + } else { + Abort(1) + }; + { + let r2: bool = Test::apply(x, |v: u64| Neq(v, 0)); + spec { + assert r2; + } + ; + if r2 { + Tuple() + } else { + Abort(2) + }; + Tuple() + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor simplifier: +module 0x42::Test { + private fun apply(v: u64,predicate: |u64|bool): bool { + spec { + assert Ge($t0, 0); + } + ; + (predicate)(v) + } + public fun test_apply(x: u64) { + { + let r1: bool = Test::apply(x, |v: u64| Ge(v, 0)); + spec { + assert r1; + } + ; + if r1 { + Tuple() + } else { + Abort(1) + }; + { + let r2: bool = Test::apply(x, |v: u64| Neq(v, 0)); + spec { + assert r2; + } + ; + if r2 { + Tuple() + } else { + Abort(2) + }; + Tuple() + } + } + } +} // end 0x42::Test + + +// -- Model dump after env processor lambda-lifting: +module 0x42::Test { + private fun apply(v: u64,predicate: |u64|bool): bool { + spec { + assert Ge($t0, 0); + } + ; + (predicate)(v) + } + public fun test_apply(x: u64) { + { + let r1: bool = Test::apply(x, closure Test::test_apply$lambda$1()); + spec { + assert r1; + } + ; + if r1 { + Tuple() + } else { + Abort(1) + }; + { + let r2: bool = Test::apply(x, closure Test::test_apply$lambda$2()); + spec { + assert r2; + } + ; + if r2 { + Tuple() + } else { + Abort(2) + }; + Tuple() + } + } + } + private fun test_apply$lambda$1(v: u64): bool { + Ge(v, 0) + } + private fun test_apply$lambda$2(v: u64): bool { + Neq(v, 0) + } +} // end 0x42::Test + + +// -- Model dump after env processor specification checker: +module 0x42::Test { + private fun apply(v: u64,predicate: |u64|bool): bool { + spec { + assert Ge($t0, 0); + } + ; + (predicate)(v) + } + public fun test_apply(x: u64) { + { + let r1: bool = Test::apply(x, closure Test::test_apply$lambda$1()); + spec { + assert r1; + } + ; + if r1 { + Tuple() + } else { + Abort(1) + }; + { + let r2: bool = Test::apply(x, closure Test::test_apply$lambda$2()); + spec { + assert r2; + } + ; + if r2 { + Tuple() + } else { + Abort(2) + }; + Tuple() + } + } + } + private fun test_apply$lambda$1(v: u64): bool { + Ge(v, 0) + } + private fun test_apply$lambda$2(v: u64): bool { + Neq(v, 0) + } +} // end 0x42::Test + + +// -- Model dump after env processor specification rewriter: +module 0x42::Test { + private fun apply(v: u64,predicate: |u64|bool): bool { + spec { + assert Ge($t0, 0); + } + ; + (predicate)(v) + } + public fun test_apply(x: u64) { + { + let r1: bool = Test::apply(x, closure Test::test_apply$lambda$1()); + spec { + assert r1; + } + ; + if r1 { + Tuple() + } else { + Abort(1) + }; + { + let r2: bool = Test::apply(x, closure Test::test_apply$lambda$2()); + spec { + assert r2; + } + ; + if r2 { + Tuple() + } else { + Abort(2) + }; + Tuple() + } + } + } + private fun test_apply$lambda$1(v: u64): bool { + Ge(v, 0) + } + private fun test_apply$lambda$2(v: u64): bool { + Neq(v, 0) + } +} // end 0x42::Test + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/spec_inlining.move:6:9 + │ +6 │ predicate(v) + │ ^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/spec_inlining.move:10:27 + │ +10 │ let r1 = apply(x, |v| v >= 0); + │ ^^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/spec_inlining.move:16:27 + │ +16 │ let r2 = apply(x, |v| v != 0); + │ ^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/spec_inlining.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/spec_inlining.move new file mode 100644 index 00000000000000..507d70a67d5cfd --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/spec_inlining.move @@ -0,0 +1,22 @@ +module 0x42::Test { + 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| v >= 0); + spec { + assert r1; + }; + assert!(r1, 1); + + let r2 = apply(x, |v| v != 0); + spec { + assert r2; + }; + assert!(r2, 2); + } +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args.exp new file mode 100644 index 00000000000000..70f2a996bbc3c9 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `M::t2` has a function parameter: + ┌─ tests/lambda/inline-parity/subtype_args.move:23:9 + │ +23 │ fun t2(f: |&u64, &mut u64|) { + │ ^^ - Parameter `f` has function-valued type `|(&u64, &mut u64)|`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args.lambda.exp new file mode 100644 index 00000000000000..04eb8f6016271b --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args.lambda.exp @@ -0,0 +1,545 @@ +// -- Model dump before env processor pipeline: +module 0x8675309::M { + struct S { + dummy_field: bool, + } + private fun imm(_x: �) { + Tuple() + } + private fun imm_imm(_x: �,_y: �) { + Tuple() + } + private fun imm_mut(_x: �,_y: &mut #0) { + Tuple() + } + private fun mut_imm(_x: &mut #0,_y: �) { + Tuple() + } + private fun t0() { + M::imm(Freeze(false)(Borrow(Mutable)(0))); + M::imm(Borrow(Immutable)(0)); + M::imm(Freeze(false)(Borrow(Mutable)(pack M::S(false)))); + M::imm(Borrow(Immutable)(pack M::S(false))); + Tuple() + } + private fun t1() { + M::imm_mut(Freeze(false)(Borrow(Mutable)(0)), Borrow(Mutable)(0)); + M::mut_imm(Borrow(Mutable)(0), Freeze(false)(Borrow(Mutable)(0))); + M::imm_imm(Freeze(false)(Borrow(Mutable)(0)), Freeze(false)(Borrow(Mutable)(0))); + Tuple() + } + private fun t2(f: |(&u64, &mut u64)|) { + (f)(Borrow(Mutable)(0), Borrow(Mutable)(0)); + (f)(Borrow(Immutable)(0), Borrow(Mutable)(0)); + Tuple() + } +} // end 0x8675309::M + + +// -- Model dump after env processor unused checks: +module 0x8675309::M { + struct S { + dummy_field: bool, + } + private fun imm(_x: �) { + Tuple() + } + private fun imm_imm(_x: �,_y: �) { + Tuple() + } + private fun imm_mut(_x: �,_y: &mut #0) { + Tuple() + } + private fun mut_imm(_x: &mut #0,_y: �) { + Tuple() + } + private fun t0() { + M::imm(Freeze(false)(Borrow(Mutable)(0))); + M::imm(Borrow(Immutable)(0)); + M::imm(Freeze(false)(Borrow(Mutable)(pack M::S(false)))); + M::imm(Borrow(Immutable)(pack M::S(false))); + Tuple() + } + private fun t1() { + M::imm_mut(Freeze(false)(Borrow(Mutable)(0)), Borrow(Mutable)(0)); + M::mut_imm(Borrow(Mutable)(0), Freeze(false)(Borrow(Mutable)(0))); + M::imm_imm(Freeze(false)(Borrow(Mutable)(0)), Freeze(false)(Borrow(Mutable)(0))); + Tuple() + } + private fun t2(f: |(&u64, &mut u64)|) { + (f)(Borrow(Mutable)(0), Borrow(Mutable)(0)); + (f)(Borrow(Immutable)(0), Borrow(Mutable)(0)); + Tuple() + } +} // end 0x8675309::M + + +// -- Model dump after env processor type parameter check: +module 0x8675309::M { + struct S { + dummy_field: bool, + } + private fun imm(_x: �) { + Tuple() + } + private fun imm_imm(_x: �,_y: �) { + Tuple() + } + private fun imm_mut(_x: �,_y: &mut #0) { + Tuple() + } + private fun mut_imm(_x: &mut #0,_y: �) { + Tuple() + } + private fun t0() { + M::imm(Freeze(false)(Borrow(Mutable)(0))); + M::imm(Borrow(Immutable)(0)); + M::imm(Freeze(false)(Borrow(Mutable)(pack M::S(false)))); + M::imm(Borrow(Immutable)(pack M::S(false))); + Tuple() + } + private fun t1() { + M::imm_mut(Freeze(false)(Borrow(Mutable)(0)), Borrow(Mutable)(0)); + M::mut_imm(Borrow(Mutable)(0), Freeze(false)(Borrow(Mutable)(0))); + M::imm_imm(Freeze(false)(Borrow(Mutable)(0)), Freeze(false)(Borrow(Mutable)(0))); + Tuple() + } + private fun t2(f: |(&u64, &mut u64)|) { + (f)(Borrow(Mutable)(0), Borrow(Mutable)(0)); + (f)(Borrow(Immutable)(0), Borrow(Mutable)(0)); + Tuple() + } +} // end 0x8675309::M + + +// -- Model dump after env processor check recursive struct definition: +module 0x8675309::M { + struct S { + dummy_field: bool, + } + private fun imm(_x: �) { + Tuple() + } + private fun imm_imm(_x: �,_y: �) { + Tuple() + } + private fun imm_mut(_x: �,_y: &mut #0) { + Tuple() + } + private fun mut_imm(_x: &mut #0,_y: �) { + Tuple() + } + private fun t0() { + M::imm(Freeze(false)(Borrow(Mutable)(0))); + M::imm(Borrow(Immutable)(0)); + M::imm(Freeze(false)(Borrow(Mutable)(pack M::S(false)))); + M::imm(Borrow(Immutable)(pack M::S(false))); + Tuple() + } + private fun t1() { + M::imm_mut(Freeze(false)(Borrow(Mutable)(0)), Borrow(Mutable)(0)); + M::mut_imm(Borrow(Mutable)(0), Freeze(false)(Borrow(Mutable)(0))); + M::imm_imm(Freeze(false)(Borrow(Mutable)(0)), Freeze(false)(Borrow(Mutable)(0))); + Tuple() + } + private fun t2(f: |(&u64, &mut u64)|) { + (f)(Borrow(Mutable)(0), Borrow(Mutable)(0)); + (f)(Borrow(Immutable)(0), Borrow(Mutable)(0)); + Tuple() + } +} // end 0x8675309::M + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x8675309::M { + struct S { + dummy_field: bool, + } + private fun imm(_x: �) { + Tuple() + } + private fun imm_imm(_x: �,_y: �) { + Tuple() + } + private fun imm_mut(_x: �,_y: &mut #0) { + Tuple() + } + private fun mut_imm(_x: &mut #0,_y: �) { + Tuple() + } + private fun t0() { + M::imm(Freeze(false)(Borrow(Mutable)(0))); + M::imm(Borrow(Immutable)(0)); + M::imm(Freeze(false)(Borrow(Mutable)(pack M::S(false)))); + M::imm(Borrow(Immutable)(pack M::S(false))); + Tuple() + } + private fun t1() { + M::imm_mut(Freeze(false)(Borrow(Mutable)(0)), Borrow(Mutable)(0)); + M::mut_imm(Borrow(Mutable)(0), Freeze(false)(Borrow(Mutable)(0))); + M::imm_imm(Freeze(false)(Borrow(Mutable)(0)), Freeze(false)(Borrow(Mutable)(0))); + Tuple() + } + private fun t2(f: |(&u64, &mut u64)|) { + (f)(Borrow(Mutable)(0), Borrow(Mutable)(0)); + (f)(Borrow(Immutable)(0), Borrow(Mutable)(0)); + Tuple() + } +} // end 0x8675309::M + + +// -- Model dump after env processor unused struct params check: +module 0x8675309::M { + struct S { + dummy_field: bool, + } + private fun imm(_x: �) { + Tuple() + } + private fun imm_imm(_x: �,_y: �) { + Tuple() + } + private fun imm_mut(_x: �,_y: &mut #0) { + Tuple() + } + private fun mut_imm(_x: &mut #0,_y: �) { + Tuple() + } + private fun t0() { + M::imm(Freeze(false)(Borrow(Mutable)(0))); + M::imm(Borrow(Immutable)(0)); + M::imm(Freeze(false)(Borrow(Mutable)(pack M::S(false)))); + M::imm(Borrow(Immutable)(pack M::S(false))); + Tuple() + } + private fun t1() { + M::imm_mut(Freeze(false)(Borrow(Mutable)(0)), Borrow(Mutable)(0)); + M::mut_imm(Borrow(Mutable)(0), Freeze(false)(Borrow(Mutable)(0))); + M::imm_imm(Freeze(false)(Borrow(Mutable)(0)), Freeze(false)(Borrow(Mutable)(0))); + Tuple() + } + private fun t2(f: |(&u64, &mut u64)|) { + (f)(Borrow(Mutable)(0), Borrow(Mutable)(0)); + (f)(Borrow(Immutable)(0), Borrow(Mutable)(0)); + Tuple() + } +} // end 0x8675309::M + + +// -- Model dump after env processor access and use check before inlining: +module 0x8675309::M { + struct S { + dummy_field: bool, + } + private fun imm(_x: �) { + Tuple() + } + private fun imm_imm(_x: �,_y: �) { + Tuple() + } + private fun imm_mut(_x: �,_y: &mut #0) { + Tuple() + } + private fun mut_imm(_x: &mut #0,_y: �) { + Tuple() + } + private fun t0() { + M::imm(Freeze(false)(Borrow(Mutable)(0))); + M::imm(Borrow(Immutable)(0)); + M::imm(Freeze(false)(Borrow(Mutable)(pack M::S(false)))); + M::imm(Borrow(Immutable)(pack M::S(false))); + Tuple() + } + private fun t1() { + M::imm_mut(Freeze(false)(Borrow(Mutable)(0)), Borrow(Mutable)(0)); + M::mut_imm(Borrow(Mutable)(0), Freeze(false)(Borrow(Mutable)(0))); + M::imm_imm(Freeze(false)(Borrow(Mutable)(0)), Freeze(false)(Borrow(Mutable)(0))); + Tuple() + } + private fun t2(f: |(&u64, &mut u64)|) { + (f)(Borrow(Mutable)(0), Borrow(Mutable)(0)); + (f)(Borrow(Immutable)(0), Borrow(Mutable)(0)); + Tuple() + } +} // end 0x8675309::M + + +// -- Model dump after env processor inlining: +module 0x8675309::M { + struct S { + dummy_field: bool, + } + private fun imm(_x: �) { + Tuple() + } + private fun imm_imm(_x: �,_y: �) { + Tuple() + } + private fun imm_mut(_x: �,_y: &mut #0) { + Tuple() + } + private fun mut_imm(_x: &mut #0,_y: �) { + Tuple() + } + private fun t0() { + M::imm(Freeze(false)(Borrow(Mutable)(0))); + M::imm(Borrow(Immutable)(0)); + M::imm(Freeze(false)(Borrow(Mutable)(pack M::S(false)))); + M::imm(Borrow(Immutable)(pack M::S(false))); + Tuple() + } + private fun t1() { + M::imm_mut(Freeze(false)(Borrow(Mutable)(0)), Borrow(Mutable)(0)); + M::mut_imm(Borrow(Mutable)(0), Freeze(false)(Borrow(Mutable)(0))); + M::imm_imm(Freeze(false)(Borrow(Mutable)(0)), Freeze(false)(Borrow(Mutable)(0))); + Tuple() + } + private fun t2(f: |(&u64, &mut u64)|) { + (f)(Borrow(Mutable)(0), Borrow(Mutable)(0)); + (f)(Borrow(Immutable)(0), Borrow(Mutable)(0)); + Tuple() + } +} // end 0x8675309::M + + +// -- Model dump after env processor access and use check after inlining: +module 0x8675309::M { + struct S { + dummy_field: bool, + } + private fun imm(_x: �) { + Tuple() + } + private fun imm_imm(_x: �,_y: �) { + Tuple() + } + private fun imm_mut(_x: �,_y: &mut #0) { + Tuple() + } + private fun mut_imm(_x: &mut #0,_y: �) { + Tuple() + } + private fun t0() { + M::imm(Freeze(false)(Borrow(Mutable)(0))); + M::imm(Borrow(Immutable)(0)); + M::imm(Freeze(false)(Borrow(Mutable)(pack M::S(false)))); + M::imm(Borrow(Immutable)(pack M::S(false))); + Tuple() + } + private fun t1() { + M::imm_mut(Freeze(false)(Borrow(Mutable)(0)), Borrow(Mutable)(0)); + M::mut_imm(Borrow(Mutable)(0), Freeze(false)(Borrow(Mutable)(0))); + M::imm_imm(Freeze(false)(Borrow(Mutable)(0)), Freeze(false)(Borrow(Mutable)(0))); + Tuple() + } + private fun t2(f: |(&u64, &mut u64)|) { + (f)(Borrow(Mutable)(0), Borrow(Mutable)(0)); + (f)(Borrow(Immutable)(0), Borrow(Mutable)(0)); + Tuple() + } +} // end 0x8675309::M + + +// -- Model dump after env processor acquires check: +module 0x8675309::M { + struct S { + dummy_field: bool, + } + private fun imm(_x: �) { + Tuple() + } + private fun imm_imm(_x: �,_y: �) { + Tuple() + } + private fun imm_mut(_x: �,_y: &mut #0) { + Tuple() + } + private fun mut_imm(_x: &mut #0,_y: �) { + Tuple() + } + private fun t0() { + M::imm(Freeze(false)(Borrow(Mutable)(0))); + M::imm(Borrow(Immutable)(0)); + M::imm(Freeze(false)(Borrow(Mutable)(pack M::S(false)))); + M::imm(Borrow(Immutable)(pack M::S(false))); + Tuple() + } + private fun t1() { + M::imm_mut(Freeze(false)(Borrow(Mutable)(0)), Borrow(Mutable)(0)); + M::mut_imm(Borrow(Mutable)(0), Freeze(false)(Borrow(Mutable)(0))); + M::imm_imm(Freeze(false)(Borrow(Mutable)(0)), Freeze(false)(Borrow(Mutable)(0))); + Tuple() + } + private fun t2(f: |(&u64, &mut u64)|) { + (f)(Borrow(Mutable)(0), Borrow(Mutable)(0)); + (f)(Borrow(Immutable)(0), Borrow(Mutable)(0)); + Tuple() + } +} // end 0x8675309::M + + +// -- Model dump after env processor simplifier: +module 0x8675309::M { + struct S { + dummy_field: bool, + } + private fun imm(_x: �) { + Tuple() + } + private fun imm_imm(_x: �,_y: �) { + Tuple() + } + private fun imm_mut(_x: �,_y: &mut #0) { + Tuple() + } + private fun mut_imm(_x: &mut #0,_y: �) { + Tuple() + } + private fun t0() { + M::imm(Freeze(false)(Borrow(Mutable)(0))); + M::imm(Borrow(Immutable)(0)); + M::imm(Freeze(false)(Borrow(Mutable)(pack M::S(false)))); + M::imm(Borrow(Immutable)(pack M::S(false))); + Tuple() + } + private fun t1() { + M::imm_mut(Freeze(false)(Borrow(Mutable)(0)), Borrow(Mutable)(0)); + M::mut_imm(Borrow(Mutable)(0), Freeze(false)(Borrow(Mutable)(0))); + M::imm_imm(Freeze(false)(Borrow(Mutable)(0)), Freeze(false)(Borrow(Mutable)(0))); + Tuple() + } + private fun t2(f: |(&u64, &mut u64)|) { + (f)(Borrow(Mutable)(0), Borrow(Mutable)(0)); + (f)(Borrow(Immutable)(0), Borrow(Mutable)(0)); + Tuple() + } +} // end 0x8675309::M + + +// -- Model dump after env processor lambda-lifting: +module 0x8675309::M { + struct S { + dummy_field: bool, + } + private fun imm(_x: �) { + Tuple() + } + private fun imm_imm(_x: �,_y: �) { + Tuple() + } + private fun imm_mut(_x: �,_y: &mut #0) { + Tuple() + } + private fun mut_imm(_x: &mut #0,_y: �) { + Tuple() + } + private fun t0() { + M::imm(Freeze(false)(Borrow(Mutable)(0))); + M::imm(Borrow(Immutable)(0)); + M::imm(Freeze(false)(Borrow(Mutable)(pack M::S(false)))); + M::imm(Borrow(Immutable)(pack M::S(false))); + Tuple() + } + private fun t1() { + M::imm_mut(Freeze(false)(Borrow(Mutable)(0)), Borrow(Mutable)(0)); + M::mut_imm(Borrow(Mutable)(0), Freeze(false)(Borrow(Mutable)(0))); + M::imm_imm(Freeze(false)(Borrow(Mutable)(0)), Freeze(false)(Borrow(Mutable)(0))); + Tuple() + } + private fun t2(f: |(&u64, &mut u64)|) { + (f)(Borrow(Mutable)(0), Borrow(Mutable)(0)); + (f)(Borrow(Immutable)(0), Borrow(Mutable)(0)); + Tuple() + } +} // end 0x8675309::M + + +// -- Model dump after env processor specification checker: +module 0x8675309::M { + struct S { + dummy_field: bool, + } + private fun imm(_x: �) { + Tuple() + } + private fun imm_imm(_x: �,_y: �) { + Tuple() + } + private fun imm_mut(_x: �,_y: &mut #0) { + Tuple() + } + private fun mut_imm(_x: &mut #0,_y: �) { + Tuple() + } + private fun t0() { + M::imm(Freeze(false)(Borrow(Mutable)(0))); + M::imm(Borrow(Immutable)(0)); + M::imm(Freeze(false)(Borrow(Mutable)(pack M::S(false)))); + M::imm(Borrow(Immutable)(pack M::S(false))); + Tuple() + } + private fun t1() { + M::imm_mut(Freeze(false)(Borrow(Mutable)(0)), Borrow(Mutable)(0)); + M::mut_imm(Borrow(Mutable)(0), Freeze(false)(Borrow(Mutable)(0))); + M::imm_imm(Freeze(false)(Borrow(Mutable)(0)), Freeze(false)(Borrow(Mutable)(0))); + Tuple() + } + private fun t2(f: |(&u64, &mut u64)|) { + (f)(Borrow(Mutable)(0), Borrow(Mutable)(0)); + (f)(Borrow(Immutable)(0), Borrow(Mutable)(0)); + Tuple() + } +} // end 0x8675309::M + + +// -- Model dump after env processor specification rewriter: +module 0x8675309::M { + struct S { + dummy_field: bool, + } + private fun imm(_x: �) { + Tuple() + } + private fun imm_imm(_x: �,_y: �) { + Tuple() + } + private fun imm_mut(_x: �,_y: &mut #0) { + Tuple() + } + private fun mut_imm(_x: &mut #0,_y: �) { + Tuple() + } + private fun t0() { + M::imm(Freeze(false)(Borrow(Mutable)(0))); + M::imm(Borrow(Immutable)(0)); + M::imm(Freeze(false)(Borrow(Mutable)(pack M::S(false)))); + M::imm(Borrow(Immutable)(pack M::S(false))); + Tuple() + } + private fun t1() { + M::imm_mut(Freeze(false)(Borrow(Mutable)(0)), Borrow(Mutable)(0)); + M::mut_imm(Borrow(Mutable)(0), Freeze(false)(Borrow(Mutable)(0))); + M::imm_imm(Freeze(false)(Borrow(Mutable)(0)), Freeze(false)(Borrow(Mutable)(0))); + Tuple() + } + private fun t2(f: |(&u64, &mut u64)|) { + (f)(Borrow(Mutable)(0), Borrow(Mutable)(0)); + (f)(Borrow(Immutable)(0), Borrow(Mutable)(0)); + Tuple() + } +} // end 0x8675309::M + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/subtype_args.move:24:9 + │ +24 │ f(&mut 0, &mut 0); + │ ^ + +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/subtype_args.move:25:9 + │ +25 │ f(&0, &mut 0); + │ ^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args.move new file mode 100644 index 00000000000000..b4622be55eace2 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args.move @@ -0,0 +1,28 @@ +module 0x8675309::M { + struct S has drop {} + + fun imm(_x: &T) {} + fun imm_mut(_x: &T, _y: &mut T) {} + fun mut_imm(_x: &mut T, _y: &T) {} + fun imm_imm(_x: &T, _y: &T) {} + + fun t0() { + imm(&mut 0); + imm(&0); + + imm(&mut S{}); + imm(&S{}); + } + + fun t1() { + imm_mut(&mut 0, &mut 0); + mut_imm(&mut 0, &mut 0); + imm_imm(&mut 0, &mut 0); + } + + fun t2(f: |&u64, &mut u64|) { + f(&mut 0, &mut 0); + f(&0, &mut 0); + } + +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args_invalid.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args_invalid.exp new file mode 100644 index 00000000000000..91693f9780ee57 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args_invalid.exp @@ -0,0 +1,37 @@ + +Diagnostics: +error: the function takes `&mut` but `&` was provided + ┌─ tests/lambda/inline-parity/subtype_args_invalid.move:10:18 + │ +10 │ mut(&0); + │ ^^ + +error: cannot pass `&S` to a function which expects argument of type `&mut u64` + ┌─ tests/lambda/inline-parity/subtype_args_invalid.move:11:18 + │ +11 │ mut(&S{}); + │ ^^^^ + +error: the function takes `&mut` but `&` was provided + ┌─ tests/lambda/inline-parity/subtype_args_invalid.move:15:26 + │ +15 │ imm_mut(&0, &0); + │ ^^ + +error: the function takes `&mut` but `&` was provided + ┌─ tests/lambda/inline-parity/subtype_args_invalid.move:16:22 + │ +16 │ mut_imm(&0, &0); + │ ^^ + +error: the function takes `&mut` but `&` was provided + ┌─ tests/lambda/inline-parity/subtype_args_invalid.move:17:22 + │ +17 │ mut_mut(&0, &0); + │ ^^ + +error: expected `&mut` but `&` was provided + ┌─ tests/lambda/inline-parity/subtype_args_invalid.move:21:9 + │ +21 │ f(&0, &0); // not okay + │ ^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args_invalid.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args_invalid.lambda.exp new file mode 100644 index 00000000000000..91693f9780ee57 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args_invalid.lambda.exp @@ -0,0 +1,37 @@ + +Diagnostics: +error: the function takes `&mut` but `&` was provided + ┌─ tests/lambda/inline-parity/subtype_args_invalid.move:10:18 + │ +10 │ mut(&0); + │ ^^ + +error: cannot pass `&S` to a function which expects argument of type `&mut u64` + ┌─ tests/lambda/inline-parity/subtype_args_invalid.move:11:18 + │ +11 │ mut(&S{}); + │ ^^^^ + +error: the function takes `&mut` but `&` was provided + ┌─ tests/lambda/inline-parity/subtype_args_invalid.move:15:26 + │ +15 │ imm_mut(&0, &0); + │ ^^ + +error: the function takes `&mut` but `&` was provided + ┌─ tests/lambda/inline-parity/subtype_args_invalid.move:16:22 + │ +16 │ mut_imm(&0, &0); + │ ^^ + +error: the function takes `&mut` but `&` was provided + ┌─ tests/lambda/inline-parity/subtype_args_invalid.move:17:22 + │ +17 │ mut_mut(&0, &0); + │ ^^ + +error: expected `&mut` but `&` was provided + ┌─ tests/lambda/inline-parity/subtype_args_invalid.move:21:9 + │ +21 │ f(&0, &0); // not okay + │ ^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args_invalid.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args_invalid.move new file mode 100644 index 00000000000000..713bea01c59db1 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args_invalid.move @@ -0,0 +1,23 @@ +module 0x8675309::M { + struct S {} + + fun mut(x: &mut T) {} + fun imm_mut(x: &T, y: &mut T) {} + fun mut_imm(x: &mut T, y: &T) {} + fun mut_mut(x: &mut T, y: &mut T) {} + + fun t0() { + mut(&0); + mut(&S{}); + } + + fun t1() { + imm_mut(&0, &0); + mut_imm(&0, &0); + mut_mut(&0, &0); + } + + fun t2(f: |&mut u64, &u64|) { + f(&0, &0); // not okay + } +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unnecessary_numerical_extreme_comparisons_warn.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unnecessary_numerical_extreme_comparisons_warn.exp new file mode 100644 index 00000000000000..99254c63344eed --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unnecessary_numerical_extreme_comparisons_warn.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `m::apply` has a function parameter: + ┌─ tests/lambda/inline-parity/unnecessary_numerical_extreme_comparisons_warn.move:49:9 + │ +49 │ fun apply(f: |u8|bool, x: u8): bool { + │ ^^^^^ - Parameter `f` has function-valued type `|u8|bool`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unnecessary_numerical_extreme_comparisons_warn.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unnecessary_numerical_extreme_comparisons_warn.lambda.exp new file mode 100644 index 00000000000000..fe498c0358a60d --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unnecessary_numerical_extreme_comparisons_warn.lambda.exp @@ -0,0 +1,1800 @@ +// -- Model dump before env processor pipeline: +module 0xc0ffee::m { + private fun apply(f: |u8|bool,x: u8): bool { + (f)(x) + } + private fun bar() { + Tuple() + } + private fun foo(x: #0): #0 { + x + } + public fun test1(x: u8) { + if Gt(Add(x, 1), 255) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test2(x: &u8,y: &u8) { + if Eq(Gt(Add(Deref(x), Deref(y)), 255), true) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test3(x: u8) { + if Or(Lt(x, 0), Gt(0, x)) { + m::bar() + } else { + Tuple() + }; + if Le(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Ge(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Gt(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Lt(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Ge(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Le(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test4(a: u8,b: u16,c: u32,d: u64,e: u128,f: u256) { + if Or(Gt(a, 255), Gt(f, Cast(255))) { + m::bar() + } else { + Tuple() + }; + if Ge(b, 65535) { + m::bar() + } else { + Tuple() + }; + if Lt(4294967295, c) { + m::bar() + } else { + Tuple() + }; + if Le(18446744073709551615, d) { + m::bar() + } else { + Tuple() + }; + if Lt(e, 340282366920938463463374607431768211455) { + m::bar() + } else { + Tuple() + }; + if Le(f, 115792089237316195423570985008687907853269984665640564039457584007913129639935) { + m::bar() + } else { + Tuple() + }; + if Ge(115792089237316195423570985008687907853269984665640564039457584007913129639935, f) { + m::bar() + } else { + Tuple() + }; + if Gt(340282366920938463463374607431768211455, e) { + m::bar() + } else { + Tuple() + }; + spec { + assert Le($t0, 255); + } + + } + public fun test5(x: u8): bool { + m::apply(|x: u8| Gt(x, 255), x) + } +} // end 0xc0ffee::m +module 0xc0ffee::no_warn { + public fun test(x: u8) { + if Lt(x, 0) { + Abort(1) + } else { + Tuple() + }; + Tuple() + } +} // end 0xc0ffee::no_warn + + +// -- Model dump after env processor unused checks: +module 0xc0ffee::m { + private fun apply(f: |u8|bool,x: u8): bool { + (f)(x) + } + private fun bar() { + Tuple() + } + private fun foo(x: #0): #0 { + x + } + public fun test1(x: u8) { + if Gt(Add(x, 1), 255) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test2(x: &u8,y: &u8) { + if Eq(Gt(Add(Deref(x), Deref(y)), 255), true) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test3(x: u8) { + if Or(Lt(x, 0), Gt(0, x)) { + m::bar() + } else { + Tuple() + }; + if Le(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Ge(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Gt(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Lt(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Ge(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Le(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test4(a: u8,b: u16,c: u32,d: u64,e: u128,f: u256) { + if Or(Gt(a, 255), Gt(f, Cast(255))) { + m::bar() + } else { + Tuple() + }; + if Ge(b, 65535) { + m::bar() + } else { + Tuple() + }; + if Lt(4294967295, c) { + m::bar() + } else { + Tuple() + }; + if Le(18446744073709551615, d) { + m::bar() + } else { + Tuple() + }; + if Lt(e, 340282366920938463463374607431768211455) { + m::bar() + } else { + Tuple() + }; + if Le(f, 115792089237316195423570985008687907853269984665640564039457584007913129639935) { + m::bar() + } else { + Tuple() + }; + if Ge(115792089237316195423570985008687907853269984665640564039457584007913129639935, f) { + m::bar() + } else { + Tuple() + }; + if Gt(340282366920938463463374607431768211455, e) { + m::bar() + } else { + Tuple() + }; + spec { + assert Le($t0, 255); + } + + } + public fun test5(x: u8): bool { + m::apply(|x: u8| Gt(x, 255), x) + } +} // end 0xc0ffee::m +module 0xc0ffee::no_warn { + public fun test(x: u8) { + if Lt(x, 0) { + Abort(1) + } else { + Tuple() + }; + Tuple() + } +} // end 0xc0ffee::no_warn + + +// -- Model dump after env processor type parameter check: +module 0xc0ffee::m { + private fun apply(f: |u8|bool,x: u8): bool { + (f)(x) + } + private fun bar() { + Tuple() + } + private fun foo(x: #0): #0 { + x + } + public fun test1(x: u8) { + if Gt(Add(x, 1), 255) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test2(x: &u8,y: &u8) { + if Eq(Gt(Add(Deref(x), Deref(y)), 255), true) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test3(x: u8) { + if Or(Lt(x, 0), Gt(0, x)) { + m::bar() + } else { + Tuple() + }; + if Le(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Ge(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Gt(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Lt(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Ge(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Le(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test4(a: u8,b: u16,c: u32,d: u64,e: u128,f: u256) { + if Or(Gt(a, 255), Gt(f, Cast(255))) { + m::bar() + } else { + Tuple() + }; + if Ge(b, 65535) { + m::bar() + } else { + Tuple() + }; + if Lt(4294967295, c) { + m::bar() + } else { + Tuple() + }; + if Le(18446744073709551615, d) { + m::bar() + } else { + Tuple() + }; + if Lt(e, 340282366920938463463374607431768211455) { + m::bar() + } else { + Tuple() + }; + if Le(f, 115792089237316195423570985008687907853269984665640564039457584007913129639935) { + m::bar() + } else { + Tuple() + }; + if Ge(115792089237316195423570985008687907853269984665640564039457584007913129639935, f) { + m::bar() + } else { + Tuple() + }; + if Gt(340282366920938463463374607431768211455, e) { + m::bar() + } else { + Tuple() + }; + spec { + assert Le($t0, 255); + } + + } + public fun test5(x: u8): bool { + m::apply(|x: u8| Gt(x, 255), x) + } +} // end 0xc0ffee::m +module 0xc0ffee::no_warn { + public fun test(x: u8) { + if Lt(x, 0) { + Abort(1) + } else { + Tuple() + }; + Tuple() + } +} // end 0xc0ffee::no_warn + + +// -- Model dump after env processor check recursive struct definition: +module 0xc0ffee::m { + private fun apply(f: |u8|bool,x: u8): bool { + (f)(x) + } + private fun bar() { + Tuple() + } + private fun foo(x: #0): #0 { + x + } + public fun test1(x: u8) { + if Gt(Add(x, 1), 255) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test2(x: &u8,y: &u8) { + if Eq(Gt(Add(Deref(x), Deref(y)), 255), true) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test3(x: u8) { + if Or(Lt(x, 0), Gt(0, x)) { + m::bar() + } else { + Tuple() + }; + if Le(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Ge(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Gt(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Lt(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Ge(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Le(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test4(a: u8,b: u16,c: u32,d: u64,e: u128,f: u256) { + if Or(Gt(a, 255), Gt(f, Cast(255))) { + m::bar() + } else { + Tuple() + }; + if Ge(b, 65535) { + m::bar() + } else { + Tuple() + }; + if Lt(4294967295, c) { + m::bar() + } else { + Tuple() + }; + if Le(18446744073709551615, d) { + m::bar() + } else { + Tuple() + }; + if Lt(e, 340282366920938463463374607431768211455) { + m::bar() + } else { + Tuple() + }; + if Le(f, 115792089237316195423570985008687907853269984665640564039457584007913129639935) { + m::bar() + } else { + Tuple() + }; + if Ge(115792089237316195423570985008687907853269984665640564039457584007913129639935, f) { + m::bar() + } else { + Tuple() + }; + if Gt(340282366920938463463374607431768211455, e) { + m::bar() + } else { + Tuple() + }; + spec { + assert Le($t0, 255); + } + + } + public fun test5(x: u8): bool { + m::apply(|x: u8| Gt(x, 255), x) + } +} // end 0xc0ffee::m +module 0xc0ffee::no_warn { + public fun test(x: u8) { + if Lt(x, 0) { + Abort(1) + } else { + Tuple() + }; + Tuple() + } +} // end 0xc0ffee::no_warn + + +// -- Model dump after env processor check cyclic type instantiation: +module 0xc0ffee::m { + private fun apply(f: |u8|bool,x: u8): bool { + (f)(x) + } + private fun bar() { + Tuple() + } + private fun foo(x: #0): #0 { + x + } + public fun test1(x: u8) { + if Gt(Add(x, 1), 255) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test2(x: &u8,y: &u8) { + if Eq(Gt(Add(Deref(x), Deref(y)), 255), true) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test3(x: u8) { + if Or(Lt(x, 0), Gt(0, x)) { + m::bar() + } else { + Tuple() + }; + if Le(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Ge(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Gt(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Lt(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Ge(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Le(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test4(a: u8,b: u16,c: u32,d: u64,e: u128,f: u256) { + if Or(Gt(a, 255), Gt(f, Cast(255))) { + m::bar() + } else { + Tuple() + }; + if Ge(b, 65535) { + m::bar() + } else { + Tuple() + }; + if Lt(4294967295, c) { + m::bar() + } else { + Tuple() + }; + if Le(18446744073709551615, d) { + m::bar() + } else { + Tuple() + }; + if Lt(e, 340282366920938463463374607431768211455) { + m::bar() + } else { + Tuple() + }; + if Le(f, 115792089237316195423570985008687907853269984665640564039457584007913129639935) { + m::bar() + } else { + Tuple() + }; + if Ge(115792089237316195423570985008687907853269984665640564039457584007913129639935, f) { + m::bar() + } else { + Tuple() + }; + if Gt(340282366920938463463374607431768211455, e) { + m::bar() + } else { + Tuple() + }; + spec { + assert Le($t0, 255); + } + + } + public fun test5(x: u8): bool { + m::apply(|x: u8| Gt(x, 255), x) + } +} // end 0xc0ffee::m +module 0xc0ffee::no_warn { + public fun test(x: u8) { + if Lt(x, 0) { + Abort(1) + } else { + Tuple() + }; + Tuple() + } +} // end 0xc0ffee::no_warn + + +// -- Model dump after env processor unused struct params check: +module 0xc0ffee::m { + private fun apply(f: |u8|bool,x: u8): bool { + (f)(x) + } + private fun bar() { + Tuple() + } + private fun foo(x: #0): #0 { + x + } + public fun test1(x: u8) { + if Gt(Add(x, 1), 255) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test2(x: &u8,y: &u8) { + if Eq(Gt(Add(Deref(x), Deref(y)), 255), true) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test3(x: u8) { + if Or(Lt(x, 0), Gt(0, x)) { + m::bar() + } else { + Tuple() + }; + if Le(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Ge(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Gt(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Lt(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Ge(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Le(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test4(a: u8,b: u16,c: u32,d: u64,e: u128,f: u256) { + if Or(Gt(a, 255), Gt(f, Cast(255))) { + m::bar() + } else { + Tuple() + }; + if Ge(b, 65535) { + m::bar() + } else { + Tuple() + }; + if Lt(4294967295, c) { + m::bar() + } else { + Tuple() + }; + if Le(18446744073709551615, d) { + m::bar() + } else { + Tuple() + }; + if Lt(e, 340282366920938463463374607431768211455) { + m::bar() + } else { + Tuple() + }; + if Le(f, 115792089237316195423570985008687907853269984665640564039457584007913129639935) { + m::bar() + } else { + Tuple() + }; + if Ge(115792089237316195423570985008687907853269984665640564039457584007913129639935, f) { + m::bar() + } else { + Tuple() + }; + if Gt(340282366920938463463374607431768211455, e) { + m::bar() + } else { + Tuple() + }; + spec { + assert Le($t0, 255); + } + + } + public fun test5(x: u8): bool { + m::apply(|x: u8| Gt(x, 255), x) + } +} // end 0xc0ffee::m +module 0xc0ffee::no_warn { + public fun test(x: u8) { + if Lt(x, 0) { + Abort(1) + } else { + Tuple() + }; + Tuple() + } +} // end 0xc0ffee::no_warn + + +// -- Model dump after env processor access and use check before inlining: +module 0xc0ffee::m { + private fun apply(f: |u8|bool,x: u8): bool { + (f)(x) + } + private fun bar() { + Tuple() + } + private fun foo(x: #0): #0 { + x + } + public fun test1(x: u8) { + if Gt(Add(x, 1), 255) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test2(x: &u8,y: &u8) { + if Eq(Gt(Add(Deref(x), Deref(y)), 255), true) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test3(x: u8) { + if Or(Lt(x, 0), Gt(0, x)) { + m::bar() + } else { + Tuple() + }; + if Le(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Ge(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Gt(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Lt(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Ge(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Le(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test4(a: u8,b: u16,c: u32,d: u64,e: u128,f: u256) { + if Or(Gt(a, 255), Gt(f, Cast(255))) { + m::bar() + } else { + Tuple() + }; + if Ge(b, 65535) { + m::bar() + } else { + Tuple() + }; + if Lt(4294967295, c) { + m::bar() + } else { + Tuple() + }; + if Le(18446744073709551615, d) { + m::bar() + } else { + Tuple() + }; + if Lt(e, 340282366920938463463374607431768211455) { + m::bar() + } else { + Tuple() + }; + if Le(f, 115792089237316195423570985008687907853269984665640564039457584007913129639935) { + m::bar() + } else { + Tuple() + }; + if Ge(115792089237316195423570985008687907853269984665640564039457584007913129639935, f) { + m::bar() + } else { + Tuple() + }; + if Gt(340282366920938463463374607431768211455, e) { + m::bar() + } else { + Tuple() + }; + spec { + assert Le($t0, 255); + } + + } + public fun test5(x: u8): bool { + m::apply(|x: u8| Gt(x, 255), x) + } +} // end 0xc0ffee::m +module 0xc0ffee::no_warn { + public fun test(x: u8) { + if Lt(x, 0) { + Abort(1) + } else { + Tuple() + }; + Tuple() + } +} // end 0xc0ffee::no_warn + + +// -- Model dump after env processor inlining: +module 0xc0ffee::m { + private fun apply(f: |u8|bool,x: u8): bool { + (f)(x) + } + private fun bar() { + Tuple() + } + private fun foo(x: #0): #0 { + x + } + public fun test1(x: u8) { + if Gt(Add(x, 1), 255) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test2(x: &u8,y: &u8) { + if Eq(Gt(Add(Deref(x), Deref(y)), 255), true) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test3(x: u8) { + if Or(Lt(x, 0), Gt(0, x)) { + m::bar() + } else { + Tuple() + }; + if Le(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Ge(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Gt(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Lt(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Ge(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Le(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test4(a: u8,b: u16,c: u32,d: u64,e: u128,f: u256) { + if Or(Gt(a, 255), Gt(f, Cast(255))) { + m::bar() + } else { + Tuple() + }; + if Ge(b, 65535) { + m::bar() + } else { + Tuple() + }; + if Lt(4294967295, c) { + m::bar() + } else { + Tuple() + }; + if Le(18446744073709551615, d) { + m::bar() + } else { + Tuple() + }; + if Lt(e, 340282366920938463463374607431768211455) { + m::bar() + } else { + Tuple() + }; + if Le(f, 115792089237316195423570985008687907853269984665640564039457584007913129639935) { + m::bar() + } else { + Tuple() + }; + if Ge(115792089237316195423570985008687907853269984665640564039457584007913129639935, f) { + m::bar() + } else { + Tuple() + }; + if Gt(340282366920938463463374607431768211455, e) { + m::bar() + } else { + Tuple() + }; + spec { + assert Le($t0, 255); + } + + } + public fun test5(x: u8): bool { + m::apply(|x: u8| Gt(x, 255), x) + } +} // end 0xc0ffee::m +module 0xc0ffee::no_warn { + public fun test(x: u8) { + if Lt(x, 0) { + Abort(1) + } else { + Tuple() + }; + Tuple() + } +} // end 0xc0ffee::no_warn + + +// -- Model dump after env processor access and use check after inlining: +module 0xc0ffee::m { + private fun apply(f: |u8|bool,x: u8): bool { + (f)(x) + } + private fun bar() { + Tuple() + } + private fun foo(x: #0): #0 { + x + } + public fun test1(x: u8) { + if Gt(Add(x, 1), 255) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test2(x: &u8,y: &u8) { + if Eq(Gt(Add(Deref(x), Deref(y)), 255), true) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test3(x: u8) { + if Or(Lt(x, 0), Gt(0, x)) { + m::bar() + } else { + Tuple() + }; + if Le(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Ge(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Gt(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Lt(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Ge(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Le(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test4(a: u8,b: u16,c: u32,d: u64,e: u128,f: u256) { + if Or(Gt(a, 255), Gt(f, Cast(255))) { + m::bar() + } else { + Tuple() + }; + if Ge(b, 65535) { + m::bar() + } else { + Tuple() + }; + if Lt(4294967295, c) { + m::bar() + } else { + Tuple() + }; + if Le(18446744073709551615, d) { + m::bar() + } else { + Tuple() + }; + if Lt(e, 340282366920938463463374607431768211455) { + m::bar() + } else { + Tuple() + }; + if Le(f, 115792089237316195423570985008687907853269984665640564039457584007913129639935) { + m::bar() + } else { + Tuple() + }; + if Ge(115792089237316195423570985008687907853269984665640564039457584007913129639935, f) { + m::bar() + } else { + Tuple() + }; + if Gt(340282366920938463463374607431768211455, e) { + m::bar() + } else { + Tuple() + }; + spec { + assert Le($t0, 255); + } + + } + public fun test5(x: u8): bool { + m::apply(|x: u8| Gt(x, 255), x) + } +} // end 0xc0ffee::m +module 0xc0ffee::no_warn { + public fun test(x: u8) { + if Lt(x, 0) { + Abort(1) + } else { + Tuple() + }; + Tuple() + } +} // end 0xc0ffee::no_warn + + +// -- Model dump after env processor acquires check: +module 0xc0ffee::m { + private fun apply(f: |u8|bool,x: u8): bool { + (f)(x) + } + private fun bar() { + Tuple() + } + private fun foo(x: #0): #0 { + x + } + public fun test1(x: u8) { + if Gt(Add(x, 1), 255) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test2(x: &u8,y: &u8) { + if Eq(Gt(Add(Deref(x), Deref(y)), 255), true) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test3(x: u8) { + if Or(Lt(x, 0), Gt(0, x)) { + m::bar() + } else { + Tuple() + }; + if Le(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Ge(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Gt(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Lt(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Ge(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Le(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test4(a: u8,b: u16,c: u32,d: u64,e: u128,f: u256) { + if Or(Gt(a, 255), Gt(f, Cast(255))) { + m::bar() + } else { + Tuple() + }; + if Ge(b, 65535) { + m::bar() + } else { + Tuple() + }; + if Lt(4294967295, c) { + m::bar() + } else { + Tuple() + }; + if Le(18446744073709551615, d) { + m::bar() + } else { + Tuple() + }; + if Lt(e, 340282366920938463463374607431768211455) { + m::bar() + } else { + Tuple() + }; + if Le(f, 115792089237316195423570985008687907853269984665640564039457584007913129639935) { + m::bar() + } else { + Tuple() + }; + if Ge(115792089237316195423570985008687907853269984665640564039457584007913129639935, f) { + m::bar() + } else { + Tuple() + }; + if Gt(340282366920938463463374607431768211455, e) { + m::bar() + } else { + Tuple() + }; + spec { + assert Le($t0, 255); + } + + } + public fun test5(x: u8): bool { + m::apply(|x: u8| Gt(x, 255), x) + } +} // end 0xc0ffee::m +module 0xc0ffee::no_warn { + public fun test(x: u8) { + if Lt(x, 0) { + Abort(1) + } else { + Tuple() + }; + Tuple() + } +} // end 0xc0ffee::no_warn + + +// -- Model dump after env processor simplifier: +module 0xc0ffee::m { + private fun apply(f: |u8|bool,x: u8): bool { + (f)(x) + } + private fun bar() { + Tuple() + } + private fun foo(x: #0): #0 { + x + } + public fun test1(x: u8) { + if Gt(Add(x, 1), 255) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test2(x: &u8,y: &u8) { + if Eq(Gt(Add(Deref(x), Deref(y)), 255), true) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test3(x: u8) { + if Or(Lt(x, 0), Gt(0, x)) { + m::bar() + } else { + Tuple() + }; + if Le(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Ge(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Gt(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Lt(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Ge(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Le(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test4(a: u8,b: u16,c: u32,d: u64,e: u128,f: u256) { + if Or(Gt(a, 255), Gt(f, 255)) { + m::bar() + } else { + Tuple() + }; + if Ge(b, 65535) { + m::bar() + } else { + Tuple() + }; + if Lt(4294967295, c) { + m::bar() + } else { + Tuple() + }; + if Le(18446744073709551615, d) { + m::bar() + } else { + Tuple() + }; + if Lt(e, 340282366920938463463374607431768211455) { + m::bar() + } else { + Tuple() + }; + if Le(f, 115792089237316195423570985008687907853269984665640564039457584007913129639935) { + m::bar() + } else { + Tuple() + }; + if Ge(115792089237316195423570985008687907853269984665640564039457584007913129639935, f) { + m::bar() + } else { + Tuple() + }; + if Gt(340282366920938463463374607431768211455, e) { + m::bar() + } else { + Tuple() + }; + spec { + assert Le($t0, 255); + } + + } + public fun test5(x: u8): bool { + m::apply(|x: u8| Gt(x, 255), x) + } +} // end 0xc0ffee::m +module 0xc0ffee::no_warn { + public fun test(x: u8) { + if Lt(x, 0) { + Abort(1) + } else { + Tuple() + }; + Tuple() + } +} // end 0xc0ffee::no_warn + + +// -- Model dump after env processor lambda-lifting: +module 0xc0ffee::m { + private fun apply(f: |u8|bool,x: u8): bool { + (f)(x) + } + private fun bar() { + Tuple() + } + private fun foo(x: #0): #0 { + x + } + public fun test1(x: u8) { + if Gt(Add(x, 1), 255) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test2(x: &u8,y: &u8) { + if Eq(Gt(Add(Deref(x), Deref(y)), 255), true) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test3(x: u8) { + if Or(Lt(x, 0), Gt(0, x)) { + m::bar() + } else { + Tuple() + }; + if Le(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Ge(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Gt(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Lt(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Ge(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Le(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test4(a: u8,b: u16,c: u32,d: u64,e: u128,f: u256) { + if Or(Gt(a, 255), Gt(f, 255)) { + m::bar() + } else { + Tuple() + }; + if Ge(b, 65535) { + m::bar() + } else { + Tuple() + }; + if Lt(4294967295, c) { + m::bar() + } else { + Tuple() + }; + if Le(18446744073709551615, d) { + m::bar() + } else { + Tuple() + }; + if Lt(e, 340282366920938463463374607431768211455) { + m::bar() + } else { + Tuple() + }; + if Le(f, 115792089237316195423570985008687907853269984665640564039457584007913129639935) { + m::bar() + } else { + Tuple() + }; + if Ge(115792089237316195423570985008687907853269984665640564039457584007913129639935, f) { + m::bar() + } else { + Tuple() + }; + if Gt(340282366920938463463374607431768211455, e) { + m::bar() + } else { + Tuple() + }; + spec { + assert Le($t0, 255); + } + + } + public fun test5(x: u8): bool { + m::apply(closure m::test5$lambda$1(), x) + } + private fun test5$lambda$1(x: u8): bool { + Gt(x, 255) + } +} // end 0xc0ffee::m +module 0xc0ffee::no_warn { + public fun test(x: u8) { + if Lt(x, 0) { + Abort(1) + } else { + Tuple() + }; + Tuple() + } +} // end 0xc0ffee::no_warn + + +// -- Model dump after env processor specification checker: +module 0xc0ffee::m { + private fun apply(f: |u8|bool,x: u8): bool { + (f)(x) + } + private fun bar() { + Tuple() + } + private fun foo(x: #0): #0 { + x + } + public fun test1(x: u8) { + if Gt(Add(x, 1), 255) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test2(x: &u8,y: &u8) { + if Eq(Gt(Add(Deref(x), Deref(y)), 255), true) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test3(x: u8) { + if Or(Lt(x, 0), Gt(0, x)) { + m::bar() + } else { + Tuple() + }; + if Le(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Ge(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Gt(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Lt(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Ge(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Le(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test4(a: u8,b: u16,c: u32,d: u64,e: u128,f: u256) { + if Or(Gt(a, 255), Gt(f, 255)) { + m::bar() + } else { + Tuple() + }; + if Ge(b, 65535) { + m::bar() + } else { + Tuple() + }; + if Lt(4294967295, c) { + m::bar() + } else { + Tuple() + }; + if Le(18446744073709551615, d) { + m::bar() + } else { + Tuple() + }; + if Lt(e, 340282366920938463463374607431768211455) { + m::bar() + } else { + Tuple() + }; + if Le(f, 115792089237316195423570985008687907853269984665640564039457584007913129639935) { + m::bar() + } else { + Tuple() + }; + if Ge(115792089237316195423570985008687907853269984665640564039457584007913129639935, f) { + m::bar() + } else { + Tuple() + }; + if Gt(340282366920938463463374607431768211455, e) { + m::bar() + } else { + Tuple() + }; + spec { + assert Le($t0, 255); + } + + } + public fun test5(x: u8): bool { + m::apply(closure m::test5$lambda$1(), x) + } + private fun test5$lambda$1(x: u8): bool { + Gt(x, 255) + } +} // end 0xc0ffee::m +module 0xc0ffee::no_warn { + public fun test(x: u8) { + if Lt(x, 0) { + Abort(1) + } else { + Tuple() + }; + Tuple() + } +} // end 0xc0ffee::no_warn + + +// -- Model dump after env processor specification rewriter: +module 0xc0ffee::m { + private fun apply(f: |u8|bool,x: u8): bool { + (f)(x) + } + private fun bar() { + Tuple() + } + private fun foo(x: #0): #0 { + x + } + public fun test1(x: u8) { + if Gt(Add(x, 1), 255) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test2(x: &u8,y: &u8) { + if Eq(Gt(Add(Deref(x), Deref(y)), 255), true) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test3(x: u8) { + if Or(Lt(x, 0), Gt(0, x)) { + m::bar() + } else { + Tuple() + }; + if Le(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Ge(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Gt(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Lt(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + if Ge(m::foo(x), 0) { + m::bar() + } else { + Tuple() + }; + if Le(0, m::foo(x)) { + m::bar() + } else { + Tuple() + }; + Tuple() + } + public fun test4(a: u8,b: u16,c: u32,d: u64,e: u128,f: u256) { + if Or(Gt(a, 255), Gt(f, 255)) { + m::bar() + } else { + Tuple() + }; + if Ge(b, 65535) { + m::bar() + } else { + Tuple() + }; + if Lt(4294967295, c) { + m::bar() + } else { + Tuple() + }; + if Le(18446744073709551615, d) { + m::bar() + } else { + Tuple() + }; + if Lt(e, 340282366920938463463374607431768211455) { + m::bar() + } else { + Tuple() + }; + if Le(f, 115792089237316195423570985008687907853269984665640564039457584007913129639935) { + m::bar() + } else { + Tuple() + }; + if Ge(115792089237316195423570985008687907853269984665640564039457584007913129639935, f) { + m::bar() + } else { + Tuple() + }; + if Gt(340282366920938463463374607431768211455, e) { + m::bar() + } else { + Tuple() + }; + spec { + assert Le($t0, 255); + } + + } + public fun test5(x: u8): bool { + m::apply(closure m::test5$lambda$1(), x) + } + private fun test5$lambda$1(x: u8): bool { + Gt(x, 255) + } +} // end 0xc0ffee::m +module 0xc0ffee::no_warn { + public fun test(x: u8) { + if Lt(x, 0) { + Abort(1) + } else { + Tuple() + }; + Tuple() + } +} // end 0xc0ffee::no_warn + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/unnecessary_numerical_extreme_comparisons_warn.move:50:9 + │ +50 │ f(x) + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/unnecessary_numerical_extreme_comparisons_warn.move:54:15 + │ +54 │ apply(|x| x > U8_MAX, x) + │ ^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unnecessary_numerical_extreme_comparisons_warn.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unnecessary_numerical_extreme_comparisons_warn.move new file mode 100644 index 00000000000000..e263d40780bc4c --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unnecessary_numerical_extreme_comparisons_warn.move @@ -0,0 +1,63 @@ +module 0xc0ffee::m { + fun bar() {} + + fun foo(x: T): T { + x + } + + public fun test1(x: u8) { + if (x + 1 > 255) { bar() }; + } + + public fun test2(x: &u8, y: &u8) { + if ((*x + *y > 255) == true) { bar() }; + } + + public fun test3(x: u8) { + if (x < 0 || 0 > x) { bar() }; + if (foo(x) <= 0) { bar() }; + if (0 >= foo(x)) { bar() }; + if (foo(x) > 0) { bar() }; + if (0 < foo(x)) { bar() }; + if (foo(x) >= 0) { bar() }; + if (0 <= foo(x)) { bar() }; + } + + const U8_MAX: u8 = 255; + const U16_MAX: u16 = 65535; + const U32_MAX: u32 = 4294967295; + const U64_MAX: u64 = 18446744073709551615; + const U128_MAX: u128 = 340282366920938463463374607431768211455; + const U256_MAX: u256 = + 115792089237316195423570985008687907853269984665640564039457584007913129639935; + + public fun test4(a: u8, b: u16, c: u32, d: u64, e: u128, f: u256) { + // Should not warn for `f > (U8_MAX as u256)`. + if (a > U8_MAX || f > (U8_MAX as u256)) { bar() }; + if (b >= U16_MAX) { bar() }; + if (U32_MAX < c) { bar() }; + if (U64_MAX <= d) { bar() }; + if (e < U128_MAX) { bar() }; + if (f <= U256_MAX) { bar() }; + if (U256_MAX >= f) { bar() }; + if (U128_MAX > e) { bar() }; + spec { + assert a <= U8_MAX; + } + } + + fun apply(f: |u8|bool, x: u8): bool { + f(x) + } + + public fun test5(x: u8): bool { + apply(|x| x > U8_MAX, x) + } +} + +module 0xc0ffee::no_warn { + #[lint::skip(unnecessary_numerical_extreme_comparison)] + public fun test(x: u8) { + if (x < 0) abort 1; + } +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unpack_generic_struct.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unpack_generic_struct.exp new file mode 100644 index 00000000000000..6c0345037f8a1f --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unpack_generic_struct.exp @@ -0,0 +1,13 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `m::h` has a function parameter: + ┌─ tests/lambda/inline-parity/unpack_generic_struct.move:22:16 + │ +22 │ public fun h(x: E, v: |Key| E): E { + │ ^ - Parameter `v` has function-valued type `|Key|m::E`. + +error: Only inline functions may have function-typed parameters, but non-inline function `m::g` has a function parameter: + ┌─ tests/lambda/inline-parity/unpack_generic_struct.move:27:16 + │ +27 │ public fun g(x: E, v: |E|) { + │ ^ - Parameter `v` has function-valued type `|m::E|`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unpack_generic_struct.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unpack_generic_struct.lambda.exp new file mode 100644 index 00000000000000..8eee3b409ad215 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unpack_generic_struct.lambda.exp @@ -0,0 +1,694 @@ +// -- Model dump before env processor pipeline: +module 0x42::m { + use std::vector; + struct E { + key: Key, + } + struct Option { + vec: vector, + } + public fun destroy_none(t: m::Option<#0>) { + if m::is_none(Borrow(Immutable)(t)) { + Tuple() + } else { + Abort(262144) + }; + { + let m::Option{ vec } = t; + vector::destroy_empty(vec) + } + } + public fun foo(data: m::E<#0>,v: &mut #0) { + { + let f: m::E = m::h(data, |e: Key| pack m::E(e)); + m::g(f, |e: m::E| { + let (m::E{ key }, _x: u64): (m::E, u64) = Tuple(e, 3); + v = key; + Tuple() + }); + Tuple() + } + } + public fun g(x: m::E<#0>,v: |m::E<#0>|) { + (v)(x) + } + public fun h(x: m::E<#0>,v: |#0|m::E<#0>): m::E<#0> { + { + let m::E{ key } = x; + (v)(key) + } + } + public fun is_none(t: &m::Option<#0>): bool { + vector::is_empty(Borrow(Immutable)(select m::Option.vec<&m::Option>(t))) + } +} // end 0x42::m + + +// -- Model dump after env processor unused checks: +module 0x42::m { + use std::vector; + struct E { + key: Key, + } + struct Option { + vec: vector, + } + public fun destroy_none(t: m::Option<#0>) { + if m::is_none(Borrow(Immutable)(t)) { + Tuple() + } else { + Abort(262144) + }; + { + let m::Option{ vec } = t; + vector::destroy_empty(vec) + } + } + public fun foo(data: m::E<#0>,v: &mut #0) { + { + let f: m::E = m::h(data, |e: Key| pack m::E(e)); + m::g(f, |e: m::E| { + let (m::E{ key }, _x: u64): (m::E, u64) = Tuple(e, 3); + v = key; + Tuple() + }); + Tuple() + } + } + public fun g(x: m::E<#0>,v: |m::E<#0>|) { + (v)(x) + } + public fun h(x: m::E<#0>,v: |#0|m::E<#0>): m::E<#0> { + { + let m::E{ key } = x; + (v)(key) + } + } + public fun is_none(t: &m::Option<#0>): bool { + vector::is_empty(Borrow(Immutable)(select m::Option.vec<&m::Option>(t))) + } +} // end 0x42::m + + +// -- Model dump after env processor type parameter check: +module 0x42::m { + use std::vector; + struct E { + key: Key, + } + struct Option { + vec: vector, + } + public fun destroy_none(t: m::Option<#0>) { + if m::is_none(Borrow(Immutable)(t)) { + Tuple() + } else { + Abort(262144) + }; + { + let m::Option{ vec } = t; + vector::destroy_empty(vec) + } + } + public fun foo(data: m::E<#0>,v: &mut #0) { + { + let f: m::E = m::h(data, |e: Key| pack m::E(e)); + m::g(f, |e: m::E| { + let (m::E{ key }, _x: u64): (m::E, u64) = Tuple(e, 3); + v = key; + Tuple() + }); + Tuple() + } + } + public fun g(x: m::E<#0>,v: |m::E<#0>|) { + (v)(x) + } + public fun h(x: m::E<#0>,v: |#0|m::E<#0>): m::E<#0> { + { + let m::E{ key } = x; + (v)(key) + } + } + public fun is_none(t: &m::Option<#0>): bool { + vector::is_empty(Borrow(Immutable)(select m::Option.vec<&m::Option>(t))) + } +} // end 0x42::m + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::m { + use std::vector; + struct E { + key: Key, + } + struct Option { + vec: vector, + } + public fun destroy_none(t: m::Option<#0>) { + if m::is_none(Borrow(Immutable)(t)) { + Tuple() + } else { + Abort(262144) + }; + { + let m::Option{ vec } = t; + vector::destroy_empty(vec) + } + } + public fun foo(data: m::E<#0>,v: &mut #0) { + { + let f: m::E = m::h(data, |e: Key| pack m::E(e)); + m::g(f, |e: m::E| { + let (m::E{ key }, _x: u64): (m::E, u64) = Tuple(e, 3); + v = key; + Tuple() + }); + Tuple() + } + } + public fun g(x: m::E<#0>,v: |m::E<#0>|) { + (v)(x) + } + public fun h(x: m::E<#0>,v: |#0|m::E<#0>): m::E<#0> { + { + let m::E{ key } = x; + (v)(key) + } + } + public fun is_none(t: &m::Option<#0>): bool { + vector::is_empty(Borrow(Immutable)(select m::Option.vec<&m::Option>(t))) + } +} // end 0x42::m + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::m { + use std::vector; + struct E { + key: Key, + } + struct Option { + vec: vector, + } + public fun destroy_none(t: m::Option<#0>) { + if m::is_none(Borrow(Immutable)(t)) { + Tuple() + } else { + Abort(262144) + }; + { + let m::Option{ vec } = t; + vector::destroy_empty(vec) + } + } + public fun foo(data: m::E<#0>,v: &mut #0) { + { + let f: m::E = m::h(data, |e: Key| pack m::E(e)); + m::g(f, |e: m::E| { + let (m::E{ key }, _x: u64): (m::E, u64) = Tuple(e, 3); + v = key; + Tuple() + }); + Tuple() + } + } + public fun g(x: m::E<#0>,v: |m::E<#0>|) { + (v)(x) + } + public fun h(x: m::E<#0>,v: |#0|m::E<#0>): m::E<#0> { + { + let m::E{ key } = x; + (v)(key) + } + } + public fun is_none(t: &m::Option<#0>): bool { + vector::is_empty(Borrow(Immutable)(select m::Option.vec<&m::Option>(t))) + } +} // end 0x42::m + + +// -- Model dump after env processor unused struct params check: +module 0x42::m { + use std::vector; + struct E { + key: Key, + } + struct Option { + vec: vector, + } + public fun destroy_none(t: m::Option<#0>) { + if m::is_none(Borrow(Immutable)(t)) { + Tuple() + } else { + Abort(262144) + }; + { + let m::Option{ vec } = t; + vector::destroy_empty(vec) + } + } + public fun foo(data: m::E<#0>,v: &mut #0) { + { + let f: m::E = m::h(data, |e: Key| pack m::E(e)); + m::g(f, |e: m::E| { + let (m::E{ key }, _x: u64): (m::E, u64) = Tuple(e, 3); + v = key; + Tuple() + }); + Tuple() + } + } + public fun g(x: m::E<#0>,v: |m::E<#0>|) { + (v)(x) + } + public fun h(x: m::E<#0>,v: |#0|m::E<#0>): m::E<#0> { + { + let m::E{ key } = x; + (v)(key) + } + } + public fun is_none(t: &m::Option<#0>): bool { + vector::is_empty(Borrow(Immutable)(select m::Option.vec<&m::Option>(t))) + } +} // end 0x42::m + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::m { + use std::vector; + struct E { + key: Key, + } + struct Option { + vec: vector, + } + public fun destroy_none(t: m::Option<#0>) { + if m::is_none(Borrow(Immutable)(t)) { + Tuple() + } else { + Abort(262144) + }; + { + let m::Option{ vec } = t; + vector::destroy_empty(vec) + } + } + public fun foo(data: m::E<#0>,v: &mut #0) { + { + let f: m::E = m::h(data, |e: Key| pack m::E(e)); + m::g(f, |e: m::E| { + let (m::E{ key }, _x: u64): (m::E, u64) = Tuple(e, 3); + v = key; + Tuple() + }); + Tuple() + } + } + public fun g(x: m::E<#0>,v: |m::E<#0>|) { + (v)(x) + } + public fun h(x: m::E<#0>,v: |#0|m::E<#0>): m::E<#0> { + { + let m::E{ key } = x; + (v)(key) + } + } + public fun is_none(t: &m::Option<#0>): bool { + vector::is_empty(Borrow(Immutable)(select m::Option.vec<&m::Option>(t))) + } +} // end 0x42::m + + +// -- Model dump after env processor inlining: +module 0x42::m { + use std::vector; + struct E { + key: Key, + } + struct Option { + vec: vector, + } + public fun destroy_none(t: m::Option<#0>) { + if m::is_none(Borrow(Immutable)(t)) { + Tuple() + } else { + Abort(262144) + }; + { + let m::Option{ vec } = t; + vector::destroy_empty(vec) + } + } + public fun foo(data: m::E<#0>,v: &mut #0) { + { + let f: m::E = m::h(data, |e: Key| pack m::E(e)); + m::g(f, |e: m::E| { + let (m::E{ key }, _x: u64): (m::E, u64) = Tuple(e, 3); + v = key; + Tuple() + }); + Tuple() + } + } + public fun g(x: m::E<#0>,v: |m::E<#0>|) { + (v)(x) + } + public fun h(x: m::E<#0>,v: |#0|m::E<#0>): m::E<#0> { + { + let m::E{ key } = x; + (v)(key) + } + } + public fun is_none(t: &m::Option<#0>): bool { + vector::is_empty(Borrow(Immutable)(select m::Option.vec<&m::Option>(t))) + } +} // end 0x42::m + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::m { + use std::vector; + struct E { + key: Key, + } + struct Option { + vec: vector, + } + public fun destroy_none(t: m::Option<#0>) { + if m::is_none(Borrow(Immutable)(t)) { + Tuple() + } else { + Abort(262144) + }; + { + let m::Option{ vec } = t; + vector::destroy_empty(vec) + } + } + public fun foo(data: m::E<#0>,v: &mut #0) { + { + let f: m::E = m::h(data, |e: Key| pack m::E(e)); + m::g(f, |e: m::E| { + let (m::E{ key }, _x: u64): (m::E, u64) = Tuple(e, 3); + v = key; + Tuple() + }); + Tuple() + } + } + public fun g(x: m::E<#0>,v: |m::E<#0>|) { + (v)(x) + } + public fun h(x: m::E<#0>,v: |#0|m::E<#0>): m::E<#0> { + { + let m::E{ key } = x; + (v)(key) + } + } + public fun is_none(t: &m::Option<#0>): bool { + vector::is_empty(Borrow(Immutable)(select m::Option.vec<&m::Option>(t))) + } +} // end 0x42::m + + +// -- Model dump after env processor acquires check: +module 0x42::m { + use std::vector; + struct E { + key: Key, + } + struct Option { + vec: vector, + } + public fun destroy_none(t: m::Option<#0>) { + if m::is_none(Borrow(Immutable)(t)) { + Tuple() + } else { + Abort(262144) + }; + { + let m::Option{ vec } = t; + vector::destroy_empty(vec) + } + } + public fun foo(data: m::E<#0>,v: &mut #0) { + { + let f: m::E = m::h(data, |e: Key| pack m::E(e)); + m::g(f, |e: m::E| { + let (m::E{ key }, _x: u64): (m::E, u64) = Tuple(e, 3); + v = key; + Tuple() + }); + Tuple() + } + } + public fun g(x: m::E<#0>,v: |m::E<#0>|) { + (v)(x) + } + public fun h(x: m::E<#0>,v: |#0|m::E<#0>): m::E<#0> { + { + let m::E{ key } = x; + (v)(key) + } + } + public fun is_none(t: &m::Option<#0>): bool { + vector::is_empty(Borrow(Immutable)(select m::Option.vec<&m::Option>(t))) + } +} // end 0x42::m + + +// -- Model dump after env processor simplifier: +module 0x42::m { + use std::vector; + struct E { + key: Key, + } + struct Option { + vec: vector, + } + public fun destroy_none(t: m::Option<#0>) { + if m::is_none(Borrow(Immutable)(t)) { + Tuple() + } else { + Abort(262144) + }; + { + let m::Option{ vec } = t; + vector::destroy_empty(vec) + } + } + public fun foo(data: m::E<#0>,v: &mut #0) { + { + let f: m::E = m::h(data, |e: Key| pack m::E(e)); + m::g(f, |e: m::E| { + let (m::E{ key }, _x: u64): (m::E, u64) = Tuple(e, 3); + v = key; + Tuple() + }); + Tuple() + } + } + public fun g(x: m::E<#0>,v: |m::E<#0>|) { + (v)(x) + } + public fun h(x: m::E<#0>,v: |#0|m::E<#0>): m::E<#0> { + { + let m::E{ key } = x; + (v)(key) + } + } + public fun is_none(t: &m::Option<#0>): bool { + vector::is_empty(Borrow(Immutable)(select m::Option.vec<&m::Option>(t))) + } +} // end 0x42::m + + +// -- Model dump after env processor lambda-lifting: +module 0x42::m { + use std::vector; + struct E { + key: Key, + } + struct Option { + vec: vector, + } + public fun destroy_none(t: m::Option<#0>) { + if m::is_none(Borrow(Immutable)(t)) { + Tuple() + } else { + Abort(262144) + }; + { + let m::Option{ vec } = t; + vector::destroy_empty(vec) + } + } + public fun foo(data: m::E<#0>,v: &mut #0) { + { + let f: m::E = m::h(data, closure m::foo$lambda$1()); + m::g(f, closure m::foo$lambda$2(v)); + Tuple() + } + } + public fun g(x: m::E<#0>,v: |m::E<#0>|) { + (v)(x) + } + public fun h(x: m::E<#0>,v: |#0|m::E<#0>): m::E<#0> { + { + let m::E{ key } = x; + (v)(key) + } + } + public fun is_none(t: &m::Option<#0>): bool { + vector::is_empty(Borrow(Immutable)(select m::Option.vec<&m::Option>(t))) + } + private fun foo$lambda$1(e: #0): m::E<#0> { + pack m::E(e) + } + private fun foo$lambda$2(v: &mut #0,e: m::E<#0>) { + { + let (m::E{ key }, _x: u64): (m::E, u64) = Tuple(e, 3); + v = key; + Tuple() + } + } +} // end 0x42::m + + +// -- Model dump after env processor specification checker: +module 0x42::m { + use std::vector; + struct E { + key: Key, + } + struct Option { + vec: vector, + } + public fun destroy_none(t: m::Option<#0>) { + if m::is_none(Borrow(Immutable)(t)) { + Tuple() + } else { + Abort(262144) + }; + { + let m::Option{ vec } = t; + vector::destroy_empty(vec) + } + } + public fun foo(data: m::E<#0>,v: &mut #0) { + { + let f: m::E = m::h(data, closure m::foo$lambda$1()); + m::g(f, closure m::foo$lambda$2(v)); + Tuple() + } + } + public fun g(x: m::E<#0>,v: |m::E<#0>|) { + (v)(x) + } + public fun h(x: m::E<#0>,v: |#0|m::E<#0>): m::E<#0> { + { + let m::E{ key } = x; + (v)(key) + } + } + public fun is_none(t: &m::Option<#0>): bool { + vector::is_empty(Borrow(Immutable)(select m::Option.vec<&m::Option>(t))) + } + private fun foo$lambda$1(e: #0): m::E<#0> { + pack m::E(e) + } + private fun foo$lambda$2(v: &mut #0,e: m::E<#0>) { + { + let (m::E{ key }, _x: u64): (m::E, u64) = Tuple(e, 3); + v = key; + Tuple() + } + } +} // end 0x42::m + + +// -- Model dump after env processor specification rewriter: +module 0x42::m { + use std::vector; + struct E { + key: Key, + } + struct Option { + vec: vector, + } + public fun destroy_none(t: m::Option<#0>) { + if m::is_none(Borrow(Immutable)(t)) { + Tuple() + } else { + Abort(262144) + }; + { + let m::Option{ vec } = t; + vector::destroy_empty(vec) + } + } + public fun foo(data: m::E<#0>,v: &mut #0) { + { + let f: m::E = m::h(data, closure m::foo$lambda$1()); + m::g(f, closure m::foo$lambda$2(v)); + Tuple() + } + } + public fun g(x: m::E<#0>,v: |m::E<#0>|) { + (v)(x) + } + public fun h(x: m::E<#0>,v: |#0|m::E<#0>): m::E<#0> { + { + let m::E{ key } = x; + (v)(key) + } + } + public fun is_none(t: &m::Option<#0>): bool { + vector::is_empty(Borrow(Immutable)(select m::Option.vec<&m::Option>(t))) + } + private fun foo$lambda$1(e: #0): m::E<#0> { + pack m::E(e) + } + private fun foo$lambda$2(v: &mut #0,e: m::E<#0>) { + { + let (m::E{ key }, _x: u64): (m::E, u64) = Tuple(e, 3); + v = key; + Tuple() + } + } +} // end 0x42::m + + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/unpack_generic_struct.move:24:9 + │ +24 │ v(key) + │ ^ + +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/unpack_generic_struct.move:28:9 + │ +28 │ v(x) + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/unpack_generic_struct.move:33:25 + │ +33 │ let f = h(data, |e| { + │ ╭─────────────────────────^ +34 │ │ E {key: e} +35 │ │ }); + │ ╰─────────^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/unpack_generic_struct.move:36:14 + │ +36 │ g(f, |e| { + │ ╭──────────────^ +37 │ │ let (E { key }, _x) = (e, 3); +38 │ │ *v = key; +39 │ │ }); + │ ╰─────────^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unpack_generic_struct.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unpack_generic_struct.move new file mode 100644 index 00000000000000..06285aa1fb1f0a --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unpack_generic_struct.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 fun h(x: E, v: |Key| E): E { + let E { key } = x; + v(key) + } + + public fun g(x: E, v: |E|) { + v(x) + } + + public fun foo( + data: E, v: &mut Key) { + let f = h(data, |e| { + E {key: e} + }); + g(f, |e| { + let (E { key }, _x) = (e, 3); + *v = key; + }); + } + +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unused_lambda_param.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unused_lambda_param.exp new file mode 100644 index 00000000000000..b4f15cc9bb9355 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unused_lambda_param.exp @@ -0,0 +1,13 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `m::test` has a function parameter: + ┌─ tests/lambda/inline-parity/unused_lambda_param.move:2:9 + │ +2 │ fun test(p: u64, f: |u64| u64): u64 { + │ ^^^^ - Parameter `f` has function-valued type `|u64|u64`. + +warning: Unused anonymous function parameter `x`. Consider removing or prefixing with an underscore: `_x` + ┌─ tests/lambda/inline-parity/unused_lambda_param.move:7:18 + │ +7 │ test(0, |x| 1); + │ ^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unused_lambda_param.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unused_lambda_param.lambda.exp new file mode 100644 index 00000000000000..a720df7124c636 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unused_lambda_param.lambda.exp @@ -0,0 +1,349 @@ +// -- Model dump before env processor pipeline: +module 0xc0ffee::m { + private fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + m::test(0, |x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed1() { + m::test(0, |_x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed2() { + m::test(0, |_: u64| 1); + Tuple() + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor unused checks: +module 0xc0ffee::m { + private fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + m::test(0, |x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed1() { + m::test(0, |_x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed2() { + m::test(0, |_: u64| 1); + Tuple() + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor type parameter check: +module 0xc0ffee::m { + private fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + m::test(0, |x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed1() { + m::test(0, |_x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed2() { + m::test(0, |_: u64| 1); + Tuple() + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor check recursive struct definition: +module 0xc0ffee::m { + private fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + m::test(0, |x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed1() { + m::test(0, |_x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed2() { + m::test(0, |_: u64| 1); + Tuple() + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor check cyclic type instantiation: +module 0xc0ffee::m { + private fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + m::test(0, |x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed1() { + m::test(0, |_x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed2() { + m::test(0, |_: u64| 1); + Tuple() + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor unused struct params check: +module 0xc0ffee::m { + private fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + m::test(0, |x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed1() { + m::test(0, |_x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed2() { + m::test(0, |_: u64| 1); + Tuple() + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor access and use check before inlining: +module 0xc0ffee::m { + private fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + m::test(0, |x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed1() { + m::test(0, |_x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed2() { + m::test(0, |_: u64| 1); + Tuple() + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor inlining: +module 0xc0ffee::m { + private fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + m::test(0, |x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed1() { + m::test(0, |_x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed2() { + m::test(0, |_: u64| 1); + Tuple() + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor access and use check after inlining: +module 0xc0ffee::m { + private fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + m::test(0, |x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed1() { + m::test(0, |_x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed2() { + m::test(0, |_: u64| 1); + Tuple() + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor acquires check: +module 0xc0ffee::m { + private fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + m::test(0, |x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed1() { + m::test(0, |_x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed2() { + m::test(0, |_: u64| 1); + Tuple() + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor simplifier: +module 0xc0ffee::m { + private fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + m::test(0, |x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed1() { + m::test(0, |_x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed2() { + m::test(0, |_: u64| 1); + Tuple() + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor lambda-lifting: +module 0xc0ffee::m { + private fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + m::test(0, closure m::unused_lambda$lambda$1()); + Tuple() + } + private fun unused_lambda_suppressed1() { + m::test(0, closure m::unused_lambda_suppressed1$lambda$1()); + Tuple() + } + private fun unused_lambda_suppressed2() { + m::test(0, closure m::unused_lambda_suppressed2$lambda$1()); + Tuple() + } + private fun unused_lambda$lambda$1(x: u64): u64 { + 1 + } + private fun unused_lambda_suppressed1$lambda$1(_x: u64): u64 { + 1 + } + private fun unused_lambda_suppressed2$lambda$1(param$0: u64): u64 { + { + let _: u64 = param$0; + 1 + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor specification checker: +module 0xc0ffee::m { + private fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + m::test(0, closure m::unused_lambda$lambda$1()); + Tuple() + } + private fun unused_lambda_suppressed1() { + m::test(0, closure m::unused_lambda_suppressed1$lambda$1()); + Tuple() + } + private fun unused_lambda_suppressed2() { + m::test(0, closure m::unused_lambda_suppressed2$lambda$1()); + Tuple() + } + private fun unused_lambda$lambda$1(x: u64): u64 { + 1 + } + private fun unused_lambda_suppressed1$lambda$1(_x: u64): u64 { + 1 + } + private fun unused_lambda_suppressed2$lambda$1(param$0: u64): u64 { + { + let _: u64 = param$0; + 1 + } + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor specification rewriter: +module 0xc0ffee::m { + private fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + m::test(0, closure m::unused_lambda$lambda$1()); + Tuple() + } + private fun unused_lambda_suppressed1() { + m::test(0, closure m::unused_lambda_suppressed1$lambda$1()); + Tuple() + } + private fun unused_lambda_suppressed2() { + m::test(0, closure m::unused_lambda_suppressed2$lambda$1()); + Tuple() + } + private fun unused_lambda$lambda$1(x: u64): u64 { + 1 + } + private fun unused_lambda_suppressed1$lambda$1(_x: u64): u64 { + 1 + } + private fun unused_lambda_suppressed2$lambda$1(param$0: u64): u64 { + { + let _: u64 = param$0; + 1 + } + } +} // end 0xc0ffee::m + + + +Diagnostics: +warning: Unused anonymous function parameter `x`. Consider removing or prefixing with an underscore: `_x` + ┌─ tests/lambda/inline-parity/unused_lambda_param.move:7:18 + │ +7 │ test(0, |x| 1); + │ ^ + + +Diagnostics: +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/inline-parity/unused_lambda_param.move:3:9 + │ +3 │ f(p) + │ ^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/unused_lambda_param.move:7:17 + │ +7 │ test(0, |x| 1); + │ ^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/unused_lambda_param.move:11:17 + │ +11 │ test(0, |_x| 1); + │ ^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/inline-parity/unused_lambda_param.move:15:17 + │ +15 │ test(0, |_| 1); + │ ^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unused_lambda_param.move b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unused_lambda_param.move new file mode 100644 index 00000000000000..809977e0396676 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unused_lambda_param.move @@ -0,0 +1,17 @@ +module 0xc0ffee::m { + fun test(p: u64, f: |u64| u64): u64 { + f(p) + } + + fun unused_lambda() { + test(0, |x| 1); + } + + fun unused_lambda_suppressed1() { + test(0, |_x| 1); + } + + fun unused_lambda_suppressed2() { + test(0, |_| 1); + } +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/lambda.exp new file mode 100644 index 00000000000000..4f17028adb675c --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/lambda.exp @@ -0,0 +1,58 @@ + +Diagnostics: +error: `reduce` is a function and not a macro + ┌─ tests/lambda/lambda.move:34:37 + │ +34 │ foreach(&v, |e| sum = sum + reduce!(*e, 0, |t, r| t + r)); + │ ^^^^^^ + +error: expected `|(&T, u64)|_` but found a value of type `|&T|` + ┌─ tests/lambda/lambda.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/lambda/lambda.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/lambda/lambda.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/lambda/lambda.move:61:9 + │ +61 │ x(1) // expected to be not a function + │ ^^^^ + +error: reference type `&integer` is not allowed as a type argument (type was inferred) + ┌─ tests/lambda/lambda.move:67:35 + │ +67 │ foreach(&v, |e| sum = sum + e) // expected to cannot infer type + │ ^ + │ + = required by instantiating type parameter `T` of function `+` + +error: tuple type `()` is not allowed as a type argument (type was inferred) + ┌─ tests/lambda/lambda.move:73:37 + │ + 4 │ public inline fun foreach(v: &vector, action: |&T|) { // expected to be not implemented + │ - declaration of type parameter `T` + · +73 │ foreach(&v, |e| { sum = sum + *e; *e }) // expected to have wrong result type of lambda + │ ^ + │ + = required by instantiating type parameter `T` of function `foreach` + +error: function type `|u64|u64` is not allowed as a field type + ┌─ tests/lambda/lambda.move:81:12 + │ +81 │ f: |u64|u64, // expected lambda not allowed + │ ^^^^^^^^ + │ + = required by declaration of field `f` diff --git a/third_party/move/move-compiler-v2/tests/lambda/lambda.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/lambda.lambda.exp new file mode 100644 index 00000000000000..4f17028adb675c --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/lambda.lambda.exp @@ -0,0 +1,58 @@ + +Diagnostics: +error: `reduce` is a function and not a macro + ┌─ tests/lambda/lambda.move:34:37 + │ +34 │ foreach(&v, |e| sum = sum + reduce!(*e, 0, |t, r| t + r)); + │ ^^^^^^ + +error: expected `|(&T, u64)|_` but found a value of type `|&T|` + ┌─ tests/lambda/lambda.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/lambda/lambda.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/lambda/lambda.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/lambda/lambda.move:61:9 + │ +61 │ x(1) // expected to be not a function + │ ^^^^ + +error: reference type `&integer` is not allowed as a type argument (type was inferred) + ┌─ tests/lambda/lambda.move:67:35 + │ +67 │ foreach(&v, |e| sum = sum + e) // expected to cannot infer type + │ ^ + │ + = required by instantiating type parameter `T` of function `+` + +error: tuple type `()` is not allowed as a type argument (type was inferred) + ┌─ tests/lambda/lambda.move:73:37 + │ + 4 │ public inline fun foreach(v: &vector, action: |&T|) { // expected to be not implemented + │ - declaration of type parameter `T` + · +73 │ foreach(&v, |e| { sum = sum + *e; *e }) // expected to have wrong result type of lambda + │ ^ + │ + = required by instantiating type parameter `T` of function `foreach` + +error: function type `|u64|u64` is not allowed as a field type + ┌─ tests/lambda/lambda.move:81:12 + │ +81 │ f: |u64|u64, // expected lambda not allowed + │ ^^^^^^^^ + │ + = required by declaration of field `f` diff --git a/third_party/move/move-compiler-v2/tests/lambda/lambda.move b/third_party/move/move-compiler-v2/tests/lambda/lambda.move new file mode 100644 index 00000000000000..c5e29275c3d286 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/lambda.move @@ -0,0 +1,100 @@ +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| sum = sum + *e) // expected to be not implemented + } + + public fun correct_reduce(): u64 { + let v = vector[1, 2, 3]; + reduce(v, 0, |t, r| t + r) + } + + public fun corrected_nested() { + let v = vector[vector[1,2], vector[3]]; + let sum = 0; + foreach(&v, |e| sum = sum + reduce!(*e, 0, |t, r| 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| 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| { sum = sum + *e; *e }) // expected to have wrong result type of lambda + } + + public fun lambda_not_allowed() { + let _x = |i| 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) + } + +} + +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/lambda/lambda3.exp b/third_party/move/move-compiler-v2/tests/lambda/lambda3.exp new file mode 100644 index 00000000000000..713c31a5edf363 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/lambda3.exp @@ -0,0 +1,17 @@ +// -- Model dump before bytecode pipeline +module 0x8675309::M { + public fun lambda_not_allowed() { + { + let _x: |u64|u64 = |i: u64| Add(i, 1); + Tuple() + } + } +} // end 0x8675309::M + + +Diagnostics: +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/lambda3.move:77:18 + │ +77 │ let _x = |i| i + 1; // expected lambda not allowed + │ ^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/lambda3.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/lambda3.lambda.exp new file mode 100644 index 00000000000000..db9ce1b64dc587 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/lambda3.lambda.exp @@ -0,0 +1,170 @@ +// -- Model dump before env processor pipeline: +module 0x8675309::M { + public fun lambda_not_allowed() { + { + let _x: |u64|u64 = |i: u64| Add(i, 1); + Tuple() + } + } +} // end 0x8675309::M + + +// -- Model dump after env processor unused checks: +module 0x8675309::M { + public fun lambda_not_allowed() { + { + let _x: |u64|u64 = |i: u64| Add(i, 1); + Tuple() + } + } +} // end 0x8675309::M + + +// -- Model dump after env processor type parameter check: +module 0x8675309::M { + public fun lambda_not_allowed() { + { + let _x: |u64|u64 = |i: u64| Add(i, 1); + Tuple() + } + } +} // end 0x8675309::M + + +// -- Model dump after env processor check recursive struct definition: +module 0x8675309::M { + public fun lambda_not_allowed() { + { + let _x: |u64|u64 = |i: u64| Add(i, 1); + Tuple() + } + } +} // end 0x8675309::M + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x8675309::M { + public fun lambda_not_allowed() { + { + let _x: |u64|u64 = |i: u64| Add(i, 1); + Tuple() + } + } +} // end 0x8675309::M + + +// -- Model dump after env processor unused struct params check: +module 0x8675309::M { + public fun lambda_not_allowed() { + { + let _x: |u64|u64 = |i: u64| Add(i, 1); + Tuple() + } + } +} // end 0x8675309::M + + +// -- Model dump after env processor access and use check before inlining: +module 0x8675309::M { + public fun lambda_not_allowed() { + { + let _x: |u64|u64 = |i: u64| Add(i, 1); + Tuple() + } + } +} // end 0x8675309::M + + +// -- Model dump after env processor inlining: +module 0x8675309::M { + public fun lambda_not_allowed() { + { + let _x: |u64|u64 = |i: u64| Add(i, 1); + Tuple() + } + } +} // end 0x8675309::M + + +// -- Model dump after env processor access and use check after inlining: +module 0x8675309::M { + public fun lambda_not_allowed() { + { + let _x: |u64|u64 = |i: u64| Add(i, 1); + Tuple() + } + } +} // end 0x8675309::M + + +// -- Model dump after env processor acquires check: +module 0x8675309::M { + public fun lambda_not_allowed() { + { + let _x: |u64|u64 = |i: u64| Add(i, 1); + Tuple() + } + } +} // end 0x8675309::M + + +// -- Model dump after env processor simplifier: +module 0x8675309::M { + public fun lambda_not_allowed() { + { + let _x: |u64|u64 = |i: u64| Add(i, 1); + Tuple() + } + } +} // end 0x8675309::M + + +// -- Model dump after env processor lambda-lifting: +module 0x8675309::M { + public fun lambda_not_allowed() { + { + let _x: |u64|u64 = closure M::lambda_not_allowed$lambda$1(); + Tuple() + } + } + private fun lambda_not_allowed$lambda$1(i: u64): u64 { + Add(i, 1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor specification checker: +module 0x8675309::M { + public fun lambda_not_allowed() { + { + let _x: |u64|u64 = closure M::lambda_not_allowed$lambda$1(); + Tuple() + } + } + private fun lambda_not_allowed$lambda$1(i: u64): u64 { + Add(i, 1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor specification rewriter: +module 0x8675309::M { + public fun lambda_not_allowed() { + { + let _x: |u64|u64 = closure M::lambda_not_allowed$lambda$1(); + Tuple() + } + } + private fun lambda_not_allowed$lambda$1(i: u64): u64 { + Add(i, 1) + } +} // end 0x8675309::M + + + +Diagnostics: +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/lambda3.move:77:18 + │ +77 │ let _x = |i| i + 1; // expected lambda not allowed + │ ^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/lambda3.move b/third_party/move/move-compiler-v2/tests/lambda/lambda3.move new file mode 100644 index 00000000000000..5450bac87c1cb7 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/lambda3.move @@ -0,0 +1,99 @@ +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| sum = sum + *e) // expected to be not implemented + // } + + // public fun correct_reduce(): u64 { + // let v = vector[1, 2, 3]; + // reduce(v, 0, |t, r| t + r) + // } + + // public fun corrected_nested() { + // let v = vector[vector[1,2], vector[3]]; + // let sum = 0; + // foreach(&v, |e| sum = sum + reduce!(*e, 0, |t, r| 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| 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| { sum = sum + *e; *e }) // expected to have wrong result type of lambda + // } + + public fun lambda_not_allowed() { + let _x = |i| 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) + // } +} + +// 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/lambda/lambda4.exp b/third_party/move/move-compiler-v2/tests/lambda/lambda4.exp new file mode 100644 index 00000000000000..036d26b980df04 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/lambda4.exp @@ -0,0 +1,13 @@ + +Diagnostics: +error: Functions may not return function-typed values, but function `M::macro_result_lambda_not_allowed` return type is the function type `|u64|`: + ┌─ tests/lambda/lambda4.move:86:58 + │ +86 │ public inline fun macro_result_lambda_not_allowed(): |u64| { // expected lambda not allowed + │ ^^^^^ + +error: Functions may not return function-typed values, but function `M::fun_result_lambda_not_allowed` return type is the function type `|u64|`: + ┌─ tests/lambda/lambda4.move:89:49 + │ +89 │ public fun fun_result_lambda_not_allowed(): |u64| { // expected lambda not allowed + │ ^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/lambda4.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/lambda4.lambda.exp new file mode 100644 index 00000000000000..f374630d851fbb --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/lambda4.lambda.exp @@ -0,0 +1,184 @@ +// -- Model dump before env processor pipeline: +module 0x8675309::M { + public fun fun_result_lambda_not_allowed(): |u64| { + Abort(1) + } + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor unused checks: +module 0x8675309::M { + public fun fun_result_lambda_not_allowed(): |u64| { + Abort(1) + } + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor type parameter check: +module 0x8675309::M { + public fun fun_result_lambda_not_allowed(): |u64| { + Abort(1) + } + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor check recursive struct definition: +module 0x8675309::M { + public fun fun_result_lambda_not_allowed(): |u64| { + Abort(1) + } + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x8675309::M { + public fun fun_result_lambda_not_allowed(): |u64| { + Abort(1) + } + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor unused struct params check: +module 0x8675309::M { + public fun fun_result_lambda_not_allowed(): |u64| { + Abort(1) + } + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor access and use check before inlining: +module 0x8675309::M { + public fun fun_result_lambda_not_allowed(): |u64| { + Abort(1) + } + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor inlining: +module 0x8675309::M { + public fun fun_result_lambda_not_allowed(): |u64| { + Abort(1) + } + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor access and use check after inlining: +module 0x8675309::M { + public fun fun_result_lambda_not_allowed(): |u64| { + Abort(1) + } + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor acquires check: +module 0x8675309::M { + public fun fun_result_lambda_not_allowed(): |u64| { + Abort(1) + } + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor simplifier: +module 0x8675309::M { + public fun fun_result_lambda_not_allowed(): |u64| { + Abort(1) + } + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor lambda-lifting: +module 0x8675309::M { + public fun fun_result_lambda_not_allowed(): |u64| { + Abort(1) + } + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor specification checker: +module 0x8675309::M { + public fun fun_result_lambda_not_allowed(): |u64| { + Abort(1) + } + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor specification rewriter: +module 0x8675309::M { + public fun fun_result_lambda_not_allowed(): |u64| { + Abort(1) + } + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +============ initial bytecode ================ + +[variant baseline] +public fun M::fun_result_lambda_not_allowed(): |u64| { + var $t0: |u64| + var $t1: u64 + 0: $t1 := 1 + 1: abort($t1) + 2: return $t0 +} + +============ after LiveVarAnalysisProcessor: ================ + +[variant baseline] +public fun M::fun_result_lambda_not_allowed(): |u64| { + var $t0: |u64| [unused] + var $t1: u64 + # live vars: + 0: $t1 := 1 + # live vars: $t1 + 1: abort($t1) +} + + +Diagnostics: +error: Unexpected type: |u64| + ┌─ tests/lambda/lambda4.move:89:16 + │ +89 │ public fun fun_result_lambda_not_allowed(): |u64| { // expected lambda not allowed + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/lambda4.move b/third_party/move/move-compiler-v2/tests/lambda/lambda4.move new file mode 100644 index 00000000000000..4a378b7e14b10f --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/lambda4.move @@ -0,0 +1,99 @@ +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| sum = sum + *e) // expected to be not implemented + // } + + // public fun correct_reduce(): u64 { + // let v = vector[1, 2, 3]; + // reduce(v, 0, |t, r| t + r) + // } + + // public fun corrected_nested() { + // let v = vector[vector[1,2], vector[3]]; + // let sum = 0; + // foreach(&v, |e| sum = sum + reduce!(*e, 0, |t, r| 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| 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| { sum = sum + *e; *e }) // expected to have wrong result type of lambda + // } + + // public fun lambda_not_allowed() { + // let _x = |i| 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) + } +} + +// 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/lambda/lambda5.exp b/third_party/move/move-compiler-v2/tests/lambda/lambda5.exp new file mode 100644 index 00000000000000..be6344f6fcbec3 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/lambda5.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Functions may not return function-typed values, but function `M::macro_result_lambda_not_allowed` return type is the function type `|u64|`: + ┌─ tests/lambda/lambda5.move:86:58 + │ +86 │ public inline fun macro_result_lambda_not_allowed(): |u64| { // expected lambda not allowed + │ ^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/lambda5.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/lambda5.lambda.exp new file mode 100644 index 00000000000000..e1b739ddf27480 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/lambda5.lambda.exp @@ -0,0 +1,123 @@ +// -- Model dump before env processor pipeline: +module 0x8675309::M { + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor unused checks: +module 0x8675309::M { + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor type parameter check: +module 0x8675309::M { + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor check recursive struct definition: +module 0x8675309::M { + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x8675309::M { + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor unused struct params check: +module 0x8675309::M { + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor access and use check before inlining: +module 0x8675309::M { + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor inlining: +module 0x8675309::M { + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor access and use check after inlining: +module 0x8675309::M { + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor acquires check: +module 0x8675309::M { + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor simplifier: +module 0x8675309::M { + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor lambda-lifting: +module 0x8675309::M { + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor specification checker: +module 0x8675309::M { + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +// -- Model dump after env processor specification rewriter: +module 0x8675309::M { + public inline fun macro_result_lambda_not_allowed(): |u64| { + Abort(1) + } +} // end 0x8675309::M + + +============ initial bytecode ================ +============ after LiveVarAnalysisProcessor: ================ + +============ disassembled file-format ================== +// Move bytecode v7 +module 8675309.M { + + + +} +============ bytecode verification succeeded ======== diff --git a/third_party/move/move-compiler-v2/tests/lambda/lambda5.move b/third_party/move/move-compiler-v2/tests/lambda/lambda5.move new file mode 100644 index 00000000000000..291c8e5cab61f9 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/lambda5.move @@ -0,0 +1,99 @@ +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| sum = sum + *e) // expected to be not implemented + // } + + // public fun correct_reduce(): u64 { + // let v = vector[1, 2, 3]; + // reduce(v, 0, |t, r| t + r) + // } + + // public fun corrected_nested() { + // let v = vector[vector[1,2], vector[3]]; + // let sum = 0; + // foreach(&v, |e| sum = sum + reduce!(*e, 0, |t, r| 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| 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| { sum = sum + *e; *e }) // expected to have wrong result type of lambda + // } + + // public fun lambda_not_allowed() { + // let _x = |i| 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) + // } +} + +// 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/lambda/non_lambda_arg.exp b/third_party/move/move-compiler-v2/tests/lambda/non_lambda_arg.exp new file mode 100644 index 00000000000000..3de94a286d4a09 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/non_lambda_arg.exp @@ -0,0 +1,13 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `sort::incorrect_sort` has a function parameter: + ┌─ tests/lambda/non_lambda_arg.move:4:16 + │ +4 │ public fun incorrect_sort(arr: &mut vector, a_less_b: |T, T| bool) { + │ ^^^^^^^^^^^^^^ -------- Parameter `a_less_b` has function-valued type `|(T, T)|bool`. + +error: Only inline functions may have function-typed parameters, but non-inline function `sort::incorrect_sort_recursive` has a function parameter: + ┌─ tests/lambda/non_lambda_arg.move:9:16 + │ +9 │ public fun incorrect_sort_recursive(arr: &mut vector, low: u64, high: u64, a_less_b: |T, T| bool) { + │ ^^^^^^^^^^^^^^^^^^^^^^^^ -------- Parameter `a_less_b` has function-valued type `|(T, T)|bool`. diff --git a/third_party/move/move-compiler-v2/tests/lambda/non_lambda_arg.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/non_lambda_arg.lambda.exp new file mode 100644 index 00000000000000..cb2548014062c8 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/non_lambda_arg.lambda.exp @@ -0,0 +1,416 @@ +// -- Model dump before env processor pipeline: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor unused checks: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor type parameter check: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor unused struct params check: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor inlining: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor acquires check: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor simplifier: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor lambda-lifting: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor specification checker: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +// -- Model dump after env processor specification rewriter: +module 0x42::sort { + use std::vector; + public fun incorrect_sort(arr: &mut vector<#0>,a_less_b: |(#0, #0)|bool) { + { + let n: u64 = vector::length(Freeze(false)(arr)); + sort::incorrect_sort_recursive(arr, 0, Sub(n, 1), a_less_b) + } + } + public fun incorrect_sort_recursive(arr: &mut vector<#0>,low: u64,high: u64,a_less_b: |(#0, #0)|bool) { + if Lt(low, high) { + { + let pi: u64 = Add(low, Div(high, 2)); + sort::incorrect_sort_recursive(arr, low, Sub(pi, 1), a_less_b); + sort::incorrect_sort_recursive(arr, Add(pi, 1), high, a_less_b); + Tuple() + } + } else { + Tuple() + }; + Tuple() + } +} // end 0x42::sort + + +============ initial bytecode ================ + +[variant baseline] +public fun sort::incorrect_sort<#0>($t0: &mut vector<#0>, $t1: |(#0, #0)|bool) { + var $t2: u64 + var $t3: &vector<#0> + var $t4: u64 + var $t5: u64 + var $t6: u64 + 0: $t3 := freeze_ref(implicit)($t0) + 1: $t2 := vector::length<#0>($t3) + 2: $t4 := 0 + 3: $t6 := 1 + 4: $t5 := -($t2, $t6) + 5: sort::incorrect_sort_recursive<#0>($t0, $t4, $t5, $t1) + 6: return () +} + + +[variant baseline] +public fun sort::incorrect_sort_recursive<#0>($t0: &mut vector<#0>, $t1: u64, $t2: u64, $t3: |(#0, #0)|bool) { + var $t4: bool + var $t5: u64 + var $t6: u64 + var $t7: u64 + var $t8: u64 + var $t9: u64 + var $t10: u64 + var $t11: u64 + 0: $t4 := <($t1, $t2) + 1: if ($t4) goto 2 else goto 13 + 2: label L0 + 3: $t7 := 2 + 4: $t6 := /($t2, $t7) + 5: $t5 := +($t1, $t6) + 6: $t9 := 1 + 7: $t8 := -($t5, $t9) + 8: sort::incorrect_sort_recursive<#0>($t0, $t1, $t8, $t3) + 9: $t11 := 1 + 10: $t10 := +($t5, $t11) + 11: sort::incorrect_sort_recursive<#0>($t0, $t10, $t2, $t3) + 12: goto 14 + 13: label L1 + 14: label L2 + 15: return () +} + + +Diagnostics: +error: local `a_less_b` of type `|(T, T)|bool` does not have the `copy` ability + ┌─ tests/lambda/non_lambda_arg.move:12:13 + │ +12 │ incorrect_sort_recursive(arr, low, pi - 1, a_less_b); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ copy needed here because value is still in use +13 │ incorrect_sort_recursive(arr, pi + 1, high, a_less_b); + │ ----------------------------------------------------- used here + +error: local `a_less_b` of type `|(T, T)|bool` does not have the `drop` ability + ┌─ tests/lambda/non_lambda_arg.move:10:9 + │ +10 │ ╭ if (low < high) { +11 │ │ let pi = low + high / 2; +12 │ │ incorrect_sort_recursive(arr, low, pi - 1, a_less_b); +13 │ │ incorrect_sort_recursive(arr, pi + 1, high, a_less_b); +14 │ │ }; + │ ╰─────────^ implicitly dropped here since it is no longer used diff --git a/third_party/move/move-compiler-v2/tests/lambda/non_lambda_arg.move b/third_party/move/move-compiler-v2/tests/lambda/non_lambda_arg.move new file mode 100644 index 00000000000000..83e9d4027661da --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/non_lambda_arg.move @@ -0,0 +1,17 @@ +module 0x42::sort { + use std::vector; + + public fun incorrect_sort(arr: &mut vector, a_less_b: |T, T| bool) { + let n = vector::length(arr); + incorrect_sort_recursive(arr, 0, n - 1, a_less_b) + } + + public fun incorrect_sort_recursive(arr: &mut vector, low: u64, high: u64, a_less_b: |T, T| bool) { + if (low < high) { + let pi = low + high / 2; + incorrect_sort_recursive(arr, low, pi - 1, a_less_b); + incorrect_sort_recursive(arr, pi + 1, high, a_less_b); + }; + } + +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/registry.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/registry.exp new file mode 100644 index 00000000000000..a196cfcde9c4c8 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/registry.exp @@ -0,0 +1,9 @@ + +Diagnostics: +error: unexpected token + ┌─ tests/lambda/storable/registry.move:7:22 + │ +6 │ struct Function { + │ - To match this '{' +7 │ f: |u64| u64 has store, + │ ^ Expected '}' diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/registry.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/registry.lambda.exp new file mode 100644 index 00000000000000..a196cfcde9c4c8 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/registry.lambda.exp @@ -0,0 +1,9 @@ + +Diagnostics: +error: unexpected token + ┌─ tests/lambda/storable/registry.move:7:22 + │ +6 │ struct Function { + │ - To match this '{' +7 │ f: |u64| u64 has store, + │ ^ Expected '}' diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/registry.move b/third_party/move/move-compiler-v2/tests/lambda/storable/registry.move new file mode 100644 index 00000000000000..a6fd8bfab655c6 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/registry.move @@ -0,0 +1,109 @@ +module 0x42::test { + struct Registry { + functions: vector + } + + struct Function { + f: |u64| u64 has store, + key: u64 + } + + enum Option { + None(), + Some(T) + }; + + fun get_function(v: &vector, k: u64): Option { + mut x = Option::None; + for_each_ref(v, |f: &Function| { + if f.key == k { + x = f.f + } + }); + x + } + + fun replace_or_add_function(v: &mut vector, k: u64, f: |u64| u64 has store): Option { + mut done = false; + for_each_mut(v, |f: &mut Function| { + if f.key == k { + f.f = f; + done = true; + } + }); + if !done { + let new_record = Function { f: f, key: k }; + v.append(new_record); + } + } + + fun register(owner: &signer, f: |u64| u64 has store, k: u64) acquires Registry { + let addr = owner.address; + if !exists(addr) { + let new_registry = Registry { + functions: vector[] + }; + move_to(owner, registry); + } + let registry = borrow_global_mut(addr); + replace_or_add_function(&mut registry.functions, k, f); + } + + fun invoke(addr: address, k: u64, x: u64): Option acquires Registry { + if !exists(addr) { + return Option::None + } + let registry = borrow_global(addr); + match get_function(registry.functions, k) { + Some(func) => { + let Function { f: f, key: key } = &func; + Some(f(x)) + }, + _ => { + Option::None + } + } + } + + fun double(x: u64):u64 { + x * 2 + } + + fun triple(x: u64):u64 { + x * 3 + } + + public fun multiply(x: u64, y: u64): u64 { + x * y + } + + fun multiply_by_x(x: u64): |u64|u64 has store { + curry(&multiply, x) + } + + + #[test(a = @0x42)] + test_registry1(a; signer) { + register(a, &double, 2); + register(a, &negate, 3); + register(a, multiply_by_x(4), 4); + register(a, multiply_by_x(5), 5); + + match invoke(a, 2, 10) { + Some(x) => { assert!(x == 20); } + _ => assert!(false); + } + match invoke(a, 3, 11) { + Some(x) => { assert!(x == 33); } + _ => assert!(false); + } + match invoke(a, 4, 2) { + Some(x) => { assert!(x == 8); } + _ => assert!(false); + } + match invoke(a, 5, 3) { + Some(x) => { assert!(x == 15); } + _ => assert!(false); + } + } +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.exp new file mode 100644 index 00000000000000..38e1020313014e --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.exp @@ -0,0 +1,10 @@ + +Diagnostics: +error: unexpected token + ┌─ tests/lambda/storable/return_func.move:14:41 + │ +14 │ fun multiply_by_x(x: u64): |u64|u64 has store { + │ ^^^ + │ │ + │ Unexpected 'has' + │ Expected '{' diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.lambda.exp new file mode 100644 index 00000000000000..38e1020313014e --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.lambda.exp @@ -0,0 +1,10 @@ + +Diagnostics: +error: unexpected token + ┌─ tests/lambda/storable/return_func.move:14:41 + │ +14 │ fun multiply_by_x(x: u64): |u64|u64 has store { + │ ^^^ + │ │ + │ Unexpected 'has' + │ Expected '{' diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.move b/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.move new file mode 100644 index 00000000000000..4f6e078d8a460b --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.move @@ -0,0 +1,79 @@ +module 0x42::test { + fun double(x: u64): u64 { + x * 2 + } + + fun triple(x: u64) : u64 { + x * 3 + } + + public fun multiply(x: u64, y: u64): u64 { + x * y + } + + fun multiply_by_x(x: u64): |u64|u64 has store { + curry(&multiply, x) + } + + fun choose_function(key: u64) : |u64|u64 has store { + if key == 0 { + &double + } else if key == 1 { + &triple + } else { + multiply_by_x(4) + } + } + + fun choose_function2(key: u64) : |u64|u64 has store { + if key == 0 { + |x| double(x); + } else if key == 1 { + |x| triple(x); + } else { + |x| multiply_by_x(4)(x) + } + } + + fun choose_function3(key: u64) : |u64|u64 has store { + if key == 0 { + let f = |x| double(x); + f + } else if key == 1 { + let g = |x| triple(x); + g + } else { + let h = multiply_by_x(4); + h + } + } + + public fun test_functions(choose_function: |u64|(|u64|u64 has store)) { + let sum = vector[]; + let x = 3; + sum.push_back(choose_function(0)(x)); + sum.push_back(choose_function(1)(x)); + sum.push_back(choose_function(2)(x)); + + let g = choose_function(1)(x); + let h = choose_function(2)(x); + let f = choose_function(0)(x); + + sum.push_back(f(5)); + sum.push_back(g(7)); + sum.push_back(h(6)); + + let funcs = vector[choose_function(0), choose_function(1), choose_function(2)]; + sum.push_back(f[0](9)); + sum.push_back(f[1](11)); + sum.push_back(f[2](13)); + + assert!(vector[6, 9, 12, 10, 21, 24, 18, 33, 52]) + } + + public fun test_function_choosers() { + test_functions(&choose_function); + test_functions(&choose_function2); + test_functions(&choose_function3); + } +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/unused_lambda_param.exp b/third_party/move/move-compiler-v2/tests/lambda/unused_lambda_param.exp new file mode 100644 index 00000000000000..8896be5127f9c9 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/unused_lambda_param.exp @@ -0,0 +1,29 @@ + +Diagnostics: +warning: Unused anonymous function parameter `x`. Consider removing or prefixing with an underscore: `_x` + ┌─ tests/lambda/unused_lambda_param.move:7:18 + │ +7 │ test(0, |x| 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 + + +============ bytecode verification succeeded ======== diff --git a/third_party/move/move-compiler-v2/tests/lambda/unused_lambda_param.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/unused_lambda_param.lambda.exp new file mode 100644 index 00000000000000..b406b29e1df3d0 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/unused_lambda_param.lambda.exp @@ -0,0 +1,412 @@ +// -- Model dump before env processor pipeline: +module 0xc0ffee::m { + private inline fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + m::test(0, |x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed1() { + m::test(0, |_x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed2() { + m::test(0, |_: u64| 1); + Tuple() + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor unused checks: +module 0xc0ffee::m { + private inline fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + m::test(0, |x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed1() { + m::test(0, |_x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed2() { + m::test(0, |_: u64| 1); + Tuple() + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor type parameter check: +module 0xc0ffee::m { + private inline fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + m::test(0, |x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed1() { + m::test(0, |_x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed2() { + m::test(0, |_: u64| 1); + Tuple() + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor check recursive struct definition: +module 0xc0ffee::m { + private inline fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + m::test(0, |x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed1() { + m::test(0, |_x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed2() { + m::test(0, |_: u64| 1); + Tuple() + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor check cyclic type instantiation: +module 0xc0ffee::m { + private inline fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + m::test(0, |x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed1() { + m::test(0, |_x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed2() { + m::test(0, |_: u64| 1); + Tuple() + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor unused struct params check: +module 0xc0ffee::m { + private inline fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + m::test(0, |x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed1() { + m::test(0, |_x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed2() { + m::test(0, |_: u64| 1); + Tuple() + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor access and use check before inlining: +module 0xc0ffee::m { + private inline fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + m::test(0, |x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed1() { + m::test(0, |_x: u64| 1); + Tuple() + } + private fun unused_lambda_suppressed2() { + m::test(0, |_: u64| 1); + Tuple() + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor inlining: +module 0xc0ffee::m { + private inline fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + { + let (p: u64): (u64) = Tuple(0); + { + let (x: u64): (u64) = Tuple(p); + 1 + } + }; + Tuple() + } + private fun unused_lambda_suppressed1() { + { + let (p: u64): (u64) = Tuple(0); + { + let (_x: u64): (u64) = Tuple(p); + 1 + } + }; + Tuple() + } + private fun unused_lambda_suppressed2() { + { + let (p: u64): (u64) = Tuple(0); + { + let (_: u64): (u64) = Tuple(p); + 1 + } + }; + Tuple() + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor access and use check after inlining: +module 0xc0ffee::m { + private inline fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + { + let (p: u64): (u64) = Tuple(0); + { + let (x: u64): (u64) = Tuple(p); + 1 + } + }; + Tuple() + } + private fun unused_lambda_suppressed1() { + { + let (p: u64): (u64) = Tuple(0); + { + let (_x: u64): (u64) = Tuple(p); + 1 + } + }; + Tuple() + } + private fun unused_lambda_suppressed2() { + { + let (p: u64): (u64) = Tuple(0); + { + let (_: u64): (u64) = Tuple(p); + 1 + } + }; + Tuple() + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor acquires check: +module 0xc0ffee::m { + private inline fun test(p: u64,f: |u64|u64): u64 { + (f)(p) + } + private fun unused_lambda() { + { + let (p: u64): (u64) = Tuple(0); + { + let (x: u64): (u64) = Tuple(p); + 1 + } + }; + Tuple() + } + private fun unused_lambda_suppressed1() { + { + let (p: u64): (u64) = Tuple(0); + { + let (_x: u64): (u64) = Tuple(p); + 1 + } + }; + Tuple() + } + private fun unused_lambda_suppressed2() { + { + let (p: u64): (u64) = Tuple(0); + { + let (_: u64): (u64) = Tuple(p); + 1 + } + }; + Tuple() + } +} // end 0xc0ffee::m + + +// -- Model dump after env processor simplifier: +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 + + +// -- Model dump after env processor lambda-lifting: +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 + + +// -- Model dump after env processor specification checker: +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 + + +// -- Model dump after env processor specification rewriter: +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 + + + +Diagnostics: +warning: Unused anonymous function parameter `x`. Consider removing or prefixing with an underscore: `_x` + ┌─ tests/lambda/unused_lambda_param.move:7:18 + │ +7 │ test(0, |x| 1); + │ ^ + +============ initial bytecode ================ + +[variant baseline] +fun m::unused_lambda() { + var $t0: u64 + 0: $t0 := 1 + 1: return () +} + + +[variant baseline] +fun m::unused_lambda_suppressed1() { + var $t0: u64 + 0: $t0 := 1 + 1: return () +} + + +[variant baseline] +fun m::unused_lambda_suppressed2() { + var $t0: u64 + 0: $t0 := 1 + 1: return () +} + +============ after LiveVarAnalysisProcessor: ================ + +[variant baseline] +fun m::unused_lambda() { + var $t0: u64 [unused] + # live vars: + 0: return () +} + + +[variant baseline] +fun m::unused_lambda_suppressed1() { + var $t0: u64 [unused] + # live vars: + 0: return () +} + + +[variant baseline] +fun m::unused_lambda_suppressed2() { + var $t0: u64 [unused] + # live vars: + 0: return () +} + + +============ disassembled file-format ================== +// Move bytecode v7 +module c0ffee.m { + + +unused_lambda() /* def_idx: 0 */ { +B0: + 0: Ret +} +unused_lambda_suppressed1() /* def_idx: 1 */ { +B0: + 0: Ret +} +unused_lambda_suppressed2() /* def_idx: 2 */ { +B0: + 0: Ret +} +} +============ bytecode verification succeeded ======== diff --git a/third_party/move/move-compiler-v2/tests/lambda/unused_lambda_param.move b/third_party/move/move-compiler-v2/tests/lambda/unused_lambda_param.move new file mode 100644 index 00000000000000..17079c81ec0756 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/unused_lambda_param.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| 1); + } + + fun unused_lambda_suppressed1() { + test(0, |_x| 1); + } + + fun unused_lambda_suppressed2() { + test(0, |_| 1); + } +} diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression.move b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression.move index 8451f7c0455f90..45f36aeb03b0f1 100644 --- a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression.move +++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression.move @@ -1,4 +1,4 @@ -module M { +module 0x123::M { fun foo() { (if (true) 5 else 0)(); (while (false) {})(0, 1); diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression2.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression2.exp new file mode 100644 index 00000000000000..03ed8ceb2af6fc --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression2.exp @@ -0,0 +1,10 @@ + +Diagnostics: +error: unexpected token + ┌─ tests/more-v1/parser/invalid_call_lhs_complex_expression2.move:3:29 + │ +3 │ (if (true) 5 else 0)(); + │ ^ + │ │ + │ Unexpected '(' + │ Expected ';' diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression2.move b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression2.move new file mode 100644 index 00000000000000..45f36aeb03b0f1 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression2.move @@ -0,0 +1,6 @@ +module 0x123::M { + fun foo() { + (if (true) 5 else 0)(); + (while (false) {})(0, 1); + } +} diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name.move b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name.move index ec2118f3a371bc..4296a1ea71ce22 100644 --- a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name.move +++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name.move @@ -1,4 +1,4 @@ -module M { +module 0x123::M { fun foo() { (foo)() } diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name2.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name2.exp new file mode 100644 index 00000000000000..f47f13fe5ecb66 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name2.exp @@ -0,0 +1,10 @@ + +Diagnostics: +error: unexpected token + ┌─ tests/more-v1/parser/invalid_call_lhs_parens_around_name2.move:3:14 + │ +3 │ (foo)() + │ ^ + │ │ + │ Unexpected '(' + │ Expected ';' diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name2.move b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name2.move new file mode 100644 index 00000000000000..4296a1ea71ce22 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name2.move @@ -0,0 +1,5 @@ +module 0x123::M { + fun foo() { + (foo)() + } +} diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return.move b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return.move index c82b6fae4edcb9..fe0d45e7135856 100644 --- a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return.move +++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return.move @@ -1,4 +1,4 @@ -module M { +module 0x123::M { fun foo() { (return ())(0, 1); } diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return2.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return2.exp new file mode 100644 index 00000000000000..b9972c50113c3f --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return2.exp @@ -0,0 +1,10 @@ + +Diagnostics: +error: unexpected token + ┌─ tests/more-v1/parser/invalid_call_lhs_return2.move:3:20 + │ +3 │ (return ())(0, 1); + │ ^ + │ │ + │ Unexpected '(' + │ Expected ';' diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return2.move b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return2.move new file mode 100644 index 00000000000000..fe0d45e7135856 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return2.move @@ -0,0 +1,5 @@ +module 0x123::M { + fun foo() { + (return ())(0, 1); + } +} diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value.move b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value.move index d952ee68335a1d..d5ce3bdae42ba2 100644 --- a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value.move +++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value.move @@ -1,4 +1,4 @@ -module M { +module 0x123::M { fun foo() { 5(); 5(0, 1); diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value2.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value2.exp new file mode 100644 index 00000000000000..e2f3d92b38d92e --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value2.exp @@ -0,0 +1,10 @@ + +Diagnostics: +error: unexpected token + ┌─ tests/more-v1/parser/invalid_call_lhs_value2.move:3:10 + │ +3 │ 5(); + │ ^ + │ │ + │ Unexpected '(' + │ Expected ';' diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value2.move b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value2.move new file mode 100644 index 00000000000000..d5ce3bdae42ba2 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value2.move @@ -0,0 +1,6 @@ +module 0x123::M { + fun foo() { + 5(); + 5(0, 1); + } +} diff --git a/third_party/move/move-compiler-v2/tests/testsuite.rs b/third_party/move/move-compiler-v2/tests/testsuite.rs index a45dba8141a87b..c02e29e570b207 100644 --- a/third_party/move/move-compiler-v2/tests/testsuite.rs +++ b/third_party/move/move-compiler-v2/tests/testsuite.rs @@ -160,23 +160,24 @@ const TEST_CONFIGS: Lazy> = Lazy::new(|| { dump_bytecode: DumpLevel::None, dump_bytecode_filter: None, }, - // Tests for lambda lifting + // Tests for lambda lifting and lambdas -- with full lambda support TestConfig { - name: "lambda-lifting", - runner: |p| run_test(p, get_config_by_name("lambda-lifting")), - include: vec!["/lambda-lifting/"], + name: "lambda", + runner: |p| run_test(p, get_config_by_name("lambda")), + include: vec!["/lambda/", "/lambda-lifting/"], exclude: vec![], - exp_suffix: None, + exp_suffix: Some("lambda.exp"), options: opts .clone() + // .set_experiment(Experiment::AST_SIMPLIFY, true) .set_experiment(Experiment::LAMBDA_FIELDS, true) .set_experiment(Experiment::LAMBDA_IN_PARAMS, true) .set_experiment(Experiment::LAMBDA_IN_RETURNS, true) .set_experiment(Experiment::LAMBDA_VALUES, true) .set_experiment(Experiment::LAMBDA_LIFTING, true), - stop_after: StopAfter::AstPipeline, + stop_after: StopAfter::FileFormat, dump_ast: DumpLevel::AllStages, - dump_bytecode: DumpLevel::None, + dump_bytecode: DumpLevel::EndStage, dump_bytecode_filter: None, }, // Tests for simplifier in full mode, with code elimination @@ -213,7 +214,7 @@ const TEST_CONFIGS: Lazy> = Lazy::new(|| { TestConfig { name: "inlining-et-al", runner: |p| run_test(p, get_config_by_name("inlining-et-al")), - include: vec!["/inlining/", "/folding/", "/simplifier/"], + include: vec!["/inlining/", "/folding/", "/simplifier/", "/lambda/"], exclude: vec!["/more-v1/"], exp_suffix: None, options: opts.clone().set_experiment(Experiment::AST_SIMPLIFY, true), diff --git a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_complex_expression2.exp b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_complex_expression2.exp new file mode 100644 index 00000000000000..7201cb27d33968 --- /dev/null +++ b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_complex_expression2.exp @@ -0,0 +1,9 @@ +error[E01002]: unexpected token + ┌─ tests/move_check/parser/invalid_call_lhs_complex_expression2.move:3:29 + │ +3 │ (if (true) 5 else 0)(); + │ ^ + │ │ + │ Unexpected '(' + │ Expected ';' + diff --git a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_complex_expression2.move b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_complex_expression2.move new file mode 100644 index 00000000000000..45f36aeb03b0f1 --- /dev/null +++ b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_complex_expression2.move @@ -0,0 +1,6 @@ +module 0x123::M { + fun foo() { + (if (true) 5 else 0)(); + (while (false) {})(0, 1); + } +} diff --git a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_parens_around_name2.exp b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_parens_around_name2.exp new file mode 100644 index 00000000000000..fefac05537b4ba --- /dev/null +++ b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_parens_around_name2.exp @@ -0,0 +1,9 @@ +error[E01002]: unexpected token + ┌─ tests/move_check/parser/invalid_call_lhs_parens_around_name2.move:3:14 + │ +3 │ (foo)() + │ ^ + │ │ + │ Unexpected '(' + │ Expected ';' + diff --git a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_parens_around_name2.move b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_parens_around_name2.move new file mode 100644 index 00000000000000..4296a1ea71ce22 --- /dev/null +++ b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_parens_around_name2.move @@ -0,0 +1,5 @@ +module 0x123::M { + fun foo() { + (foo)() + } +} diff --git a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_return2.exp b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_return2.exp new file mode 100644 index 00000000000000..2527998d560059 --- /dev/null +++ b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_return2.exp @@ -0,0 +1,9 @@ +error[E01002]: unexpected token + ┌─ tests/move_check/parser/invalid_call_lhs_return2.move:3:20 + │ +3 │ (return ())(0, 1); + │ ^ + │ │ + │ Unexpected '(' + │ Expected ';' + diff --git a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_return2.move b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_return2.move new file mode 100644 index 00000000000000..fe0d45e7135856 --- /dev/null +++ b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_return2.move @@ -0,0 +1,5 @@ +module 0x123::M { + fun foo() { + (return ())(0, 1); + } +} diff --git a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_value2.exp b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_value2.exp new file mode 100644 index 00000000000000..cd650973ac8190 --- /dev/null +++ b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_value2.exp @@ -0,0 +1,9 @@ +error[E01002]: unexpected token + ┌─ tests/move_check/parser/invalid_call_lhs_value2.move:3:10 + │ +3 │ 5(); + │ ^ + │ │ + │ Unexpected '(' + │ Expected ';' + diff --git a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_value2.move b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_value2.move new file mode 100644 index 00000000000000..d5ce3bdae42ba2 --- /dev/null +++ b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_value2.move @@ -0,0 +1,6 @@ +module 0x123::M { + fun foo() { + 5(); + 5(0, 1); + } +}