From 2940f128664f913dedfe7e658486cf2c140b91ec Mon Sep 17 00:00:00 2001 From: "Brian R. Murphy" <132495859+brmataptos@users.noreply.github.com> Date: Fri, 27 Sep 2024 14:54:12 -0700 Subject: [PATCH] Response to Vineeth's review --- .../src/env_pipeline/function_checker.rs | 205 +++++++++++++----- .../move/move-compiler-v2/src/experiments.rs | 10 +- .../tests/checking/inlining/lambda4.exp | 12 +- .../tests/checking/inlining/lambda5.exp | 6 +- .../tests/checking/typing/lambda.move | 11 +- .../tests/checking/typing/lambda2.exp | 14 +- .../tests/checking/typing/lambda2.move | 29 ++- .../tests/checking/typing/lambda3.exp | 17 ++ .../tests/checking/typing/lambda3.move | 99 +++++++++ .../typing/lambda_returning_lambda.exp | 7 + .../typing/lambda_returning_lambda.move | 28 +++ .../typing/lambda_returning_lambda2.exp | 7 + .../typing/lambda_returning_lambda2.move | 12 + .../move/move-compiler-v2/tests/testsuite.rs | 8 +- .../move/move-compiler/src/typing/core.rs | 2 +- .../move_check/inlining/non_lambda_arg.exp | 4 +- .../parser/spec_parsing_fun_type_fail.exp | 2 +- .../tests/move_check/typing/lambda.exp | 22 +- .../tests/move_check/typing/lambda.move | 11 +- .../tests/move_check/typing/lambda2.exp | 14 +- .../tests/move_check/typing/lambda2.move | 33 ++- .../tests/move_check/typing/lambda3.exp | 6 + .../tests/move_check/typing/lambda3.move | 99 +++++++++ .../typing/lambda_returning_lambda.exp | 6 + .../typing/lambda_returning_lambda.move | 28 +++ .../typing/lambda_returning_lambda2.exp | 12 + .../typing/lambda_returning_lambda2.move | 12 + .../move-model/src/builder/module_builder.rs | 14 +- third_party/move/move-model/src/model.rs | 35 +-- third_party/move/move-model/src/ty.rs | 10 +- 30 files changed, 608 insertions(+), 167 deletions(-) create mode 100644 third_party/move/move-compiler-v2/tests/checking/typing/lambda3.exp create mode 100644 third_party/move/move-compiler-v2/tests/checking/typing/lambda3.move create mode 100644 third_party/move/move-compiler-v2/tests/checking/typing/lambda_returning_lambda.exp create mode 100644 third_party/move/move-compiler-v2/tests/checking/typing/lambda_returning_lambda.move create mode 100644 third_party/move/move-compiler-v2/tests/checking/typing/lambda_returning_lambda2.exp create mode 100644 third_party/move/move-compiler-v2/tests/checking/typing/lambda_returning_lambda2.move create mode 100644 third_party/move/move-compiler/tests/move_check/typing/lambda3.exp create mode 100644 third_party/move/move-compiler/tests/move_check/typing/lambda3.move create mode 100644 third_party/move/move-compiler/tests/move_check/typing/lambda_returning_lambda.exp create mode 100644 third_party/move/move-compiler/tests/move_check/typing/lambda_returning_lambda.move create mode 100644 third_party/move/move-compiler/tests/move_check/typing/lambda_returning_lambda2.exp create mode 100644 third_party/move/move-compiler/tests/move_check/typing/lambda_returning_lambda2.move diff --git a/third_party/move/move-compiler-v2/src/env_pipeline/function_checker.rs b/third_party/move/move-compiler-v2/src/env_pipeline/function_checker.rs index 05e86f37e82be5..c70cc293aeb7a1 100644 --- a/third_party/move/move-compiler-v2/src/env_pipeline/function_checker.rs +++ b/third_party/move/move-compiler-v2/src/env_pipeline/function_checker.rs @@ -8,20 +8,72 @@ use codespan_reporting::diagnostic::Severity; use move_binary_format::file_format::Visibility; use move_model::{ ast::{ExpData, Operation, Pattern}, - model::{FunId, FunctionEnv, GlobalEnv, Loc, ModuleEnv, NodeId, QualifiedId}, + model::{FunId, FunctionEnv, GlobalEnv, Loc, ModuleEnv, NodeId, Parameter, QualifiedId}, ty::Type, }; -use std::{collections::BTreeSet, iter::Iterator, vec::Vec}; +use std::{collections::BTreeSet, iter::Iterator, ops::Deref, vec::Vec}; type QualifiedFunId = QualifiedId; -/// check that non-inline function parameters do not have function type. +fn type_has_function(ty: &Type) -> bool { + match ty { + Type::Tuple(tys) => tys.iter().any(|ty| ty.is_function()), + Type::Fun(..) => true, + _ => false, + } +} + +// Takes a list of function types, returns those which have a function type in their argument type +fn identify_function_types_with_functions_in_args(func_returns: Vec) -> Vec { + func_returns + .into_iter() + .filter_map(|ty| { + if let Type::Fun(argt, _) = &ty { + if type_has_function(argt.deref()) { + Some(ty) + } else { + None + } + } else { + None + } + }) + .collect() +} + +// Takes a list of function-typed parameters, along with argument and result type +// Returns a list of any parameters whose result type has a function value, along with that result type. +fn identify_function_typed_params_with_functions_in_rets<'a>( + func_params: Vec<&'a Parameter>, +) -> Vec<(&'a Parameter, &'a Type)> { + func_params + .iter() + .filter_map(|param| { + if let Type::Fun(_argt, rest) = ¶m.1 { + let rest_unboxed = rest.deref(); + if type_has_function(rest_unboxed) { + Some((*param, rest_unboxed)) + } else { + None + } + } else { + None + } + }) + .collect() +} + +/// check that function parameters/results do not have function type unless allowed. +/// (1) is there a function type arg at the top level? This is allowed for inline or LAMBDA_IN_PARAMS +/// (2) is there a function type result at the top level? This is allowed only for LAMBDA_IN_RETURNS +/// (3) is there *any* function type with function type in an arg? This is allowed only for LAMBDA_IN_PARAMS +/// (4) is there *any* function type with function type in a result? This is allowed only for LAMBDA_IN_RETURNS pub fn check_for_function_typed_parameters(env: &mut GlobalEnv) { let options = env .get_extension::() .expect("Options is available"); - let lambda_params_ok = options.experiment_on(Experiment::LAMBDA_PARAMS); - let lambda_return_ok = options.experiment_on(Experiment::LAMBDA_RESULTS); + let lambda_params_ok = options.experiment_on(Experiment::LAMBDA_IN_PARAMS); + let lambda_return_ok = options.experiment_on(Experiment::LAMBDA_IN_RETURNS); if lambda_params_ok && lambda_return_ok { return; } @@ -29,57 +81,112 @@ pub fn check_for_function_typed_parameters(env: &mut GlobalEnv) { for caller_module in env.get_modules() { if caller_module.is_primary_target() { for caller_func in caller_module.get_functions() { - // Check that no functions have function return type - if !lambda_return_ok { + if !lambda_params_ok || !lambda_return_ok { let caller_name = caller_func.get_full_name_str(); let return_type = caller_func.get_result_type(); - let has_function_value = - return_type.clone().flatten().iter().any(Type::is_function); - if has_function_value { - let type_display_ctx = caller_func.get_type_display_ctx(); - env.diag( - Severity::Error, - &caller_func.get_id_loc(), - &format!("Functions may not return function-typed values, but function `{}` return type is `{}`:", - caller_name, - return_type.display(&type_display_ctx)), - ); + let func_returns: Vec<_> = return_type + .clone() + .flatten() + .into_iter() + .filter(|t| t.is_function()) + .collect(); + let type_display_ctx = caller_func.get_type_display_ctx(); + if !func_returns.is_empty() { + // (2) is there a function type result at the top level? This is allowed + // only for LAMBDA_IN_RETURNS + if !lambda_return_ok { + if !func_returns.is_empty() { + env.diag( + Severity::Error, + &caller_func.get_result_type_loc(), + &format!("Functions may not return function-typed values, but function `{}` return type is the function type `{}`:", + &caller_name, + return_type.display(&type_display_ctx)), + ) + } + } + if !lambda_params_ok { + // (3) is there *any* function type with function type in an arg? This + // is allowed only for LAMBDA_IN_PARAMS + let bad_returns = + identify_function_types_with_functions_in_args(func_returns); + if !bad_returns.is_empty() { + env.diag( + Severity::Error, + &caller_func.get_result_type_loc(), + &format!("Non-inline functions may not take function-typed parameters, but function `{}` return type is `{}`, which has a function type taking a function parameter:", + &caller_name, + return_type.display(&type_display_ctx)), + ) + } + } } - } - // Check that non-inline function parameters don't have function type - if !caller_func.is_inline() && !lambda_params_ok { - let parameters = caller_func.get_parameters(); - let bad_params: Vec<_> = parameters + + let parameters = caller_func.get_parameters_ref(); + let func_params: Vec<_> = parameters .iter() - .filter(|param| matches!(param.1, Type::Fun(_, _))) + .filter(|param| matches!(param.1, Type::Fun(..))) .collect(); - if !bad_params.is_empty() { - let type_display_ctx = caller_func.get_type_display_ctx(); - let caller_name = caller_func.get_full_name_str(); - let reasons: Vec<(Loc, String)> = bad_params - .iter() - .map(|param| { - ( - param.2.clone(), - format!( - "Parameter `{}` has function-valued type `{}`.", - param.0.display(env.symbol_pool()), - param.1.display(&type_display_ctx) + if !func_params.is_empty() { + // (1) is there a function type arg at the top level? This is allowed for + // inline or LAMBDA_IN_PARAMS + if !caller_func.is_inline() && !lambda_params_ok { + let reasons: Vec<(Loc, String)> = func_params + .iter() + .map(|param| { + ( + param.2.clone(), + format!( + "Parameter `{}` has function-valued type `{}`.", + param.0.display(env.symbol_pool()), + param.1.display(&type_display_ctx) + ), + ) + }) + .collect(); + env.diag_with_labels( + Severity::Error, + &caller_func.get_id_loc(), + &format!("Only inline functions may have function-typed parameters, but non-inline function `{}` has {}:", + caller_name, + if reasons.len() > 1 { "function parameters" } else { "a function parameter" }, + ), + reasons, + ); + } + if !lambda_return_ok { + // (4) is there *any* function type with function type in its result? This is + // allowed only for LAMBDA_IN_RETURNS + let bad_params = + identify_function_typed_params_with_functions_in_rets(func_params); + if !bad_params.is_empty() { + let reasons: Vec<(Loc, String)> = bad_params + .iter() + .map(|(param, ty)| { + ( + param.2.clone(), + format!( + "Parameter `{}` has type `{}`, which has function type `{}` as a function result type", + param.0.display(env.symbol_pool()), + param.1.display(&type_display_ctx), + ty.display(&type_display_ctx), + ), + ) + }) + .collect(); + env.diag_with_labels( + Severity::Error, + &caller_func.get_id_loc(), + &format!("Functions may not return function-typed values, but function `{}` has {} of function type with function-typed result:", + caller_name, + if reasons.len() > 1 { "parameters" } else { "a parameter" }, ), - ) - }) - .collect(); - env.diag_with_labels( - Severity::Error, - &caller_func.get_id_loc(), - &format!("Only inline functions may have function-typed parameters, but non-inline function `{}` has {}:", - caller_name, - if reasons.len() > 1 { "function parameters" } else { "a function parameter" }, - ), - reasons, - ); + reasons, + ); + } + } } - } + }; } } } diff --git a/third_party/move/move-compiler-v2/src/experiments.rs b/third_party/move/move-compiler-v2/src/experiments.rs index c067d2f243ee1d..ceea7b65d84031 100644 --- a/third_party/move/move-compiler-v2/src/experiments.rs +++ b/third_party/move/move-compiler-v2/src/experiments.rs @@ -122,14 +122,14 @@ pub static EXPERIMENTS: Lazy> = Lazy::new(|| { default: Given(false), }, Experiment { - name: Experiment::LAMBDA_PARAMS.to_string(), + name: Experiment::LAMBDA_IN_PARAMS.to_string(), description: "Turns on or off function values as parameters to non-inline functions" .to_string(), default: Given(false), }, Experiment { - name: Experiment::LAMBDA_RESULTS.to_string(), - description: "Turns on or off function values in function results".to_string(), + name: Experiment::LAMBDA_IN_RETURNS.to_string(), + description: "Turns on or off function values in function return values".to_string(), default: Given(false), }, Experiment { @@ -297,9 +297,9 @@ impl Experiment { pub const KEEP_INLINE_FUNS: &'static str = "keep-inline-funs"; pub const KEEP_UNINIT_ANNOTATIONS: &'static str = "keep-uninit-annotations"; pub const LAMBDA_FIELDS: &'static str = "lambda-fields"; + pub const LAMBDA_IN_PARAMS: &'static str = "lambda-in-params"; + pub const LAMBDA_IN_RETURNS: &'static str = "lambda-in-returns"; pub const LAMBDA_LIFTING: &'static str = "lambda-lifting"; - pub const LAMBDA_PARAMS: &'static str = "lambda-params"; - pub const LAMBDA_RESULTS: &'static str = "lambda-results"; pub const LAMBDA_VALUES: &'static str = "lambda-values"; pub const LINT_CHECKS: &'static str = "lint-checks"; pub const OPTIMIZE: &'static str = "optimize"; diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/lambda4.exp b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda4.exp index 7a6fd81d695931..14e896bb69ca51 100644 --- a/third_party/move/move-compiler-v2/tests/checking/inlining/lambda4.exp +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda4.exp @@ -1,13 +1,13 @@ Diagnostics: -error: Functions may not return function-typed values, but function `M::macro_result_lambda_not_allowed` return type is `|u64|`: - ┌─ tests/checking/inlining/lambda4.move:86:23 +error: Functions may not return function-typed values, but function `M::macro_result_lambda_not_allowed` return type is the function type `|u64|`: + ┌─ tests/checking/inlining/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 `|u64|`: - ┌─ tests/checking/inlining/lambda4.move:89:16 +error: Functions may not return function-typed values, but function `M::fun_result_lambda_not_allowed` return type is the function type `|u64|`: + ┌─ tests/checking/inlining/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/checking/inlining/lambda5.exp b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda5.exp index 8dc25cb601fb43..78669969275c4c 100644 --- a/third_party/move/move-compiler-v2/tests/checking/inlining/lambda5.exp +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda5.exp @@ -1,7 +1,7 @@ Diagnostics: -error: Functions may not return function-typed values, but function `M::macro_result_lambda_not_allowed` return type is `|u64|`: - ┌─ tests/checking/inlining/lambda5.move:86:23 +error: Functions may not return function-typed values, but function `M::macro_result_lambda_not_allowed` return type is the function type `|u64|`: + ┌─ tests/checking/inlining/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/checking/typing/lambda.move b/third_party/move/move-compiler-v2/tests/checking/typing/lambda.move index c5e29275c3d286..92e24c0c36a901 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/lambda.move +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda.move @@ -83,18 +83,17 @@ module 0x8675309::M { 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 + public inline fun inline_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) } + public fun length(_v: &vector): u64 { abort(1) } + public fun is_empty(_v: &vector): bool { abort(1) } + public fun borrow(_v: &vector, _i: u64): &T { abort(1) } + public fun pop_back(_v: &mut vector): T { abort(1) } } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/lambda2.exp b/third_party/move/move-compiler-v2/tests/checking/typing/lambda2.exp index 3488e912088496..4f27955dd4e6ff 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/lambda2.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda2.exp @@ -12,14 +12,14 @@ warning: Unused parameter `x`. Consider removing or prefixing with an underscore 84 │ public fun fun_arg_lambda_not_allowed(x: |u64|) {} // expected lambda not allowed │ ^ -error: Functions may not return function-typed values, but function `M::macro_result_lambda_not_allowed` return type is `|u64|`: - ┌─ tests/checking/typing/lambda2.move:86:23 +error: Functions may not return function-typed values, but function `M::inline_result_lambda_not_allowed` return type is the function type `|u64|`: + ┌─ tests/checking/typing/lambda2.move:86:59 │ -86 │ public inline fun macro_result_lambda_not_allowed(): |u64| { // expected lambda not allowed - │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +86 │ public inline fun inline_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 `|u64|`: - ┌─ tests/checking/typing/lambda2.move:89:16 +error: Functions may not return function-typed values, but function `M::fun_result_lambda_not_allowed` return type is the function type `|u64|`: + ┌─ tests/checking/typing/lambda2.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/checking/typing/lambda2.move b/third_party/move/move-compiler-v2/tests/checking/typing/lambda2.move index 5d7cc52daf2aeb..ccaa472c2e2c26 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/lambda2.move +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda2.move @@ -1,5 +1,13 @@ module 0x8675309::M { - // use 0x1::XVector; + + // *** NOTE: THIS TEST FILE IS DERIVED FROM lambda.move by commenting out code which has errors + // successfully flagged by move-compiler-v2, so that we can check for errors on other lines + // which may be shadowed by those errors. + // + // We keep the commented code so that the error line numbers line up. + // + // + // ... code removed here to allow above message ... // public inline fun foreach(v: &vector, action: |&T|) { // expected to be not implemented // let i = 0; @@ -9,14 +17,6 @@ module 0x8675309::M { // } // } - // 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; @@ -83,18 +83,17 @@ module 0x8675309::M { 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 + public inline fun inline_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) } +// public fun length(_v: &vector): u64 { abort(1) } +// public fun is_empty(_v: &vector): bool { abort(1) } +// public fun borrow(_v: &vector, _i: u64): &T { abort(1) } +// public fun pop_back(_v: &mut vector): T { abort(1) } // } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/lambda3.exp b/third_party/move/move-compiler-v2/tests/checking/typing/lambda3.exp new file mode 100644 index 00000000000000..a629fb8ec36d9c --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/typing/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/checking/typing/lambda3.move:77:18 + │ +77 │ let _x = |i| i + 1; // expected lambda not allowed + │ ^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/lambda3.move b/third_party/move/move-compiler-v2/tests/checking/typing/lambda3.move new file mode 100644 index 00000000000000..bc302cc3ee3bef --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda3.move @@ -0,0 +1,99 @@ +module 0x8675309::M { + + // *** NOTE: THIS TEST FILE IS DERIVED FROM lambda2.move by commenting out code which has errors + // successfully flagged by move-compiler-v2, so that we can check for errors on other lines + // which may be shadowed by those errors. + // + // We keep the commented code so that the error line numbers line up. + // + // + // ... code removed here to allow above message ... + + // 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 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/checking/typing/lambda_returning_lambda.exp b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_returning_lambda.exp new file mode 100644 index 00000000000000..d16f979db05621 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_returning_lambda.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Functions may not return function-typed values, but function `M::foreach_caller` has a parameter of function type with function-typed result: + ┌─ tests/checking/typing/lambda_returning_lambda.move:12:23 + │ +12 │ public inline fun foreach_caller(v: &vector, action: ||(|&T|)) { + │ ^^^^^^^^^^^^^^ ------ Parameter `action` has type `|()||&T|`, which has function type `|&T|` as a function result type diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/lambda_returning_lambda.move b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_returning_lambda.move new file mode 100644 index 00000000000000..bd93f64575ac68 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_returning_lambda.move @@ -0,0 +1,28 @@ +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 foreach_caller(v: &vector, action: ||(|&T|)) { + foreach(v, action()) + } + + public fun whacky_foreach() { + let v = vector[1, 2, 3]; + let sum = 0; + foreach_caller(&v, ||(|e| sum = sum + *e)) // expected to be not implemented + } +} + +module 0x1::XVector { + public fun length(_v: &vector): u64 { abort(1) } + public fun is_empty(_v: &vector): bool { abort(1) } + public fun borrow(_v: &vector, _i: u64): &T { abort(1) } + public fun pop_back(_v: &mut vector): T { abort(1) } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/lambda_returning_lambda2.exp b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_returning_lambda2.exp new file mode 100644 index 00000000000000..7fccdd1f60f5f9 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_returning_lambda2.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: Functions may not return function-typed values, but function `M::foreach_caller2` has a parameter of function type with function-typed result: + ┌─ tests/checking/typing/lambda_returning_lambda2.move:3:23 + │ +3 │ public inline fun foreach_caller2(_v: &vector, _action: ||(|&T|)) { + │ ^^^^^^^^^^^^^^^ ------- Parameter `_action` has type `|()||&T|`, which has function type `|&T|` as a function result type diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/lambda_returning_lambda2.move b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_returning_lambda2.move new file mode 100644 index 00000000000000..a77ab5421fcd8f --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_returning_lambda2.move @@ -0,0 +1,12 @@ +module 0x8675309::M { + + public inline fun foreach_caller2(_v: &vector, _action: ||(|&T|)) { + abort(1) + } + + public fun whacky_foreach2() { + let v = vector[1, 2, 3]; + let sum = 0; + foreach_caller2(&v, ||(|e| sum = sum + *e)) // expected to be not implemented + } +} diff --git a/third_party/move/move-compiler-v2/tests/testsuite.rs b/third_party/move/move-compiler-v2/tests/testsuite.rs index eb0d506c1f6996..1d516f047a21c9 100644 --- a/third_party/move/move-compiler-v2/tests/testsuite.rs +++ b/third_party/move/move-compiler-v2/tests/testsuite.rs @@ -127,9 +127,9 @@ const TEST_CONFIGS: Lazy> = Lazy::new(|| { options: opts .clone() .set_experiment(Experiment::ACQUIRES_CHECK, false), - stop_after: StopAfter::BytecodeGen, + stop_after: StopAfter::BytecodeGen, // FileFormat, dump_ast: DumpLevel::EndStage, - dump_bytecode: DumpLevel::None, + dump_bytecode: DumpLevel::None, // EndStage, dump_bytecode_filter: None, }, // Tests for checking v2 language features only supported if v2 @@ -170,8 +170,8 @@ const TEST_CONFIGS: Lazy> = Lazy::new(|| { options: opts .clone() .set_experiment(Experiment::LAMBDA_FIELDS, true) - .set_experiment(Experiment::LAMBDA_PARAMS, true) - .set_experiment(Experiment::LAMBDA_RESULTS, 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, diff --git a/third_party/move/move-compiler/src/typing/core.rs b/third_party/move/move-compiler/src/typing/core.rs index 1b1c196e57f3a0..df4bf1dae52c65 100644 --- a/third_party/move/move-compiler/src/typing/core.rs +++ b/third_party/move/move-compiler/src/typing/core.rs @@ -1664,7 +1664,7 @@ pub fn check_non_fun(context: &mut Context, ty: &Type) { TypeSafety::InvalidFunctionType, ( *loc, - "function type only allowed for inline function arguments" + "function-typed values only allowed for inline function arguments" ) )) } diff --git a/third_party/move/move-compiler/tests/move_check/inlining/non_lambda_arg.exp b/third_party/move/move-compiler/tests/move_check/inlining/non_lambda_arg.exp index 51dfb276b53426..b0d908310701a6 100644 --- a/third_party/move/move-compiler/tests/move_check/inlining/non_lambda_arg.exp +++ b/third_party/move/move-compiler/tests/move_check/inlining/non_lambda_arg.exp @@ -2,11 +2,11 @@ error[E04024]: invalid usage of function type ┌─ tests/move_check/inlining/non_lambda_arg.move:4:71 │ 4 │ public fun incorrect_sort(arr: &mut vector, a_less_b: |T, T| bool) { - │ ^^^^^^^^^^^ function type only allowed for inline function arguments + │ ^^^^^^^^^^^ function-typed values only allowed for inline function arguments error[E04024]: invalid usage of function type ┌─ tests/move_check/inlining/non_lambda_arg.move:9:102 │ 9 │ public fun incorrect_sort_recursive(arr: &mut vector, low: u64, high: u64, a_less_b: |T, T| bool) { - │ ^^^^^^^^^^^ function type only allowed for inline function arguments + │ ^^^^^^^^^^^ function-typed values only allowed for inline function arguments diff --git a/third_party/move/move-compiler/tests/move_check/parser/spec_parsing_fun_type_fail.exp b/third_party/move/move-compiler/tests/move_check/parser/spec_parsing_fun_type_fail.exp index e305bdc9c047b4..8f5acce33805a9 100644 --- a/third_party/move/move-compiler/tests/move_check/parser/spec_parsing_fun_type_fail.exp +++ b/third_party/move/move-compiler/tests/move_check/parser/spec_parsing_fun_type_fail.exp @@ -2,5 +2,5 @@ error[E04024]: invalid usage of function type ┌─ tests/move_check/parser/spec_parsing_fun_type_fail.move:2:29 │ 2 │ fun fun_type_in_prog(p: |u64|u64) { - │ ^^^^^^^^ function type only allowed for inline function arguments + │ ^^^^^^^^ function-typed values only allowed for inline function arguments diff --git a/third_party/move/move-compiler/tests/move_check/typing/lambda.exp b/third_party/move/move-compiler/tests/move_check/typing/lambda.exp index e59ad1ba145cf6..f3bf11a387c2c6 100644 --- a/third_party/move/move-compiler/tests/move_check/typing/lambda.exp +++ b/third_party/move/move-compiler/tests/move_check/typing/lambda.exp @@ -22,8 +22,8 @@ error[E04007]: incompatible types 48 │ action(i); // expected to have wrong argument type │ ^^^^^^^^^ Invalid call of 'action'. Invalid argument type · -96 │ public fun length(v: &vector): u64 { abort(1) } - │ --- Given: 'u64' +95 │ public fun length(_v: &vector): u64 { abort(1) } + │ --- Given: 'u64' error[E04007]: incompatible types ┌─ tests/move_check/typing/lambda.move:56:19 @@ -34,8 +34,8 @@ error[E04007]: incompatible types 56 │ i = i + action(XVector::borrow(v, i)); // expected to have wrong result type │ ^ Incompatible arguments to '+' · -96 │ public fun length(v: &vector): u64 { abort(1) } - │ --- Found: 'u64'. It is not compatible with the other type. +95 │ public fun length(_v: &vector): u64 { abort(1) } + │ --- Found: 'u64'. It is not compatible with the other type. error[E04007]: incompatible types ┌─ tests/move_check/typing/lambda.move:61:9 @@ -71,29 +71,29 @@ error[E04024]: invalid usage of function type ┌─ tests/move_check/typing/lambda.move:77:18 │ 77 │ let _x = |i| i + 1; // expected lambda not allowed - │ ^^^^^^^^^ function type only allowed for inline function arguments + │ ^^^^^^^^^ function-typed values only allowed for inline function arguments error[E04024]: invalid usage of function type ┌─ tests/move_check/typing/lambda.move:81:12 │ 81 │ f: |u64|u64, // expected lambda not allowed - │ ^^^^^^^^ function type only allowed for inline function arguments + │ ^^^^^^^^ function-typed values only allowed for inline function arguments error[E04024]: invalid usage of function type ┌─ tests/move_check/typing/lambda.move:84:46 │ 84 │ public fun fun_arg_lambda_not_allowed(x: |u64|) {} // expected lambda not allowed - │ ^^^^^ function type only allowed for inline function arguments + │ ^^^^^ function-typed values only allowed for inline function arguments error[E04024]: invalid usage of function type - ┌─ tests/move_check/typing/lambda.move:86:58 + ┌─ tests/move_check/typing/lambda.move:86:59 │ -86 │ public inline fun macro_result_lambda_not_allowed(): |u64| { // expected lambda not allowed - │ ^^^^^ function type only allowed for inline function arguments +86 │ public inline fun inline_result_lambda_not_allowed(): |u64| { // expected lambda not allowed + │ ^^^^^ function-typed values only allowed for inline function arguments error[E04024]: invalid usage of function type ┌─ tests/move_check/typing/lambda.move:89:49 │ 89 │ public fun fun_result_lambda_not_allowed(): |u64| { // expected lambda not allowed - │ ^^^^^ function type only allowed for inline function arguments + │ ^^^^^ function-typed values only allowed for inline function arguments diff --git a/third_party/move/move-compiler/tests/move_check/typing/lambda.move b/third_party/move/move-compiler/tests/move_check/typing/lambda.move index c5e29275c3d286..92e24c0c36a901 100644 --- a/third_party/move/move-compiler/tests/move_check/typing/lambda.move +++ b/third_party/move/move-compiler/tests/move_check/typing/lambda.move @@ -83,18 +83,17 @@ module 0x8675309::M { 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 + public inline fun inline_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) } + 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/tests/move_check/typing/lambda2.exp b/third_party/move/move-compiler/tests/move_check/typing/lambda2.exp index 073ed797528e36..6a329bd27c5d20 100644 --- a/third_party/move/move-compiler/tests/move_check/typing/lambda2.exp +++ b/third_party/move/move-compiler/tests/move_check/typing/lambda2.exp @@ -2,29 +2,23 @@ error[E04024]: invalid usage of function type ┌─ tests/move_check/typing/lambda2.move:77:18 │ 77 │ let _x = |i| i + 1; // expected lambda not allowed - │ ^^^^^^^^^ function type only allowed for inline function arguments - -error[E04024]: invalid usage of function type - ┌─ tests/move_check/typing/lambda2.move:81:12 - │ -81 │ f: |u64|u64, // expected lambda not allowed - │ ^^^^^^^^ function type only allowed for inline function arguments + │ ^^^^^^^^^ function-typed values only allowed for inline function arguments error[E04024]: invalid usage of function type ┌─ tests/move_check/typing/lambda2.move:84:46 │ 84 │ public fun fun_arg_lambda_not_allowed(x: |u64|) {} // expected lambda not allowed - │ ^^^^^ function type only allowed for inline function arguments + │ ^^^^^ function-typed values only allowed for inline function arguments error[E04024]: invalid usage of function type ┌─ tests/move_check/typing/lambda2.move:86:58 │ 86 │ public inline fun macro_result_lambda_not_allowed(): |u64| { // expected lambda not allowed - │ ^^^^^ function type only allowed for inline function arguments + │ ^^^^^ function-typed values only allowed for inline function arguments error[E04024]: invalid usage of function type ┌─ tests/move_check/typing/lambda2.move:89:49 │ 89 │ public fun fun_result_lambda_not_allowed(): |u64| { // expected lambda not allowed - │ ^^^^^ function type only allowed for inline function arguments + │ ^^^^^ function-typed values only allowed for inline function arguments diff --git a/third_party/move/move-compiler/tests/move_check/typing/lambda2.move b/third_party/move/move-compiler/tests/move_check/typing/lambda2.move index 50bdd1270ce254..0a3ede2f22a19c 100644 --- a/third_party/move/move-compiler/tests/move_check/typing/lambda2.move +++ b/third_party/move/move-compiler/tests/move_check/typing/lambda2.move @@ -1,5 +1,13 @@ module 0x8675309::M { - // use 0x1::XVector; + + // *** NOTE: THIS TEST FILE IS DERIVED FROM lambda.move by commenting out code which has errors + // successfully flagged by move-compiler-v2, so that we can check for errors on other lines + // which may be shadowed by those errors. + // + // We keep the commented code so that the error line numbers line up. + // + // + // ... code removed here to allow above message ... // public inline fun foreach(v: &vector, action: |&T|) { // expected to be not implemented // let i = 0; @@ -9,14 +17,6 @@ module 0x8675309::M { // } // } - // 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; @@ -77,9 +77,9 @@ module 0x8675309::M { let _x = |i| i + 1; // expected lambda not allowed } - struct FieldFunNotAllowed { - f: |u64|u64, // 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 @@ -89,12 +89,11 @@ module 0x8675309::M { 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) } +// 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/tests/move_check/typing/lambda3.exp b/third_party/move/move-compiler/tests/move_check/typing/lambda3.exp new file mode 100644 index 00000000000000..fcc8ff722d396e --- /dev/null +++ b/third_party/move/move-compiler/tests/move_check/typing/lambda3.exp @@ -0,0 +1,6 @@ +error[E04024]: invalid usage of function type + ┌─ tests/move_check/typing/lambda3.move:77:18 + │ +77 │ let _x = |i| i + 1; // expected lambda not allowed + │ ^^^^^^^^^ function-typed values only allowed for inline function arguments + diff --git a/third_party/move/move-compiler/tests/move_check/typing/lambda3.move b/third_party/move/move-compiler/tests/move_check/typing/lambda3.move new file mode 100644 index 00000000000000..bc302cc3ee3bef --- /dev/null +++ b/third_party/move/move-compiler/tests/move_check/typing/lambda3.move @@ -0,0 +1,99 @@ +module 0x8675309::M { + + // *** NOTE: THIS TEST FILE IS DERIVED FROM lambda2.move by commenting out code which has errors + // successfully flagged by move-compiler-v2, so that we can check for errors on other lines + // which may be shadowed by those errors. + // + // We keep the commented code so that the error line numbers line up. + // + // + // ... code removed here to allow above message ... + + // 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 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/tests/move_check/typing/lambda_returning_lambda.exp b/third_party/move/move-compiler/tests/move_check/typing/lambda_returning_lambda.exp new file mode 100644 index 00000000000000..7e44d487754e8b --- /dev/null +++ b/third_party/move/move-compiler/tests/move_check/typing/lambda_returning_lambda.exp @@ -0,0 +1,6 @@ +error[E14003]: feature not supported in inlined functions + ┌─ tests/move_check/typing/lambda_returning_lambda.move:13:23 + │ +13 │ foreach(v, action()) + │ ^^^^^^^^ Inlined function-typed parameter currently must be a literal lambda expression + diff --git a/third_party/move/move-compiler/tests/move_check/typing/lambda_returning_lambda.move b/third_party/move/move-compiler/tests/move_check/typing/lambda_returning_lambda.move new file mode 100644 index 00000000000000..bd93f64575ac68 --- /dev/null +++ b/third_party/move/move-compiler/tests/move_check/typing/lambda_returning_lambda.move @@ -0,0 +1,28 @@ +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 foreach_caller(v: &vector, action: ||(|&T|)) { + foreach(v, action()) + } + + public fun whacky_foreach() { + let v = vector[1, 2, 3]; + let sum = 0; + foreach_caller(&v, ||(|e| sum = sum + *e)) // expected to be not implemented + } +} + +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/tests/move_check/typing/lambda_returning_lambda2.exp b/third_party/move/move-compiler/tests/move_check/typing/lambda_returning_lambda2.exp new file mode 100644 index 00000000000000..3c0588535c6aaf --- /dev/null +++ b/third_party/move/move-compiler/tests/move_check/typing/lambda_returning_lambda2.exp @@ -0,0 +1,12 @@ +error[E04007]: incompatible types + ┌─ tests/move_check/typing/lambda_returning_lambda2.move:10:9 + │ + 3 │ public inline fun foreach_caller2(_v: &vector, _action: ||(u64)) { + │ ----- Expected: 'u64' + · +10 │ foreach_caller2(&v, ||(|e| sum = sum + *e)) // expected to be not implemented + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + │ │ │ + │ │ Given: '|&{integer}|()' + │ Invalid call of '0x8675309::M::foreach_caller2'. Invalid argument for parameter '_action' + diff --git a/third_party/move/move-compiler/tests/move_check/typing/lambda_returning_lambda2.move b/third_party/move/move-compiler/tests/move_check/typing/lambda_returning_lambda2.move new file mode 100644 index 00000000000000..a77ab5421fcd8f --- /dev/null +++ b/third_party/move/move-compiler/tests/move_check/typing/lambda_returning_lambda2.move @@ -0,0 +1,12 @@ +module 0x8675309::M { + + public inline fun foreach_caller2(_v: &vector, _action: ||(|&T|)) { + abort(1) + } + + public fun whacky_foreach2() { + let v = vector[1, 2, 3]; + let sum = 0; + foreach_caller2(&v, ||(|e| sum = sum + *e)) // expected to be not implemented + } +} diff --git a/third_party/move/move-model/src/builder/module_builder.rs b/third_party/move/move-model/src/builder/module_builder.rs index 95d45397af6234..40edad8e2ebaa1 100644 --- a/third_party/move/move-model/src/builder/module_builder.rs +++ b/third_party/move/move-model/src/builder/module_builder.rs @@ -20,9 +20,9 @@ use crate::{ intrinsics::process_intrinsic_declaration, model, model::{ - EqIgnoringLoc, FieldData, FieldId, FunId, FunctionData, FunctionKind, Loc, ModuleId, - MoveIrLoc, NamedConstantData, NamedConstantId, NodeId, Parameter, SchemaId, SpecFunId, - SpecVarId, StructData, StructId, TypeParameter, TypeParameterKind, + EqIgnoringLoc, FieldData, FieldId, FunId, FunctionData, FunctionKind, FunctionLoc, Loc, + ModuleId, MoveIrLoc, NamedConstantData, NamedConstantId, NodeId, Parameter, SchemaId, + SpecFunId, SpecVarId, StructData, StructId, TypeParameter, TypeParameterKind, }, options::ModelBuilderOptions, pragmas::{ @@ -3552,9 +3552,11 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> { let fun_id = FunId::new(name.symbol); let data = FunctionData { name: name.symbol, - loc: entry.loc.clone(), - id_loc: entry.name_loc.clone(), - result_type_loc: entry.result_type_loc.clone(), + loc: FunctionLoc { + full: entry.loc.clone(), + id_loc: entry.name_loc.clone(), + result_type_loc: entry.result_type_loc.clone(), + }, def_idx: None, handle_idx: None, visibility: entry.visibility, diff --git a/third_party/move/move-model/src/model.rs b/third_party/move/move-model/src/model.rs index 71f4059e609b98..b5545f670cb51f 100644 --- a/third_party/move/move-model/src/model.rs +++ b/third_party/move/move-model/src/model.rs @@ -1869,9 +1869,11 @@ impl GlobalEnv { let called_funs = def.called_funs(); let data = FunctionData { name, - loc: loc.clone(), - id_loc: loc.clone(), - result_type_loc: loc, + loc: FunctionLoc { + full: loc.clone(), + id_loc: loc.clone(), + result_type_loc: loc, + }, def_idx: None, handle_idx: None, visibility, @@ -3968,19 +3970,26 @@ impl EqIgnoringLoc for Parameter { } } -#[derive(Debug)] -pub struct FunctionData { - /// Name of this function. - pub(crate) name: Symbol, - +/// Represents source code locations associated with a function. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct FunctionLoc { /// Location of this function. - pub(crate) loc: Loc, + pub(crate) full: Loc, /// Location of the function identifier, suitable for error messages alluding to the function. pub(crate) id_loc: Loc, /// Location of the function result type, suitable for error messages alluding to the result type. pub(crate) result_type_loc: Loc, +} + +#[derive(Debug)] +pub struct FunctionData { + /// Name of this function. + pub(crate) name: Symbol, + + /// Locations of this function. + pub(crate) loc: FunctionLoc, /// The definition index of this function in its bytecode module, if a bytecode module /// is attached to the parent module data. @@ -4101,7 +4110,7 @@ impl<'env> FunctionEnv<'env> { /// Get documentation associated with this function. pub fn get_doc(&self) -> &str { - self.module_env.env.get_doc(&self.data.loc) + self.module_env.env.get_doc(&self.data.loc.full) } /// Gets the definition index of this function. @@ -4116,17 +4125,17 @@ impl<'env> FunctionEnv<'env> { /// Returns the location of this function. pub fn get_loc(&self) -> Loc { - self.data.loc.clone() + self.data.loc.full.clone() } /// Returns the location of the function identifier. pub fn get_id_loc(&self) -> Loc { - self.data.id_loc.clone() + self.data.loc.id_loc.clone() } /// Returns the location of the function identifier. pub fn get_result_type_loc(&self) -> Loc { - self.data.result_type_loc.clone() + self.data.loc.result_type_loc.clone() } /// Returns the attributes of this function. diff --git a/third_party/move/move-model/src/ty.rs b/third_party/move/move-model/src/ty.rs index 985a75766055d6..9fc0002f44ece0 100644 --- a/third_party/move/move-model/src/ty.rs +++ b/third_party/move/move-model/src/ty.rs @@ -535,14 +535,14 @@ impl Constraint { } } - /// Returns the constraints which need to be satisfied to instantiate the given - /// type parameter. This creates NoReference, NoTuple, NoPhantom unless the type parameter is - /// phantom, and HasAbilities if any abilities need to be met. + /// Returns the constraints which need to be satisfied to instantiate the given type + /// parameter. This creates NoReference, NoFunction, NoTuple, NoPhantom unless the type + /// parameter is phantom, and HasAbilities if any abilities need to be met. pub fn for_type_parameter(param: &TypeParameter) -> Vec { let mut result = vec![ Constraint::NoReference, Constraint::NoTuple, - Constraint::NoFunction, + Constraint::NoFunction, // TODO(LAMBDA) - remove when implement LAMBDA_AS_TYPE_PARAMETERS ]; let TypeParameter( _, @@ -567,7 +567,7 @@ impl Constraint { Constraint::NoPhantom, Constraint::NoReference, Constraint::NoTuple, - Constraint::NoFunction, + Constraint::NoFunction, // TODO(LAMBDA) - remove when we implement LAMBDA_IN_VECTORS ] }