From 918b643c98f81b8b2b3dd3a597329210b35c30b3 Mon Sep 17 00:00:00 2001 From: "Brian R. Murphy" <132495859+brmataptos@users.noreply.github.com> Date: Wed, 9 Oct 2024 21:56:33 -0700 Subject: [PATCH] [move-compiler-v2] fix #14633: fix error messages for lambdas, identify change points for more complete lambda implementation (#14742) Catch all errors in move-compiler-v2/tests/checking/typing/lambda.move in Compiler V2, after splitting and gradually commenting out code as lambda[2-5].move, to avoid shadowing by other errors. Lay groundwork for support of lambdas in various capacities. Fixes #14633. - add checking for function-typed function results in function_checker, and functions in parameters and results of function types in both args and results to functions there. - to properly show "error" rather than "bug" if lambdas are mistakenly used as values today. - tag some code to show where changes are needed to support lambda: // TODO(LAMBDA) fix unused_params_checker and recursive_struct_checker to tolerate lambda types - add experiments to control enabling of various aspects of lambda support: - add a result_type_loc field to move-model's FunctionData (and model-builder's FunEntry) to more precisely locate errors in function result types. - Fix GlobalEnv::internal_dump_env to use function- and struct-specific type contexts so that types are shown with correct type parameter names. - Check that struct fields are not functions. --- .../tests/type_safety/gerbens_test.exp | 2 +- .../src/bytecode_generator.rs | 28 +- .../src/env_pipeline/function_checker.rs | 189 ++++++-- .../src/env_pipeline/lambda_lifter.rs | 4 +- .../env_pipeline/recursive_struct_checker.rs | 4 +- .../src/env_pipeline/unused_params_checker.rs | 10 +- .../move/move-compiler-v2/src/experiments.rs | 25 + .../file_format_generator/module_generator.rs | 13 +- .../tests/bytecode-generator/assign.exp | 2 +- .../borrow_deref_optimize.exp | 4 +- .../bug_14471_receiver_inference.exp | 10 +- .../bytecode-generator/escape_autoref.exp | 4 +- .../tests/bytecode-generator/fields.exp | 6 +- .../bytecode-generator/fields_invalid.exp | 2 +- .../tests/bytecode-generator/globals.exp | 4 +- .../matching_ability_err.exp | 6 +- .../matching_coverage_err.exp | 6 +- .../tests/bytecode-generator/matching_ok.exp | 10 +- .../mutate_immutable_cmp.exp | 2 +- .../tests/bytecode-generator/pack_unpack.exp | 2 +- .../bytecode-generator/spec_construct.exp | 2 +- .../use_struct_overlap_with_module.exp | 4 +- .../abilities/v1/ability_constraints.exp | 22 +- .../v1/phantom_param_op_abilities.exp | 22 +- .../phantom_params_constraint_abilities.exp | 38 +- .../v1/phantom_params_field_abilities.exp | 24 +- .../checking/access_specifiers/access_ok.exp | 20 +- .../acquires_list_generic.exp | 6 +- .../tests/checking/dotdot/dotdot_valid.exp | 22 +- .../tests/checking/indexing/examples_book.exp | 2 +- .../tests/checking/inlining/lambda3.exp | 24 + .../tests/checking/inlining/lambda3.move | 99 ++++ .../tests/checking/inlining/lambda4.exp | 13 + .../tests/checking/inlining/lambda4.move | 99 ++++ .../tests/checking/inlining/lambda5.exp | 7 + .../tests/checking/inlining/lambda5.move | 99 ++++ .../checking/inlining/non_lambda_arg.exp | 4 +- .../checking/inlining/resources_valid.exp | 4 +- .../naming/duplicate_acquires_list_item.exp | 16 +- .../global_builtin_one_type_argument.exp | 2 +- .../naming/unused_type_parameter_struct.exp | 20 +- .../checking/naming/warning_dependency.exp | 20 +- .../positional_fields/assign_field.exp | 10 +- .../bind_anonymous_field.exp | 6 +- .../checking/positional_fields/decl_ok.exp | 6 +- .../named_tuple_ability_decl_ok.exp | 20 +- .../named_tuple_construct_ok.exp | 8 +- .../variant_ability_decl_ok.exp | 8 +- .../tests/checking/receiver/decl_errors.exp | 6 +- .../tests/checking/receiver/generic_calls.exp | 4 +- .../checking/receiver/generic_calls_typed.exp | 4 +- .../checking/specs/intrinsic_decl_ok.exp | 4 +- .../tests/checking/specs/invariants_ok.exp | 2 +- .../specs/move_function_in_spec_ok.exp | 2 +- .../tests/checking/specs/schemas_ok.exp | 4 +- .../tests/checking/specs/structs_ok.exp | 6 +- .../checking/typing/borrow_field_chain.exp | 4 +- .../typing/decl_unpack_references.exp | 4 +- .../tests/checking/typing/derefrence.exp | 2 +- .../tests/checking/typing/dummy_field.exp | 4 +- .../tests/checking/typing/eq.exp | 4 +- .../tests/checking/typing/exp_list.exp | 4 +- .../tests/checking/typing/global_builtins.exp | 4 +- .../typing/global_builtins_inferred.exp | 2 +- .../implicit_deref_borrow_field_chain.exp | 4 +- .../tests/checking/typing/lambda.exp | 8 + .../tests/checking/typing/lambda.move | 11 +- .../tests/checking/typing/lambda2.exp | 25 + .../tests/checking/typing/lambda2.move | 99 ++++ .../tests/checking/typing/lambda3.exp | 24 + .../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 + .../tests/checking/typing/lambda_typed.exp | 8 + .../typing/main_arguments_various_caes.exp | 4 +- .../typing/move_from_type_argument.exp | 2 +- .../checking/typing/mutable_eq_and_neq.exp | 4 +- .../tests/checking/typing/neq.exp | 4 +- .../checking/typing/nested_post_process.exp | 10 +- .../typing/phantom_param_struct_decl.exp | 20 +- .../typing/type_variable_join_single_pack.exp | 6 +- .../type_variable_join_single_unpack.exp | 6 +- ...ype_variable_join_single_unpack_assign.exp | 6 +- .../type_variable_join_threaded_pack.exp | 10 +- .../multi_pool_money_market_token.exp | 52 +- .../v1-examples/simple_money_market_token.exp | 46 +- .../variants_test_no_parenthesis_ok.exp | 4 +- .../checking/variants/variants_test_ok.exp | 4 +- ...mutually_recursive_non_generic_type_ok.exp | 4 +- .../infinite_instantiations_valid.exp | 4 +- .../tests/lambda-lifting/basic.exp | 258 ++++++++++ .../tests/lambda-lifting/modify.exp | 457 ++++++++++++++++++ .../tests/lambda-lifting/nested.exp | 180 +++++++ .../tests/lambda-lifting/pattern.exp | 224 ++++++++- .../parser/spec_parsing_fun_type_fail.exp | 2 +- .../tests/op-equal/valid0.exp | 6 +- .../tests/op-equal/valid1.exp | 6 +- .../assign_unpack_references.exp | 4 +- .../move/move-compiler-v2/tests/testsuite.rs | 17 +- .../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 | 24 + .../tests/move_check/typing/lambda2.move | 99 ++++ .../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 | 6 + .../typing/lambda_returning_lambda2.move | 12 + .../move-model/src/builder/model_builder.rs | 5 +- .../move-model/src/builder/module_builder.rs | 15 +- third_party/move/move-model/src/model.rs | 73 ++- third_party/move/move-model/src/ty.rs | 59 ++- 118 files changed, 2740 insertions(+), 425 deletions(-) create mode 100644 third_party/move/move-compiler-v2/tests/checking/inlining/lambda3.exp create mode 100644 third_party/move/move-compiler-v2/tests/checking/inlining/lambda3.move create mode 100644 third_party/move/move-compiler-v2/tests/checking/inlining/lambda4.exp create mode 100644 third_party/move/move-compiler-v2/tests/checking/inlining/lambda4.move create mode 100644 third_party/move/move-compiler-v2/tests/checking/inlining/lambda5.exp create mode 100644 third_party/move/move-compiler-v2/tests/checking/inlining/lambda5.move create mode 100644 third_party/move/move-compiler-v2/tests/checking/typing/lambda2.exp create mode 100644 third_party/move/move-compiler-v2/tests/checking/typing/lambda2.move 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/lambda2.exp create mode 100644 third_party/move/move-compiler/tests/move_check/typing/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-bytecode-verifier/transactional-tests/tests/type_safety/gerbens_test.exp b/third_party/move/move-bytecode-verifier/transactional-tests/tests/type_safety/gerbens_test.exp index 21191ffa107a6..739b14b80441d 100644 --- a/third_party/move/move-bytecode-verifier/transactional-tests/tests/type_safety/gerbens_test.exp +++ b/third_party/move/move-bytecode-verifier/transactional-tests/tests/type_safety/gerbens_test.exp @@ -5,6 +5,6 @@ Error: error[E04024]: invalid usage of function type ┌─ TEMPFILE:9:62 │ 9 │ public fun for_each_ref(v: &vector, f: |&Element|) { - │ ^^^^^^^^^^ 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-v2/src/bytecode_generator.rs b/third_party/move/move-compiler-v2/src/bytecode_generator.rs index 16248e056d369..2b024cb47991d 100644 --- a/third_party/move/move-compiler-v2/src/bytecode_generator.rs +++ b/third_party/move/move-compiler-v2/src/bytecode_generator.rs @@ -406,9 +406,12 @@ impl<'env> Generator<'env> { ), ); } - self.emit_call(*id, targets, BytecodeOperation::WriteRef, vec![ - lhs_temp, rhs_temp, - ]) + self.emit_call( + *id, + targets, + BytecodeOperation::WriteRef, + vec![lhs_temp, rhs_temp], + ) }, ExpData::Assign(id, lhs, rhs) => self.gen_assign(*id, lhs, rhs, None), ExpData::Return(id, exp) => { @@ -479,9 +482,16 @@ impl<'env> Generator<'env> { .rewrite_spec_descent(&SpecBlockTarget::Inline, spec); self.emit_with(*id, |attr| Bytecode::SpecBlock(attr, spec)); }, - ExpData::Invoke(id, _, _) | ExpData::Lambda(id, _, _) => { - self.internal_error(*id, format!("not yet implemented: {:?}", exp)) - }, + // TODO(LAMBDA) + ExpData::Lambda(id, _, _) => self.error( + *id, + "Function-typed values not yet supported except as parameters to calls to inline functions", + ), + // TODO(LAMBDA) + ExpData::Invoke(_, exp, _) => self.error( + exp.as_ref().node_id(), + "Calls to function values other than inline function parameters not yet supported", + ), ExpData::Quant(id, _, _, _, _, _) => { self.internal_error(*id, "unsupported specification construct") }, @@ -806,7 +816,11 @@ impl<'env> Generator<'env> { Operation::NoOp => {}, // do nothing - Operation::Closure(..) => self.internal_error(id, "closure not yet implemented"), + // TODO(LAMBDA) + Operation::Closure(..) => self.error( + id, + "Function-typed values not yet supported except as parameters to calls to inline functions", + ), // Non-supported specification related operations Operation::Exists(Some(_)) 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 57a9976ed3635..d7dbcc3cfce2b 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 @@ -3,55 +3,180 @@ //! Do a few checks of functions and function calls. -use crate::Options; +use crate::{experiments::Experiment, Options}; 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. +// 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_types: Vec) -> Vec { + func_types + .into_iter() + .filter_map(|ty| { + if let Type::Fun(argt, _) = &ty { + if argt.deref().has_function() { + 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( + func_types: Vec<&Parameter>, +) -> Vec<(&Parameter, &Type)> { + func_types + .iter() + .filter_map(|param| { + if let Type::Fun(_argt, rest) = ¶m.1 { + let rest_unboxed = rest.deref(); + if rest_unboxed.has_function() { + 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_IN_PARAMS); + let lambda_return_ok = options.experiment_on(Experiment::LAMBDA_IN_RETURNS); + if lambda_params_ok && lambda_return_ok { + return; + } + for caller_module in env.get_modules() { if caller_module.is_primary_target() { for caller_func in caller_module.get_functions() { - // Check that non-inline function parameters don't have function type - if !caller_func.is_inline() { - let parameters = caller_func.get_parameters(); - let bad_params: Vec<_> = parameters + 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 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 && !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)), + ) + } + } + } + + 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 caller_name = caller_func.get_full_name_str(); - let reasons: Vec<(Loc, String)> = bad_params - .iter() - .map(|param| { - ( - param.2.clone(), - format!( - "Parameter `{}` has a function type.", - param.0.display(env.symbol_pool()), + 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/env_pipeline/lambda_lifter.rs b/third_party/move/move-compiler-v2/src/env_pipeline/lambda_lifter.rs index cb11736440a66..8326c3e8af618 100644 --- a/third_party/move/move-compiler-v2/src/env_pipeline/lambda_lifter.rs +++ b/third_party/move/move-compiler-v2/src/env_pipeline/lambda_lifter.rs @@ -309,7 +309,7 @@ impl<'a> ExpRewriterFunctions for LambdaLifter<'a> { env.error( &loc, &format!( - "captured variable `{}` cannot be modified inside of a lambda", + "captured variable `{}` cannot be modified inside of a lambda", // TODO(LAMBDA) name.display(env.symbol_pool()) ), ); @@ -327,7 +327,7 @@ impl<'a> ExpRewriterFunctions for LambdaLifter<'a> { env.error( &loc, &format!( - "captured variable `{}` cannot be modified inside of a lambda", + "captured variable `{}` cannot be modified inside of a lambda", // TODO(LAMBDA) name.display(env.symbol_pool()) ), ); diff --git a/third_party/move/move-compiler-v2/src/env_pipeline/recursive_struct_checker.rs b/third_party/move/move-compiler-v2/src/env_pipeline/recursive_struct_checker.rs index 29c5a6b299bca..9f4d51838ff56 100644 --- a/third_party/move/move-compiler-v2/src/env_pipeline/recursive_struct_checker.rs +++ b/third_party/move/move-compiler-v2/src/env_pipeline/recursive_struct_checker.rs @@ -101,7 +101,7 @@ impl<'a> RecursiveStructChecker<'a> { self.report_invalid_field(&struct_env, &field_env); } }, - Type::Primitive(_) | Type::TypeParameter(_) => {}, + Type::Primitive(_) | Type::TypeParameter(_) | Type::Fun(..) => {}, _ => unreachable!("invalid field type"), } path.pop(); @@ -195,7 +195,7 @@ impl<'a> RecursiveStructChecker<'a> { .iter() .any(|ty| self.ty_contains_struct(path, ty, loc.clone(), struct_id, checked)) }, - Type::Primitive(_) | Type::TypeParameter(_) => false, + Type::Primitive(_) | Type::TypeParameter(_) | Type::Fun(..) => false, _ => panic!("ICE: {:?} used as a type parameter", ty), } } diff --git a/third_party/move/move-compiler-v2/src/env_pipeline/unused_params_checker.rs b/third_party/move/move-compiler-v2/src/env_pipeline/unused_params_checker.rs index 276b8dc3d675c..e9da0d5cbb053 100644 --- a/third_party/move/move-compiler-v2/src/env_pipeline/unused_params_checker.rs +++ b/third_party/move/move-compiler-v2/src/env_pipeline/unused_params_checker.rs @@ -55,12 +55,16 @@ fn used_type_parameters_in_fields(struct_env: &StructEnv) -> BTreeSet { fn used_type_parameters_in_ty(ty: &Type) -> BTreeSet { match ty { Type::Primitive(_) => BTreeSet::new(), - Type::Struct(_, _, tys) => tys.iter().flat_map(used_type_parameters_in_ty).collect(), + Type::Tuple(tys) | Type::Struct(_, _, tys) => { + tys.iter().flat_map(used_type_parameters_in_ty).collect() + }, Type::TypeParameter(i) => BTreeSet::from([*i]), Type::Vector(ty) => used_type_parameters_in_ty(ty), + Type::Fun(t1, t2) => [t1, t2] + .iter() + .flat_map(|t| used_type_parameters_in_ty(t)) + .collect(), Type::Reference(..) - | Type::Fun(..) - | Type::Tuple(..) | Type::TypeDomain(..) | Type::ResourceDomain(..) | Type::Error diff --git a/third_party/move/move-compiler-v2/src/experiments.rs b/third_party/move/move-compiler-v2/src/experiments.rs index d7bdf7820c00e..ceea7b65d8403 100644 --- a/third_party/move/move-compiler-v2/src/experiments.rs +++ b/third_party/move/move-compiler-v2/src/experiments.rs @@ -111,11 +111,32 @@ pub static EXPERIMENTS: Lazy> = Lazy::new(|| { description: "Turns on or off specification rewriting".to_string(), default: Given(false), }, + Experiment { + name: Experiment::LAMBDA_FIELDS.to_string(), + description: "Turns on or off function values in struct fields".to_string(), + default: Given(false), + }, Experiment { name: Experiment::LAMBDA_LIFTING.to_string(), description: "Turns on or off lambda lifting".to_string(), default: Given(false), }, + Experiment { + 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_IN_RETURNS.to_string(), + description: "Turns on or off function values in function return values".to_string(), + default: Given(false), + }, + Experiment { + name: Experiment::LAMBDA_VALUES.to_string(), + description: "Turns on or off first-class function values".to_string(), + default: Given(false), + }, Experiment { name: Experiment::RECURSIVE_TYPE_CHECK.to_string(), description: "Turns on or off checking of recursive structs and type instantiations" @@ -275,7 +296,11 @@ impl Experiment { pub const INLINING: &'static str = "inlining"; 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_VALUES: &'static str = "lambda-values"; pub const LINT_CHECKS: &'static str = "lint-checks"; pub const OPTIMIZE: &'static str = "optimize"; pub const OPTIMIZE_EXTRA: &'static str = "optimize-extra"; diff --git a/third_party/move/move-compiler-v2/src/file_format_generator/module_generator.rs b/third_party/move/move-compiler-v2/src/file_format_generator/module_generator.rs index 4fd794aca6c6b..483020e61a99e 100644 --- a/third_party/move/move-compiler-v2/src/file_format_generator/module_generator.rs +++ b/third_party/move/move-compiler-v2/src/file_format_generator/module_generator.rs @@ -365,7 +365,18 @@ impl ModuleGenerator { ReferenceKind::Mutable => FF::SignatureToken::MutableReference(target_ty), } }, - Fun(_, _) | TypeDomain(_) | ResourceDomain(_, _, _) | Error | Var(_) => { + Fun(_param_ty, _result_ty) => { + // TODO(LAMBDA) + ctx.error( + loc, + format!( + "Unexpected type: {}", + ty.display(&ctx.env.get_type_display_ctx()) + ), + ); + FF::SignatureToken::Bool + }, + TypeDomain(_) | ResourceDomain(_, _, _) | Error | Var(_) => { ctx.internal_error( loc, format!( diff --git a/third_party/move/move-compiler-v2/tests/bytecode-generator/assign.exp b/third_party/move/move-compiler-v2/tests/bytecode-generator/assign.exp index deeab73004ab4..19a38d4478a92 100644 --- a/third_party/move/move-compiler-v2/tests/bytecode-generator/assign.exp +++ b/third_party/move/move-compiler-v2/tests/bytecode-generator/assign.exp @@ -5,7 +5,7 @@ module 0x42::assign { } struct S { f: u64, - g: 0x42::assign::T, + g: T, } private fun assign_field(s: &mut S,f: u64) { select assign::S.f<&mut S>(s) = f; diff --git a/third_party/move/move-compiler-v2/tests/bytecode-generator/borrow_deref_optimize.exp b/third_party/move/move-compiler-v2/tests/bytecode-generator/borrow_deref_optimize.exp index ae6515bb0501c..bc23929966e0e 100644 --- a/third_party/move/move-compiler-v2/tests/bytecode-generator/borrow_deref_optimize.exp +++ b/third_party/move/move-compiler-v2/tests/bytecode-generator/borrow_deref_optimize.exp @@ -4,7 +4,7 @@ module 0x42::test { value: bool, } private fun no_optimize_resource(): bool - acquires 0x42::test::X(*) + acquires X(*) { { let x: &mut X = Borrow(Mutable)(Deref(BorrowGlobal(Immutable)(0x1))); @@ -18,7 +18,7 @@ module 0x42::test { } } private fun optimize_resource(): bool - acquires 0x42::test::X(*) + acquires X(*) { { let x: &X = Borrow(Immutable)(Deref(BorrowGlobal(Immutable)(0x1))); diff --git a/third_party/move/move-compiler-v2/tests/bytecode-generator/bug_14471_receiver_inference.exp b/third_party/move/move-compiler-v2/tests/bytecode-generator/bug_14471_receiver_inference.exp index e89103eda02a7..693daacb1ff71 100644 --- a/third_party/move/move-compiler-v2/tests/bytecode-generator/bug_14471_receiver_inference.exp +++ b/third_party/move/move-compiler-v2/tests/bytecode-generator/bug_14471_receiver_inference.exp @@ -1,11 +1,11 @@ // -- Model dump before bytecode pipeline module 0x815::m { struct MyMap { - table: 0x815::m::Table, + table: Table, } - struct Table { - x: #0, - y: #1, + struct Table { + x: T1, + y: T2, } struct ValueWrap { val: u64, @@ -17,7 +17,7 @@ module 0x815::m { Tuple() } public fun add_when_missing(key: address,val: u64) - acquires 0x815::m::MyMap(*) + acquires MyMap(*) { { let my_map: &mut MyMap = BorrowGlobal(Mutable)(0x815); diff --git a/third_party/move/move-compiler-v2/tests/bytecode-generator/escape_autoref.exp b/third_party/move/move-compiler-v2/tests/bytecode-generator/escape_autoref.exp index 9b8e310000ede..aae0dcbebfe42 100644 --- a/third_party/move/move-compiler-v2/tests/bytecode-generator/escape_autoref.exp +++ b/third_party/move/move-compiler-v2/tests/bytecode-generator/escape_autoref.exp @@ -10,7 +10,7 @@ module 0x42::m { Abort(0) } private fun owner_correct(o: Object): address - acquires 0x42::m::ObjectCore(*) + acquires ObjectCore(*) { { let addr: address = select m::Object.inner(o); @@ -18,7 +18,7 @@ module 0x42::m { } } private fun owner_read_ref_missing(o: Object): address - acquires 0x42::m::ObjectCore(*) + acquires ObjectCore(*) { select m::ObjectCore.owner<&ObjectCore>(BorrowGlobal(Immutable)(select m::Object.inner(o))) } diff --git a/third_party/move/move-compiler-v2/tests/bytecode-generator/fields.exp b/third_party/move/move-compiler-v2/tests/bytecode-generator/fields.exp index 8806b10eaaeaf..72ad2c417ca09 100644 --- a/third_party/move/move-compiler-v2/tests/bytecode-generator/fields.exp +++ b/third_party/move/move-compiler-v2/tests/bytecode-generator/fields.exp @@ -3,12 +3,12 @@ module 0x42::fields { struct T { h: u64, } - struct G { - f: #0, + struct G { + f: X, } struct S { f: u64, - g: 0x42::fields::T, + g: T, } private fun read_generic_val(x: G): u64 { select fields::G.f>(x) diff --git a/third_party/move/move-compiler-v2/tests/bytecode-generator/fields_invalid.exp b/third_party/move/move-compiler-v2/tests/bytecode-generator/fields_invalid.exp index 4911ab49100bf..91fc860a9e2da 100644 --- a/third_party/move/move-compiler-v2/tests/bytecode-generator/fields_invalid.exp +++ b/third_party/move/move-compiler-v2/tests/bytecode-generator/fields_invalid.exp @@ -5,7 +5,7 @@ module 0x42::fields { } struct S { f: u64, - g: 0x42::fields::T, + g: T, } private fun write_ref(x: &S) { select fields::T.h(select fields::S.g<&S>(x)) = 42; diff --git a/third_party/move/move-compiler-v2/tests/bytecode-generator/globals.exp b/third_party/move/move-compiler-v2/tests/bytecode-generator/globals.exp index 60f8155f1393d..58f17e58316dc 100644 --- a/third_party/move/move-compiler-v2/tests/bytecode-generator/globals.exp +++ b/third_party/move/move-compiler-v2/tests/bytecode-generator/globals.exp @@ -19,7 +19,7 @@ module 0x42::globals { Tuple() } private fun read(a: address): u64 - acquires 0x42::globals::R(*) + acquires R(*) { { let r: &R = BorrowGlobal(Immutable)(a); @@ -27,7 +27,7 @@ module 0x42::globals { } } private fun write(a: address,x: u64): u64 - acquires 0x42::globals::R(*) + acquires R(*) { { let r: &mut R = BorrowGlobal(Mutable)(a); diff --git a/third_party/move/move-compiler-v2/tests/bytecode-generator/matching_ability_err.exp b/third_party/move/move-compiler-v2/tests/bytecode-generator/matching_ability_err.exp index a3dfa3d3f7cab..06001c73b254d 100644 --- a/third_party/move/move-compiler-v2/tests/bytecode-generator/matching_ability_err.exp +++ b/third_party/move/move-compiler-v2/tests/bytecode-generator/matching_ability_err.exp @@ -15,11 +15,11 @@ module 0xc0ffee::m { enum Outer { None, One { - i: 0xc0ffee::m::Inner, + i: Inner, } Two { - i: 0xc0ffee::m::Inner, - b: 0xc0ffee::m::Box, + i: Inner, + b: Box, } } public fun condition_requires_copy(o: Outer): Outer { diff --git a/third_party/move/move-compiler-v2/tests/bytecode-generator/matching_coverage_err.exp b/third_party/move/move-compiler-v2/tests/bytecode-generator/matching_coverage_err.exp index 805678cbb5cf7..cebf2819486bb 100644 --- a/third_party/move/move-compiler-v2/tests/bytecode-generator/matching_coverage_err.exp +++ b/third_party/move/move-compiler-v2/tests/bytecode-generator/matching_coverage_err.exp @@ -15,11 +15,11 @@ module 0xc0ffee::m { enum Outer { None, One { - i: 0xc0ffee::m::Inner, + i: Inner, } Two { - i: 0xc0ffee::m::Inner, - b: 0xc0ffee::m::Box, + i: Inner, + b: Box, } } public fun exhaustive_tuple(i: &Inner) { diff --git a/third_party/move/move-compiler-v2/tests/bytecode-generator/matching_ok.exp b/third_party/move/move-compiler-v2/tests/bytecode-generator/matching_ok.exp index c7116654488be..a49fde8a4b9a3 100644 --- a/third_party/move/move-compiler-v2/tests/bytecode-generator/matching_ok.exp +++ b/third_party/move/move-compiler-v2/tests/bytecode-generator/matching_ok.exp @@ -39,20 +39,20 @@ module 0xc0ffee::m { y: u64, } } - enum Option { + enum Option { None, Some { - value: #0, + value: A, } } enum Outer { None, One { - i: 0xc0ffee::m::Inner, + i: Inner, } Two { - i: 0xc0ffee::m::Inner, - b: 0xc0ffee::m::Box, + i: Inner, + b: Box, } } public fun inner_value(self: Inner): u64 { diff --git a/third_party/move/move-compiler-v2/tests/bytecode-generator/mutate_immutable_cmp.exp b/third_party/move/move-compiler-v2/tests/bytecode-generator/mutate_immutable_cmp.exp index f78da5ffeca47..bd21055b8ac2e 100644 --- a/third_party/move/move-compiler-v2/tests/bytecode-generator/mutate_immutable_cmp.exp +++ b/third_party/move/move-compiler-v2/tests/bytecode-generator/mutate_immutable_cmp.exp @@ -1,7 +1,7 @@ // -- Model dump before bytecode pipeline module 0x8675309::M { struct T { - s: 0x8675309::M::S, + s: S, } struct G { dummy_field: bool, diff --git a/third_party/move/move-compiler-v2/tests/bytecode-generator/pack_unpack.exp b/third_party/move/move-compiler-v2/tests/bytecode-generator/pack_unpack.exp index 50897a53c5ba0..17e454f6177ee 100644 --- a/third_party/move/move-compiler-v2/tests/bytecode-generator/pack_unpack.exp +++ b/third_party/move/move-compiler-v2/tests/bytecode-generator/pack_unpack.exp @@ -5,7 +5,7 @@ module 0x42::pack_unpack { } struct S { f: u64, - g: 0x42::pack_unpack::T, + g: T, } private fun pack(x: u64,y: u64): S { pack pack_unpack::S(x, pack pack_unpack::T(y)) diff --git a/third_party/move/move-compiler-v2/tests/bytecode-generator/spec_construct.exp b/third_party/move/move-compiler-v2/tests/bytecode-generator/spec_construct.exp index 906f7604749fa..6108d5abdaa96 100644 --- a/third_party/move/move-compiler-v2/tests/bytecode-generator/spec_construct.exp +++ b/third_party/move/move-compiler-v2/tests/bytecode-generator/spec_construct.exp @@ -5,7 +5,7 @@ module 0x42::m { k: u8, } struct S { - data: vector<0x42::m::E>, + data: vector, } public fun foo(v: &S): u8 { select m::E.k<&E>(vector::borrow(Borrow(Immutable)(select m::S.data<&S>(v)), 0)) diff --git a/third_party/move/move-compiler-v2/tests/checking-lang-v1/use_struct_overlap_with_module.exp b/third_party/move/move-compiler-v2/tests/checking-lang-v1/use_struct_overlap_with_module.exp index e9e0328eb51f1..e554327c1f4f0 100644 --- a/third_party/move/move-compiler-v2/tests/checking-lang-v1/use_struct_overlap_with_module.exp +++ b/third_party/move/move-compiler-v2/tests/checking-lang-v1/use_struct_overlap_with_module.exp @@ -7,8 +7,8 @@ module 0x2::X { module 0x2::M { use 0x2::X::{Self, S as X}; // resolved as: 0x2::X struct A { - f1: 0x2::X::S, - f2: 0x2::X::S, + f1: X::S, + f2: X::S, } } // end 0x2::M diff --git a/third_party/move/move-compiler-v2/tests/checking/abilities/v1/ability_constraints.exp b/third_party/move/move-compiler-v2/tests/checking/abilities/v1/ability_constraints.exp index dcaf90f90259f..f749653a7f251 100644 --- a/third_party/move/move-compiler-v2/tests/checking/abilities/v1/ability_constraints.exp +++ b/third_party/move/move-compiler-v2/tests/checking/abilities/v1/ability_constraints.exp @@ -1,11 +1,11 @@ // -- Model dump before bytecode pipeline module 0x42::M { - struct Box { - f: #0, + struct Box { + f: T, } - struct Pair { - f1: #0, - f2: #1, + struct Pair { + f1: T1, + f2: T2, } struct R { dummy_field: bool, @@ -13,22 +13,22 @@ module 0x42::M { struct S { dummy_field: bool, } - struct Sc { + struct Sc { dummy_field: bool, } - struct Scds { + struct Scds { dummy_field: bool, } - struct Sd { + struct Sd { dummy_field: bool, } - struct Sk { + struct Sk { dummy_field: bool, } - struct Ss { + struct Ss { dummy_field: bool, } - struct Ssk { + struct Ssk { dummy_field: bool, } private fun c() { diff --git a/third_party/move/move-compiler-v2/tests/checking/abilities/v1/phantom_param_op_abilities.exp b/third_party/move/move-compiler-v2/tests/checking/abilities/v1/phantom_param_op_abilities.exp index 21ea211538722..0e83fb52e54e8 100644 --- a/third_party/move/move-compiler-v2/tests/checking/abilities/v1/phantom_param_op_abilities.exp +++ b/third_party/move/move-compiler-v2/tests/checking/abilities/v1/phantom_param_op_abilities.exp @@ -1,22 +1,22 @@ // -- Model dump before bytecode pipeline module 0x42::M { - struct HasCopy { - a: #1, + struct HasCopy { + a: T2, } - struct HasDrop { - a: #1, + struct HasDrop { + a: T2, } - struct HasKey { - a: #1, + struct HasKey { + a: T2, } - struct HasStore { - a: #1, + struct HasStore { + a: T2, } struct NoAbilities { dummy_field: bool, } - struct RequireStore { - a: #0, + struct RequireStore { + a: T, } private fun f1(ref: &mut HasDrop) { ref = pack M::HasDrop(1); @@ -37,7 +37,7 @@ module 0x42::M { Tuple() } private fun f6(): HasKey - acquires 0x42::M::HasKey(*) + acquires HasKey(*) { MoveFrom>(0x0) } diff --git a/third_party/move/move-compiler-v2/tests/checking/abilities/v1/phantom_params_constraint_abilities.exp b/third_party/move/move-compiler-v2/tests/checking/abilities/v1/phantom_params_constraint_abilities.exp index 5666042391855..ff67e3db96804 100644 --- a/third_party/move/move-compiler-v2/tests/checking/abilities/v1/phantom_params_constraint_abilities.exp +++ b/third_party/move/move-compiler-v2/tests/checking/abilities/v1/phantom_params_constraint_abilities.exp @@ -1,37 +1,37 @@ // -- Model dump before bytecode pipeline module 0x42::M { - struct HasAbilities { - a: #1, + struct HasAbilities { + a: T2, } - struct HasCopy { - a: #1, + struct HasCopy { + a: T2, } - struct HasDrop { - a: #1, + struct HasDrop { + a: T2, } - struct HasKey { - a: #1, + struct HasKey { + a: T2, } - struct HasStore { - a: #1, + struct HasStore { + a: T2, } struct NoAbilities { a: bool, } - struct S1 { - a: #0, + struct S1 { + a: T, } struct S2 { - a: 0x42::M::S1<0x42::M::HasAbilities<0x42::M::NoAbilities, u64>>, + a: S1>, } - struct S3 { - a: #0, - b: #1, - c: #2, - d: #3, + struct S3 { + a: T1, + b: T2, + c: T3, + d: T4, } struct S4 { - a: 0x42::M::S3<0x42::M::HasDrop<0x42::M::NoAbilities, u64>, 0x42::M::HasCopy<0x42::M::NoAbilities, u64>, 0x42::M::HasStore<0x42::M::NoAbilities, u64>, 0x42::M::HasKey<0x42::M::NoAbilities, u64>>, + a: S3, HasCopy, HasStore, HasKey>, } private fun f1() { Tuple() diff --git a/third_party/move/move-compiler-v2/tests/checking/abilities/v1/phantom_params_field_abilities.exp b/third_party/move/move-compiler-v2/tests/checking/abilities/v1/phantom_params_field_abilities.exp index c9c9943eb3973..b7bc1372321de 100644 --- a/third_party/move/move-compiler-v2/tests/checking/abilities/v1/phantom_params_field_abilities.exp +++ b/third_party/move/move-compiler-v2/tests/checking/abilities/v1/phantom_params_field_abilities.exp @@ -1,31 +1,31 @@ // -- Model dump before bytecode pipeline module 0x42::M { - struct HasCopy { - a: #1, + struct HasCopy { + a: T2, } - struct HasDrop { - a: #1, + struct HasDrop { + a: T2, } - struct HasKey { - a: #1, + struct HasKey { + a: T2, } - struct HasStore { - a: #1, + struct HasStore { + a: T2, } struct NoAbilities { dummy_field: bool, } struct S1 { - a: 0x42::M::HasDrop<0x42::M::NoAbilities, u64>, + a: HasDrop, } struct S2 { - a: 0x42::M::HasCopy<0x42::M::NoAbilities, u64>, + a: HasCopy, } struct S3 { - a: 0x42::M::HasStore<0x42::M::NoAbilities, u64>, + a: HasStore, } struct S4 { - a: 0x42::M::HasStore<0x42::M::NoAbilities, u64>, + a: HasStore, } } // end 0x42::M diff --git a/third_party/move/move-compiler-v2/tests/checking/access_specifiers/access_ok.exp b/third_party/move/move-compiler-v2/tests/checking/access_specifiers/access_ok.exp index 6482442cfa288..8298da9baae10 100644 --- a/third_party/move/move-compiler-v2/tests/checking/access_specifiers/access_ok.exp +++ b/third_party/move/move-compiler-v2/tests/checking/access_specifiers/access_ok.exp @@ -23,7 +23,7 @@ module 0x42::m { struct T { dummy_field: bool, } - struct G { + struct G { dummy_field: bool, } struct R { @@ -33,7 +33,7 @@ module 0x42::m { dummy_field: bool, } private fun f1() - acquires 0x42::m::S(*) + acquires S(*) { Tuple() } @@ -53,17 +53,17 @@ module 0x42::m { Tuple() } private fun f2() - reads 0x42::m::S(*) + reads S(*) { Tuple() } private fun f3() - writes 0x42::m::S(*) + writes S(*) { Tuple() } private fun f4() - acquires 0x42::m::S(*) + acquires S(*) { Tuple() } @@ -93,11 +93,11 @@ module 0x42::m { Tuple() } private fun f_multiple() - acquires 0x42::m::R(*) - reads 0x42::m::R(*) - writes 0x42::m::T(*) - writes 0x42::m::S(*) - reads 0x42::m::G(*) + acquires R(*) + reads R(*) + writes T(*) + writes S(*) + reads G(*) { Tuple() } diff --git a/third_party/move/move-compiler-v2/tests/checking/access_specifiers/acquires_list_generic.exp b/third_party/move/move-compiler-v2/tests/checking/access_specifiers/acquires_list_generic.exp index 1c78e50c8f0b2..82e8a78a2518a 100644 --- a/third_party/move/move-compiler-v2/tests/checking/access_specifiers/acquires_list_generic.exp +++ b/third_party/move/move-compiler-v2/tests/checking/access_specifiers/acquires_list_generic.exp @@ -1,16 +1,16 @@ // -- Model dump before bytecode pipeline module 0x42::M { - struct B { + struct B { dummy_field: bool, } - struct CupC { + struct CupC { dummy_field: bool, } struct R { dummy_field: bool, } private fun foo() - acquires 0x42::M::B<0x42::M::CupC<0x42::M::R>>(*) + acquires B>(*) { Abort(0) } diff --git a/third_party/move/move-compiler-v2/tests/checking/dotdot/dotdot_valid.exp b/third_party/move/move-compiler-v2/tests/checking/dotdot/dotdot_valid.exp index 8de9c715617c4..6b25517efe372 100644 --- a/third_party/move/move-compiler-v2/tests/checking/dotdot/dotdot_valid.exp +++ b/third_party/move/move-compiler-v2/tests/checking/dotdot/dotdot_valid.exp @@ -10,7 +10,7 @@ module 0x42::test { } C { x: u8, - y: 0x42::test::S1, + y: S1, } } struct S0 { @@ -21,23 +21,23 @@ module 0x42::test { } struct S2 { 0: bool, - 1: 0x42::test::S0, + 1: S0, } struct S3 { x: bool, y: u8, } - struct S4 { - x: #0, - y: 0x42::test::S3, + struct S4 { + x: T, + y: S3, } - struct S5 { - 0: #0, - 1: #1, + struct S5 { + 0: T, + 1: U, } - struct S6 { - x: #0, - y: #1, + struct S6 { + x: T, + y: U, } struct S7 { 0: u8, diff --git a/third_party/move/move-compiler-v2/tests/checking/indexing/examples_book.exp b/third_party/move/move-compiler-v2/tests/checking/indexing/examples_book.exp index 225201e7eb6d2..979ec749c6216 100644 --- a/third_party/move/move-compiler-v2/tests/checking/indexing/examples_book.exp +++ b/third_party/move/move-compiler-v2/tests/checking/indexing/examples_book.exp @@ -4,7 +4,7 @@ module 0x1::m { value: bool, } private fun f1() - acquires 0x1::m::R(*) + acquires R(*) { { let x: &mut R = BorrowGlobal(Mutable)(0x1); diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/lambda3.exp b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda3.exp new file mode 100644 index 0000000000000..7d3fd078fd386 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda3.exp @@ -0,0 +1,24 @@ +// -- 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 + +// -- Sourcified model before bytecode pipeline +module 0x8675309::M { + public fun lambda_not_allowed() { + let _x = |i| i + 1; + } +} + + +Diagnostics: +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/checking/inlining/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/inlining/lambda3.move b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda3.move new file mode 100644 index 0000000000000..5450bac87c1cb --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/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/checking/inlining/lambda4.exp b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda4.exp new file mode 100644 index 0000000000000..14e896bb69ca5 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/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/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 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/lambda4.move b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda4.move new file mode 100644 index 0000000000000..4a378b7e14b10 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/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/checking/inlining/lambda5.exp b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda5.exp new file mode 100644 index 0000000000000..78669969275c4 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/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/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/inlining/lambda5.move b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda5.move new file mode 100644 index 0000000000000..291c8e5cab61f --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/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/checking/inlining/non_lambda_arg.exp b/third_party/move/move-compiler-v2/tests/checking/inlining/non_lambda_arg.exp index aa83fbc21a0bd..88cfe01e12e08 100644 --- a/third_party/move/move-compiler-v2/tests/checking/inlining/non_lambda_arg.exp +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/non_lambda_arg.exp @@ -4,10 +4,10 @@ error: Only inline functions may have function-typed parameters, but non-inline ┌─ tests/checking/inlining/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 a function type. + │ ^^^^^^^^^^^^^^ -------- 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/checking/inlining/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 a function type. + │ ^^^^^^^^^^^^^^^^^^^^^^^^ -------- Parameter `a_less_b` has function-valued type `|(T, T)|bool`. diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/resources_valid.exp b/third_party/move/move-compiler-v2/tests/checking/inlining/resources_valid.exp index 1a3c18119c4dd..36dc07fcb1f05 100644 --- a/third_party/move/move-compiler-v2/tests/checking/inlining/resources_valid.exp +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/resources_valid.exp @@ -1,6 +1,6 @@ // -- Model dump before bytecode pipeline module 0x42::objects { - struct ReaderRef { + struct ReaderRef { addr: address, } public fun get_addr(ref: &ReaderRef): address { @@ -16,7 +16,7 @@ module 0x42::token { val: u64, } public fun get_value(ref: &objects::ReaderRef): u64 - acquires 0x42::token::Token(*) + acquires Token(*) { select token::Token.val<&Token>({ let (ref: &objects::ReaderRef): (&objects::ReaderRef) = Tuple(ref); diff --git a/third_party/move/move-compiler-v2/tests/checking/naming/duplicate_acquires_list_item.exp b/third_party/move/move-compiler-v2/tests/checking/naming/duplicate_acquires_list_item.exp index e09b6408ae260..3a1b5c04d51a4 100644 --- a/third_party/move/move-compiler-v2/tests/checking/naming/duplicate_acquires_list_item.exp +++ b/third_party/move/move-compiler-v2/tests/checking/naming/duplicate_acquires_list_item.exp @@ -7,20 +7,20 @@ module 0x8675309::M { dummy_field: bool, } private fun t0() - acquires 0x8675309::M::R(*) - acquires 0x8675309::M::X(*) - acquires 0x8675309::M::R(*) + acquires R(*) + acquires X(*) + acquires R(*) { BorrowGlobal(Mutable)(0x1); BorrowGlobal(Mutable)(0x1); Tuple() } private fun t1() - acquires 0x8675309::M::R(*) - acquires 0x8675309::M::X(*) - acquires 0x8675309::M::R(*) - acquires 0x8675309::M::R(*) - acquires 0x8675309::M::R(*) + acquires R(*) + acquires X(*) + acquires R(*) + acquires R(*) + acquires R(*) { BorrowGlobal(Mutable)(0x1); BorrowGlobal(Mutable)(0x1); diff --git a/third_party/move/move-compiler-v2/tests/checking/naming/global_builtin_one_type_argument.exp b/third_party/move/move-compiler-v2/tests/checking/naming/global_builtin_one_type_argument.exp index 85a59aab9e4b2..b2fecf533bafc 100644 --- a/third_party/move/move-compiler-v2/tests/checking/naming/global_builtin_one_type_argument.exp +++ b/third_party/move/move-compiler-v2/tests/checking/naming/global_builtin_one_type_argument.exp @@ -4,7 +4,7 @@ module 0x8675309::M { dummy_field: bool, } private fun t(account: &signer) - acquires 0x8675309::M::R(*) + acquires R(*) { { let _: bool = exists(0x0); diff --git a/third_party/move/move-compiler-v2/tests/checking/naming/unused_type_parameter_struct.exp b/third_party/move/move-compiler-v2/tests/checking/naming/unused_type_parameter_struct.exp index 3ae2e7bdc83b2..68d6effb7bd3f 100644 --- a/third_party/move/move-compiler-v2/tests/checking/naming/unused_type_parameter_struct.exp +++ b/third_party/move/move-compiler-v2/tests/checking/naming/unused_type_parameter_struct.exp @@ -42,24 +42,24 @@ warning: unused type parameter // -- Model dump before bytecode pipeline module 0x42::test { - struct S0 { + struct S0 { dummy_field: bool, } - struct S1 { + struct S1 { dummy_field: bool, } - struct S2 { - f: 0x42::test::S3<#1>, + struct S2 { + f: S3, } - struct S3 { + struct S3 { dummy_field: bool, } - struct S4 { - f: vector<#0>, + struct S4 { + f: vector, } - struct S5 { - f: vector<#0>, - g: vector<#1>, + struct S5 { + f: vector, + g: vector, } } // end 0x42::test diff --git a/third_party/move/move-compiler-v2/tests/checking/naming/warning_dependency.exp b/third_party/move/move-compiler-v2/tests/checking/naming/warning_dependency.exp index af81d60312b4a..2c4e4059c504f 100644 --- a/third_party/move/move-compiler-v2/tests/checking/naming/warning_dependency.exp +++ b/third_party/move/move-compiler-v2/tests/checking/naming/warning_dependency.exp @@ -11,24 +11,24 @@ module 0x42::dependency { use 0x42::test::{S0}; } // end 0x42::dependency module 0x42::test { - struct S0 { + struct S0 { dummy_field: bool, } - struct S1 { + struct S1 { dummy_field: bool, } - struct S2 { - f: 0x42::test::S3<#1>, + struct S2 { + f: S3, } - struct S3 { + struct S3 { dummy_field: bool, } - struct S4 { - f: vector<#0>, + struct S4 { + f: vector, } - struct S5 { - f: vector<#0>, - g: vector<#1>, + struct S5 { + f: vector, + g: vector, } } // end 0x42::test diff --git a/third_party/move/move-compiler-v2/tests/checking/positional_fields/assign_field.exp b/third_party/move/move-compiler-v2/tests/checking/positional_fields/assign_field.exp index 81f20a0b029dc..c84034b0a95a8 100644 --- a/third_party/move/move-compiler-v2/tests/checking/positional_fields/assign_field.exp +++ b/third_party/move/move-compiler-v2/tests/checking/positional_fields/assign_field.exp @@ -6,7 +6,7 @@ module 0x42::test { 1: bool, } V2 { - 0: 0x42::test::S3, + 0: S3, } } struct S0 { @@ -17,13 +17,13 @@ module 0x42::test { 1: bool, } struct S2 { - 0: 0x42::test::S0, + 0: S0, 1: u8, } struct S3 { - 0: 0x42::test::S2, - 1: 0x42::test::S0, - 2: 0x42::test::S2, + 0: S2, + 1: S0, + 2: S2, } private fun assign0(a: u64,b: bool) { { diff --git a/third_party/move/move-compiler-v2/tests/checking/positional_fields/bind_anonymous_field.exp b/third_party/move/move-compiler-v2/tests/checking/positional_fields/bind_anonymous_field.exp index 1a0b7be9954d6..f0ef1a992ba40 100644 --- a/third_party/move/move-compiler-v2/tests/checking/positional_fields/bind_anonymous_field.exp +++ b/third_party/move/move-compiler-v2/tests/checking/positional_fields/bind_anonymous_field.exp @@ -2,10 +2,10 @@ module 0x42::test { enum E1 { V1 { - 0: 0x42::test::S0, + 0: S0, } V2 { - 0: 0x42::test::S1, + 0: S1, } } struct S0 { @@ -13,7 +13,7 @@ module 0x42::test { } struct S1 { 0: bool, - 1: 0x42::test::S0, + 1: S0, } private fun match(x: E1) { match (x) { diff --git a/third_party/move/move-compiler-v2/tests/checking/positional_fields/decl_ok.exp b/third_party/move/move-compiler-v2/tests/checking/positional_fields/decl_ok.exp index d0188cbba98fb..69f0be3a2e1ee 100644 --- a/third_party/move/move-compiler-v2/tests/checking/positional_fields/decl_ok.exp +++ b/third_party/move/move-compiler-v2/tests/checking/positional_fields/decl_ok.exp @@ -15,10 +15,10 @@ module 0x42::test { 0: u8, 1: bool, } - struct S3 { - 0: #1, + struct S3 { + 0: T2, 1: u8, - 2: #0, + 2: T1, } private fun bar(x: S2) { select test::S2.0(x); diff --git a/third_party/move/move-compiler-v2/tests/checking/positional_fields/named_tuple_ability_decl_ok.exp b/third_party/move/move-compiler-v2/tests/checking/positional_fields/named_tuple_ability_decl_ok.exp index 298a8f310f809..5b6703568a6ab 100644 --- a/third_party/move/move-compiler-v2/tests/checking/positional_fields/named_tuple_ability_decl_ok.exp +++ b/third_party/move/move-compiler-v2/tests/checking/positional_fields/named_tuple_ability_decl_ok.exp @@ -6,23 +6,23 @@ module 0x42::test { struct S1 { 0: u8, } - struct S2 { - 0: #0, + struct S2 { + 0: T, 1: u8, } - struct S3 { - 0: #0, + struct S3 { + 0: T, 1: u8, } - struct S4 { + struct S4 { x: u8, - y: #0, + y: T, } - struct S5 { - 0: #0, - 1: 0x42::test::S3<#0>, + struct S5 { + 0: T, + 1: S3, } - struct S6 { + struct S6 { dummy_field: bool, } } // end 0x42::test diff --git a/third_party/move/move-compiler-v2/tests/checking/positional_fields/named_tuple_construct_ok.exp b/third_party/move/move-compiler-v2/tests/checking/positional_fields/named_tuple_construct_ok.exp index 30bd1a8bb884a..faaf3481933e0 100644 --- a/third_party/move/move-compiler-v2/tests/checking/positional_fields/named_tuple_construct_ok.exp +++ b/third_party/move/move-compiler-v2/tests/checking/positional_fields/named_tuple_construct_ok.exp @@ -18,15 +18,15 @@ module 0x42::test { 0: u8, 1: bool, } - struct S3 { - 0: #0, + struct S3 { + 0: T, 1: u8, } struct S4 { dummy_field: bool, } - struct S5 { - x: #0, + struct S5 { + x: T, y: u8, } private fun S0_inhabited(): S0 { diff --git a/third_party/move/move-compiler-v2/tests/checking/positional_fields/variant_ability_decl_ok.exp b/third_party/move/move-compiler-v2/tests/checking/positional_fields/variant_ability_decl_ok.exp index 07b4274a25e4b..ee8fd6fdb431b 100644 --- a/third_party/move/move-compiler-v2/tests/checking/positional_fields/variant_ability_decl_ok.exp +++ b/third_party/move/move-compiler-v2/tests/checking/positional_fields/variant_ability_decl_ok.exp @@ -1,17 +1,17 @@ // -- Model dump before bytecode pipeline module 0x42::test { - enum Bar { + enum Bar { A { - 0: #0, + 0: T, } B { 0: u8, 1: bool, } } - enum Foo { + enum Foo { A { - 0: #0, + 0: T, } B { 0: u8, diff --git a/third_party/move/move-compiler-v2/tests/checking/receiver/decl_errors.exp b/third_party/move/move-compiler-v2/tests/checking/receiver/decl_errors.exp index 4f4835bda6621..4cbfc158da8cb 100644 --- a/third_party/move/move-compiler-v2/tests/checking/receiver/decl_errors.exp +++ b/third_party/move/move-compiler-v2/tests/checking/receiver/decl_errors.exp @@ -38,9 +38,9 @@ module 0x42::n { } // end 0x42::n module 0x42::m { use 0x42::n::{T}; // resolved as: 0x42::n - struct G { - x: #0, - y: #1, + struct G { + x: T, + y: R, } struct S { x: u64, diff --git a/third_party/move/move-compiler-v2/tests/checking/receiver/generic_calls.exp b/third_party/move/move-compiler-v2/tests/checking/receiver/generic_calls.exp index 2c10daec390de..765d427973c0e 100644 --- a/third_party/move/move-compiler-v2/tests/checking/receiver/generic_calls.exp +++ b/third_party/move/move-compiler-v2/tests/checking/receiver/generic_calls.exp @@ -1,7 +1,7 @@ // -- Model dump before bytecode pipeline module 0x42::m { - struct S { - x: #0, + struct S { + x: T, } private fun id(self: S): S { self diff --git a/third_party/move/move-compiler-v2/tests/checking/receiver/generic_calls_typed.exp b/third_party/move/move-compiler-v2/tests/checking/receiver/generic_calls_typed.exp index 2c10daec390de..765d427973c0e 100644 --- a/third_party/move/move-compiler-v2/tests/checking/receiver/generic_calls_typed.exp +++ b/third_party/move/move-compiler-v2/tests/checking/receiver/generic_calls_typed.exp @@ -1,7 +1,7 @@ // -- Model dump before bytecode pipeline module 0x42::m { - struct S { - x: #0, + struct S { + x: T, } private fun id(self: S): S { self diff --git a/third_party/move/move-compiler-v2/tests/checking/specs/intrinsic_decl_ok.exp b/third_party/move/move-compiler-v2/tests/checking/specs/intrinsic_decl_ok.exp index 04ca7c2e62df2..c6ba5637c6bcf 100644 --- a/third_party/move/move-compiler-v2/tests/checking/specs/intrinsic_decl_ok.exp +++ b/third_party/move/move-compiler-v2/tests/checking/specs/intrinsic_decl_ok.exp @@ -1,12 +1,12 @@ // -- Model dump before bytecode pipeline module 0x42::M { - struct MyTable1 { + struct MyTable1 { dummy_field: bool, } spec { } - struct MyTable2 { + struct MyTable2 { dummy_field: bool, } spec { diff --git a/third_party/move/move-compiler-v2/tests/checking/specs/invariants_ok.exp b/third_party/move/move-compiler-v2/tests/checking/specs/invariants_ok.exp index a7059c9346e06..00ce3b6b54444 100644 --- a/third_party/move/move-compiler-v2/tests/checking/specs/invariants_ok.exp +++ b/third_party/move/move-compiler-v2/tests/checking/specs/invariants_ok.exp @@ -1,7 +1,7 @@ // -- Model dump before bytecode pipeline module 0x42::M { struct R { - s: 0x42::M::S, + s: S, } spec { invariant M::less10(true, select M::S.x<0x42::M::S>(select M::R.s())); diff --git a/third_party/move/move-compiler-v2/tests/checking/specs/move_function_in_spec_ok.exp b/third_party/move/move-compiler-v2/tests/checking/specs/move_function_in_spec_ok.exp index 983ba541a7124..4ba45bf526215 100644 --- a/third_party/move/move-compiler-v2/tests/checking/specs/move_function_in_spec_ok.exp +++ b/third_party/move/move-compiler-v2/tests/checking/specs/move_function_in_spec_ok.exp @@ -18,7 +18,7 @@ module 0x42::move_function_in_spec { } } public fun no_change(target: address,new_addr: address): bool - acquires 0x42::move_function_in_spec::TypeInfo(*) + acquires TypeInfo(*) { { let ty: &TypeInfo = BorrowGlobal(Immutable)(target); diff --git a/third_party/move/move-compiler-v2/tests/checking/specs/schemas_ok.exp b/third_party/move/move-compiler-v2/tests/checking/specs/schemas_ok.exp index 4c8215291a695..efd869ab6d011 100644 --- a/third_party/move/move-compiler-v2/tests/checking/specs/schemas_ok.exp +++ b/third_party/move/move-compiler-v2/tests/checking/specs/schemas_ok.exp @@ -52,8 +52,8 @@ note: unused schema M::SchemaExp // -- Model dump before bytecode pipeline module 0x42::M { - struct S { - x: #0, + struct S { + x: X, } private fun add(x: u64): u64 { Add(x, 1) diff --git a/third_party/move/move-compiler-v2/tests/checking/specs/structs_ok.exp b/third_party/move/move-compiler-v2/tests/checking/specs/structs_ok.exp index 43214d6022fa7..69ded91a3a375 100644 --- a/third_party/move/move-compiler-v2/tests/checking/specs/structs_ok.exp +++ b/third_party/move/move-compiler-v2/tests/checking/specs/structs_ok.exp @@ -3,12 +3,12 @@ module 0x42::M { struct T { x: u64, } - struct G { - x: #0, + struct G { + x: T, y: bool, } struct R { - s: 0x42::M::S, + s: S, } struct S { x: u64, diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/borrow_field_chain.exp b/third_party/move/move-compiler-v2/tests/checking/typing/borrow_field_chain.exp index 70d4ba0fd60ae..460c8c1455365 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/borrow_field_chain.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/borrow_field_chain.exp @@ -1,10 +1,10 @@ // -- Model dump before bytecode pipeline module 0x8675309::M { struct X1 { - x2: 0x8675309::M::X2, + x2: X2, } struct X2 { - x3: 0x8675309::M::X3, + x3: X3, } struct X3 { f: u64, diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/decl_unpack_references.exp b/third_party/move/move-compiler-v2/tests/checking/typing/decl_unpack_references.exp index d6881be7a2b73..dac518a528414 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/decl_unpack_references.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/decl_unpack_references.exp @@ -1,8 +1,8 @@ // -- Model dump before bytecode pipeline module 0x8675309::M { struct R { - s1: 0x8675309::M::S, - s2: 0x8675309::M::S, + s1: S, + s2: S, } struct S { f: u64, diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/derefrence.exp b/third_party/move/move-compiler-v2/tests/checking/typing/derefrence.exp index 8c7a6c1aceb7b..b31e5493c2008 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/derefrence.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/derefrence.exp @@ -2,7 +2,7 @@ module 0x8675309::M { struct S { f: u64, - x: 0x8675309::M::X, + x: X, } struct X { dummy_field: bool, diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/dummy_field.exp b/third_party/move/move-compiler-v2/tests/checking/typing/dummy_field.exp index 56d305e825796..83cbf7d25cbf8 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/dummy_field.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/dummy_field.exp @@ -7,7 +7,7 @@ module 0x42::test { dummy_field: bool, } public entry fun test(addr: address) - acquires 0x42::test::R(*) + acquires R(*) { { let test::R{ dummy_field: _dummy_field } = MoveFrom(addr); @@ -21,7 +21,7 @@ module 0x42::test { } } public entry fun test3(addr: address) - acquires 0x42::test::T(*) + acquires T(*) { { let test::T{ dummy_field: _ } = MoveFrom(addr); diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/eq.exp b/third_party/move/move-compiler-v2/tests/checking/typing/eq.exp index 0f6289490929e..66f11852a5790 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/eq.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/eq.exp @@ -1,7 +1,7 @@ // -- Model dump before bytecode pipeline module 0x8675309::M { - struct G { - f: #0, + struct G { + f: T, } struct R { f: u64, diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/exp_list.exp b/third_party/move/move-compiler-v2/tests/checking/typing/exp_list.exp index 423fbbc8ff7f7..4cc3f57c1d1fe 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/exp_list.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/exp_list.exp @@ -1,7 +1,7 @@ // -- Model dump before bytecode pipeline module 0x8675309::M { - struct R { - f: #0, + struct R { + f: T, } struct S { dummy_field: bool, diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/global_builtins.exp b/third_party/move/move-compiler-v2/tests/checking/typing/global_builtins.exp index 04b8d2231d938..4a0650b38a25c 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/global_builtins.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/global_builtins.exp @@ -4,7 +4,7 @@ module 0x8675309::M { dummy_field: bool, } private fun t0(a: &signer) - acquires 0x8675309::M::R(*) + acquires R(*) { { let _: bool = exists(0x0); @@ -24,7 +24,7 @@ module 0x8675309::M { } } private fun t1(a: &signer) - acquires 0x8675309::M::R(*) + acquires R(*) { { let _: bool = exists(0x0); diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/global_builtins_inferred.exp b/third_party/move/move-compiler-v2/tests/checking/typing/global_builtins_inferred.exp index f8c0150058c56..8491eba0f62c7 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/global_builtins_inferred.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/global_builtins_inferred.exp @@ -4,7 +4,7 @@ module 0x42::m { addr: address, } public fun foo(input: address): address - acquires 0x42::m::A(*) + acquires A(*) { { let a: A = MoveFrom(input); diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/implicit_deref_borrow_field_chain.exp b/third_party/move/move-compiler-v2/tests/checking/typing/implicit_deref_borrow_field_chain.exp index 5f505db3a6d37..5b32bfee85bac 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/implicit_deref_borrow_field_chain.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/implicit_deref_borrow_field_chain.exp @@ -1,10 +1,10 @@ // -- Model dump before bytecode pipeline module 0x8675309::M { struct X1 { - x2: 0x8675309::M::X2, + x2: X2, } struct X2 { - x3: 0x8675309::M::X3, + x3: X3, } struct X3 { f: u64, diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/lambda.exp b/third_party/move/move-compiler-v2/tests/checking/typing/lambda.exp index c3d568872e95c..ebcdc1fcfcfdb 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/lambda.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda.exp @@ -48,3 +48,11 @@ error: tuple type `()` is not allowed as a type argument (type was inferred) │ ^ │ = required by instantiating type parameter `T` of function `foreach` + +error: function type `|u64|u64` is not allowed as a field type + ┌─ tests/checking/typing/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/checking/typing/lambda.move b/third_party/move/move-compiler-v2/tests/checking/typing/lambda.move index c5e29275c3d28..92e24c0c36a90 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 new file mode 100644 index 0000000000000..4f27955dd4e6f --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda2.exp @@ -0,0 +1,25 @@ + +Diagnostics: +error: Only inline functions may have function-typed parameters, but non-inline function `M::fun_arg_lambda_not_allowed` has a function parameter: + ┌─ tests/checking/typing/lambda2.move:84:16 + │ +84 │ public fun fun_arg_lambda_not_allowed(x: |u64|) {} // expected lambda not allowed + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ - Parameter `x` has function-valued type `|u64|`. + +warning: Unused parameter `x`. Consider removing or prefixing with an underscore: `_x` + ┌─ tests/checking/typing/lambda2.move:84:43 + │ +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::inline_result_lambda_not_allowed` return type is the function type `|u64|`: + ┌─ tests/checking/typing/lambda2.move:86:59 + │ +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 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 new file mode 100644 index 0000000000000..ccaa472c2e2c2 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda2.move @@ -0,0 +1,99 @@ +module 0x8675309::M { + + // *** 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; + // 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 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) } +// } 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 0000000000000..f89935a0c3358 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda3.exp @@ -0,0 +1,24 @@ +// -- 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 + +// -- Sourcified model before bytecode pipeline +module 0x8675309::M { + public fun lambda_not_allowed() { + let _x = |i| i + 1; + } +} + + +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 0000000000000..bc302cc3ee3be --- /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 0000000000000..d16f979db0562 --- /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 0000000000000..bd93f64575ac6 --- /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 0000000000000..7fccdd1f60f5f --- /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 0000000000000..a77ab5421fcd8 --- /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/checking/typing/lambda_typed.exp b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed.exp index 351d607a7b2b7..7817686444d8f 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda_typed.exp @@ -35,3 +35,11 @@ error: cannot pass `|&u64|u64` to a function which expects argument of type `|&u │ 73 │ foreach(&v, |e: &u64| { sum = sum + *e; *e }) // expected to have wrong result type of lambda │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: function type `|u64|u64` is not allowed as a field type + ┌─ tests/checking/typing/lambda_typed.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/checking/typing/main_arguments_various_caes.exp b/third_party/move/move-compiler-v2/tests/checking/typing/main_arguments_various_caes.exp index ebd403606785e..96d0c3ab89dd8 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/main_arguments_various_caes.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/main_arguments_various_caes.exp @@ -1,7 +1,7 @@ // -- Model dump before bytecode pipeline module 0x42::M { - struct Cup { - f1: #0, + struct Cup { + f1: T, } struct R { dummy_field: bool, diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/move_from_type_argument.exp b/third_party/move/move-compiler-v2/tests/checking/typing/move_from_type_argument.exp index f8c0150058c56..8491eba0f62c7 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/move_from_type_argument.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/move_from_type_argument.exp @@ -4,7 +4,7 @@ module 0x42::m { addr: address, } public fun foo(input: address): address - acquires 0x42::m::A(*) + acquires A(*) { { let a: A = MoveFrom(input); diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/mutable_eq_and_neq.exp b/third_party/move/move-compiler-v2/tests/checking/typing/mutable_eq_and_neq.exp index adc57ec46e5eb..1de8c0247dc61 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/mutable_eq_and_neq.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/mutable_eq_and_neq.exp @@ -4,8 +4,8 @@ module 0x8675309::M { f: bool, } struct P { - b1: 0x8675309::M::B, - b2: 0x8675309::M::B, + b1: B, + b2: B, } struct S { f: u64, diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/neq.exp b/third_party/move/move-compiler-v2/tests/checking/typing/neq.exp index f1976389c8105..00367877ed612 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/neq.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/neq.exp @@ -1,7 +1,7 @@ // -- Model dump before bytecode pipeline module 0x8675309::M { - struct G { - f: #0, + struct G { + f: T, } struct R { f: u64, diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/nested_post_process.exp b/third_party/move/move-compiler-v2/tests/checking/typing/nested_post_process.exp index f962be66efbfa..302baa8097a2f 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/nested_post_process.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/nested_post_process.exp @@ -3,12 +3,12 @@ module 0x42::simple_map { use std::error; use std::option; use std::vector; - struct Element { - key: #0, - value: #1, + struct Element { + key: Key, + value: Value, } - struct SimpleMap { - data: vector<0x42::simple_map::Element<#0, #1>>, + struct SimpleMap { + data: vector>, } public fun borrow(map: &SimpleMap,key: &Key): &Value { { diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/phantom_param_struct_decl.exp b/third_party/move/move-compiler-v2/tests/checking/typing/phantom_param_struct_decl.exp index 9397cd73cadd2..478578a6eacaf 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/phantom_param_struct_decl.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/phantom_param_struct_decl.exp @@ -1,21 +1,21 @@ // -- Model dump before bytecode pipeline module 0x42::M1 { - struct S1 { + struct S1 { a: u64, } - struct S2 { - a: 0x42::M1::S1<#0>, - b: vector<0x42::M1::S1<#0>>, + struct S2 { + a: S1, + b: vector>, } - struct S3 { - a: #1, - b: #3, + struct S3 { + a: T2, + b: T4, } - struct S4 { + struct S4 { a: u64, } - struct S5 { - a: 0x42::M1::S4<#0>, + struct S5 { + a: S4, } } // end 0x42::M1 diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_single_pack.exp b/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_single_pack.exp index ab361d197f9af..fa31994614be4 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_single_pack.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_single_pack.exp @@ -1,8 +1,8 @@ // -- Model dump before bytecode pipeline module 0x42::M { - struct Box { - f1: #0, - f2: #0, + struct Box { + f1: T, + f2: T, } private fun t0() { { diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_single_unpack.exp b/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_single_unpack.exp index ebfb56730b924..fd5056c8e617a 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_single_unpack.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_single_unpack.exp @@ -1,8 +1,8 @@ // -- Model dump before bytecode pipeline module 0x8675309::M { - struct Box { - f1: #0, - f2: #0, + struct Box { + f1: T, + f2: T, } private fun new(): Box { Abort(0) diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_single_unpack_assign.exp b/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_single_unpack_assign.exp index 73269d41aa3c1..e1f2fc3e1a998 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_single_unpack_assign.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_single_unpack_assign.exp @@ -1,8 +1,8 @@ // -- Model dump before bytecode pipeline module 0x8675309::M { - struct Box { - f1: #0, - f2: #0, + struct Box { + f1: T, + f2: T, } private fun new(): Box { Abort(0) diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_threaded_pack.exp b/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_threaded_pack.exp index cb79ee03e4703..66848a8d97a42 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_threaded_pack.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_threaded_pack.exp @@ -1,7 +1,7 @@ // -- Model dump before bytecode pipeline module 0x2::Container { - struct T { - f: #0, + struct T { + f: V, } public fun get(_self: &T): V { Abort(0) @@ -15,9 +15,9 @@ module 0x2::Container { } // end 0x2::Container module 0x2::M { use 0x2::Container; // resolved as: 0x2::Container - struct Box { - f1: #0, - f2: #0, + struct Box { + f1: T, + f2: T, } private fun t0(): Box { { diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/v1-examples/multi_pool_money_market_token.exp b/third_party/move/move-compiler-v2/tests/checking/typing/v1-examples/multi_pool_money_market_token.exp index f4e0e789dbb91..438c492d624f6 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/v1-examples/multi_pool_money_market_token.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/v1-examples/multi_pool_money_market_token.exp @@ -18,8 +18,8 @@ warning: unused type parameter // -- Model dump before bytecode pipeline module 0x2::Token { - struct Coin { - type: #0, + struct Coin { + type: AssetType, value: u64, } public fun create(type: ATy,value: u64): Coin { @@ -71,7 +71,7 @@ module 0x2::Token { } } // end 0x2::Token module 0x2::Map { - struct T { + struct T { } public native fun empty(): T; public native fun remove(m: &T,k: &K): V; @@ -84,23 +84,23 @@ module 0x3::OneToOneMarket { use std::signer; use 0x2::Map; // resolved as: 0x2::Map use 0x2::Token; // resolved as: 0x2::Token - struct BorrowRecord { - record: 0x2::Map::T, + struct BorrowRecord { + record: Map::T, } - struct DepositRecord { - record: 0x2::Map::T, + struct DepositRecord { + record: Map::T, } - struct Pool { - coin: 0x2::Token::Coin<#0>, + struct Pool { + coin: Token::Coin, } - struct Price { + struct Price { price: u64, } public fun borrow(account: &signer,pool_owner: address,amount: u64): Token::Coin - acquires 0x3::OneToOneMarket::Price(*) - acquires 0x3::OneToOneMarket::Pool(*) - acquires 0x3::OneToOneMarket::DepositRecord(*) - acquires 0x3::OneToOneMarket::BorrowRecord(*) + acquires Price(*) + acquires Pool(*) + acquires DepositRecord(*) + acquires BorrowRecord(*) { if Le(amount, OneToOneMarket::max_borrow_amount(account, pool_owner)) { Tuple() @@ -114,8 +114,8 @@ module 0x3::OneToOneMarket { } } public fun deposit(account: &signer,pool_owner: address,coin: Token::Coin) - acquires 0x3::OneToOneMarket::Pool(*) - acquires 0x3::OneToOneMarket::DepositRecord(*) + acquires Pool(*) + acquires DepositRecord(*) { { let amount: u64 = Token::value(Borrow(Immutable)(coin)); @@ -138,7 +138,7 @@ module 0x3::OneToOneMarket { } } private fun borrowed_amount(account: &signer,pool_owner: address): u64 - acquires 0x3::OneToOneMarket::BorrowRecord(*) + acquires BorrowRecord(*) { { let sender: address = signer::address_of(account); @@ -158,7 +158,7 @@ module 0x3::OneToOneMarket { } } private fun deposited_amount(account: &signer,pool_owner: address): u64 - acquires 0x3::OneToOneMarket::DepositRecord(*) + acquires DepositRecord(*) { { let sender: address = signer::address_of(account); @@ -178,10 +178,10 @@ module 0x3::OneToOneMarket { } } private fun max_borrow_amount(account: &signer,pool_owner: address): u64 - acquires 0x3::OneToOneMarket::Price(*) - acquires 0x3::OneToOneMarket::Pool(*) - acquires 0x3::OneToOneMarket::DepositRecord(*) - acquires 0x3::OneToOneMarket::BorrowRecord(*) + acquires Price(*) + acquires Pool(*) + acquires DepositRecord(*) + acquires BorrowRecord(*) { { let input_deposited: u64 = OneToOneMarket::deposited_amount(account, pool_owner); @@ -217,7 +217,7 @@ module 0x3::OneToOneMarket { MoveTo>(account, pack OneToOneMarket::Price(price)) } private fun update_borrow_record(account: &signer,pool_owner: address,amount: u64) - acquires 0x3::OneToOneMarket::BorrowRecord(*) + acquires BorrowRecord(*) { { let sender: address = signer::address_of(account); @@ -242,7 +242,7 @@ module 0x3::OneToOneMarket { } } private fun update_deposit_record(account: &signer,pool_owner: address,amount: u64) - acquires 0x3::OneToOneMarket::DepositRecord(*) + acquires DepositRecord(*) { { let sender: address = signer::address_of(account); @@ -274,7 +274,7 @@ module 0x70dd::ToddNickels { dummy_field: bool, } struct Wallet { - nickels: 0x2::Token::Coin<0x70dd::ToddNickels::T>, + nickels: Token::Coin, } public fun init(account: &signer) { if Eq
(signer::address_of(account), 0x70dd) { @@ -285,7 +285,7 @@ module 0x70dd::ToddNickels { MoveTo(account, pack ToddNickels::Wallet(Token::create(pack ToddNickels::T(false), 0))) } public fun destroy(c: Token::Coin) - acquires 0x70dd::ToddNickels::Wallet(*) + acquires Wallet(*) { Token::deposit(Borrow(Mutable)(select ToddNickels::Wallet.nickels<&mut Wallet>(BorrowGlobal(Mutable)(0x70dd))), c) } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/v1-examples/simple_money_market_token.exp b/third_party/move/move-compiler-v2/tests/checking/typing/v1-examples/simple_money_market_token.exp index f28f09f7ddb92..3749e13a8d819 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/v1-examples/simple_money_market_token.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/v1-examples/simple_money_market_token.exp @@ -1,7 +1,7 @@ // -- Model dump before bytecode pipeline module 0x2::Token { - struct Coin { - type: #0, + struct Coin { + type: AssetType, value: u64, } public fun create(type: ATy,value: u64): Coin { @@ -59,7 +59,7 @@ module 0x70dd::ToddNickels { dummy_field: bool, } struct Wallet { - nickels: 0x2::Token::Coin<0x70dd::ToddNickels::T>, + nickels: Token::Coin, } public fun init(account: &signer) { if Eq
(signer::address_of(account), 0x70dd) { @@ -70,7 +70,7 @@ module 0x70dd::ToddNickels { MoveTo(account, pack ToddNickels::Wallet(Token::create(pack ToddNickels::T(false), 0))) } public fun destroy(c: Token::Coin) - acquires 0x70dd::ToddNickels::Wallet(*) + acquires Wallet(*) { Token::deposit(Borrow(Mutable)(select ToddNickels::Wallet.nickels<&mut Wallet>(BorrowGlobal(Mutable)(0x70dd))), c) } @@ -86,23 +86,23 @@ module 0x70dd::ToddNickels { module 0xb055::OneToOneMarket { use std::signer; use 0x2::Token; // resolved as: 0x2::Token - struct BorrowRecord { + struct BorrowRecord { record: u64, } - struct DepositRecord { + struct DepositRecord { record: u64, } - struct Pool { - coin: 0x2::Token::Coin<#0>, + struct Pool { + coin: Token::Coin, } - struct Price { + struct Price { price: u64, } public fun borrow(account: &signer,amount: u64): Token::Coin - acquires 0xb055::OneToOneMarket::Price(*) - acquires 0xb055::OneToOneMarket::Pool(*) - acquires 0xb055::OneToOneMarket::DepositRecord(*) - acquires 0xb055::OneToOneMarket::BorrowRecord(*) + acquires Price(*) + acquires Pool(*) + acquires DepositRecord(*) + acquires BorrowRecord(*) { if Le(amount, OneToOneMarket::max_borrow_amount(account)) { Tuple() @@ -116,8 +116,8 @@ module 0xb055::OneToOneMarket { } } public fun deposit(account: &signer,coin: Token::Coin) - acquires 0xb055::OneToOneMarket::Pool(*) - acquires 0xb055::OneToOneMarket::DepositRecord(*) + acquires Pool(*) + acquires DepositRecord(*) { { let amount: u64 = Token::value(Borrow(Immutable)(coin)); @@ -140,7 +140,7 @@ module 0xb055::OneToOneMarket { } } private fun borrowed_amount(account: &signer): u64 - acquires 0xb055::OneToOneMarket::BorrowRecord(*) + acquires BorrowRecord(*) { { let sender: address = signer::address_of(account); @@ -153,7 +153,7 @@ module 0xb055::OneToOneMarket { } } private fun deposited_amount(account: &signer): u64 - acquires 0xb055::OneToOneMarket::DepositRecord(*) + acquires DepositRecord(*) { { let sender: address = signer::address_of(account); @@ -166,10 +166,10 @@ module 0xb055::OneToOneMarket { } } private fun max_borrow_amount(account: &signer): u64 - acquires 0xb055::OneToOneMarket::Price(*) - acquires 0xb055::OneToOneMarket::Pool(*) - acquires 0xb055::OneToOneMarket::DepositRecord(*) - acquires 0xb055::OneToOneMarket::BorrowRecord(*) + acquires Price(*) + acquires Pool(*) + acquires DepositRecord(*) + acquires BorrowRecord(*) { { let input_deposited: u64 = OneToOneMarket::deposited_amount(account); @@ -213,7 +213,7 @@ module 0xb055::OneToOneMarket { } } private fun update_borrow_record(account: &signer,amount: u64) - acquires 0xb055::OneToOneMarket::BorrowRecord(*) + acquires BorrowRecord(*) { { let sender: address = signer::address_of(account); @@ -229,7 +229,7 @@ module 0xb055::OneToOneMarket { } } private fun update_deposit_record(account: &signer,amount: u64) - acquires 0xb055::OneToOneMarket::DepositRecord(*) + acquires DepositRecord(*) { { let sender: address = signer::address_of(account); diff --git a/third_party/move/move-compiler-v2/tests/checking/variants/variants_test_no_parenthesis_ok.exp b/third_party/move/move-compiler-v2/tests/checking/variants/variants_test_no_parenthesis_ok.exp index 97f7cc058eebf..da04961916c62 100644 --- a/third_party/move/move-compiler-v2/tests/checking/variants/variants_test_no_parenthesis_ok.exp +++ b/third_party/move/move-compiler-v2/tests/checking/variants/variants_test_no_parenthesis_ok.exp @@ -9,9 +9,9 @@ module 0x815::m { Red, Blue, } - enum Generic { + enum Generic { Foo { - 0: #0, + 0: T, } Bar { 0: u64, diff --git a/third_party/move/move-compiler-v2/tests/checking/variants/variants_test_ok.exp b/third_party/move/move-compiler-v2/tests/checking/variants/variants_test_ok.exp index 97f7cc058eebf..da04961916c62 100644 --- a/third_party/move/move-compiler-v2/tests/checking/variants/variants_test_ok.exp +++ b/third_party/move/move-compiler-v2/tests/checking/variants/variants_test_ok.exp @@ -9,9 +9,9 @@ module 0x815::m { Red, Blue, } - enum Generic { + enum Generic { Foo { - 0: #0, + 0: T, } Bar { 0: u64, diff --git a/third_party/move/move-compiler-v2/tests/cyclic-instantiation-checker/v1-tests/mutually_recursive_non_generic_type_ok.exp b/third_party/move/move-compiler-v2/tests/cyclic-instantiation-checker/v1-tests/mutually_recursive_non_generic_type_ok.exp index ee9f393b3f473..fe2891c695b11 100644 --- a/third_party/move/move-compiler-v2/tests/cyclic-instantiation-checker/v1-tests/mutually_recursive_non_generic_type_ok.exp +++ b/third_party/move/move-compiler-v2/tests/cyclic-instantiation-checker/v1-tests/mutually_recursive_non_generic_type_ok.exp @@ -1,7 +1,7 @@ // -- Model dump before bytecode pipeline module 0x8675309::M { - struct S { - f: #0, + struct S { + f: T, } private fun f() { M::g>() diff --git a/third_party/move/move-compiler-v2/tests/cyclic-instantiation-checker/v1-typing/infinite_instantiations_valid.exp b/third_party/move/move-compiler-v2/tests/cyclic-instantiation-checker/v1-typing/infinite_instantiations_valid.exp index d986f83593d1a..62dc89568b814 100644 --- a/third_party/move/move-compiler-v2/tests/cyclic-instantiation-checker/v1-typing/infinite_instantiations_valid.exp +++ b/third_party/move/move-compiler-v2/tests/cyclic-instantiation-checker/v1-typing/infinite_instantiations_valid.exp @@ -1,7 +1,7 @@ // -- Model dump before bytecode pipeline module 0x42::M { - struct Box { - f: #0, + struct Box { + f: T, } public fun t0() { M::t1(); diff --git a/third_party/move/move-compiler-v2/tests/lambda-lifting/basic.exp b/third_party/move/move-compiler-v2/tests/lambda-lifting/basic.exp index 560bf63d49ec9..cd8a217423ba1 100644 --- a/third_party/move/move-compiler-v2/tests/lambda-lifting/basic.exp +++ b/third_party/move/move-compiler-v2/tests/lambda-lifting/basic.exp @@ -18,6 +18,206 @@ module 0xcafe::m { } // 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 { @@ -45,3 +245,61 @@ module 0xcafe::m { }, 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 diff --git a/third_party/move/move-compiler-v2/tests/lambda-lifting/modify.exp b/third_party/move/move-compiler-v2/tests/lambda-lifting/modify.exp index 9b00da4dfeba8..3664bd2e163bb 100644 --- a/third_party/move/move-compiler-v2/tests/lambda-lifting/modify.exp +++ b/third_party/move/move-compiler-v2/tests/lambda-lifting/modify.exp @@ -44,6 +44,463 @@ module 0xcafe::m { } // 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 diff --git a/third_party/move/move-compiler-v2/tests/lambda-lifting/nested.exp b/third_party/move/move-compiler-v2/tests/lambda-lifting/nested.exp index 9ddfd3b736119..6da5f81560227 100644 --- a/third_party/move/move-compiler-v2/tests/lambda-lifting/nested.exp +++ b/third_party/move/move-compiler-v2/tests/lambda-lifting/nested.exp @@ -12,6 +12,146 @@ module 0xcafe::m { } // 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 { @@ -30,3 +170,43 @@ module 0xcafe::m { 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 diff --git a/third_party/move/move-compiler-v2/tests/lambda-lifting/pattern.exp b/third_party/move/move-compiler-v2/tests/lambda-lifting/pattern.exp index 0b9d7af753a8c..9b6c76f186bb0 100644 --- a/third_party/move/move-compiler-v2/tests/lambda-lifting/pattern.exp +++ b/third_party/move/move-compiler-v2/tests/lambda-lifting/pattern.exp @@ -1,7 +1,177 @@ // -- Model dump before env processor pipeline: module 0xcafe::m { - struct S { - x: #0, + struct S { + x: T, + } + private fun consume(s: S,x: T,f: |(S, T)|T): T { + (f)(s, x) + } + private fun pattern(s: S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (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: S,x: T,f: |(S, T)|T): T { + (f)(s, x) + } + private fun pattern(s: S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (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: S,x: T,f: |(S, T)|T): T { + (f)(s, x) + } + private fun pattern(s: S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (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: S,x: T,f: |(S, T)|T): T { + (f)(s, x) + } + private fun pattern(s: S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (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: S,x: T,f: |(S, T)|T): T { + (f)(s, x) + } + private fun pattern(s: S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (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: S,x: T,f: |(S, T)|T): T { + (f)(s, x) + } + private fun pattern(s: S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (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: S,x: T,f: |(S, T)|T): T { + (f)(s, x) + } + private fun pattern(s: S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (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: S,x: T,f: |(S, T)|T): T { + (f)(s, x) + } + private fun pattern(s: S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (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: S,x: T,f: |(S, T)|T): T { + (f)(s, x) + } + private fun pattern(s: S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (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: S,x: T,f: |(S, T)|T): T { + (f)(s, x) + } + private fun pattern(s: S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (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: S,x: T,f: |(S, T)|T): T { (f)(s, x) @@ -17,8 +187,54 @@ module 0xcafe::m { // -- Model dump after env processor lambda-lifting: module 0xcafe::m { - struct S { - x: #0, + struct S { + x: T, + } + private fun consume(s: S,x: T,f: |(S, T)|T): T { + (f)(s, x) + } + private fun pattern(s: S,x: u64): u64 { + m::consume(s, x, closure m::pattern$lambda$1()) + } + private fun pattern$lambda$1(param$0: 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: S,x: T,f: |(S, T)|T): T { + (f)(s, x) + } + private fun pattern(s: S,x: u64): u64 { + m::consume(s, x, closure m::pattern$lambda$1()) + } + private fun pattern$lambda$1(param$0: 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: S,x: T,f: |(S, T)|T): T { (f)(s, x) diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/spec_parsing_fun_type_fail.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/spec_parsing_fun_type_fail.exp index f5a92a3579cfe..e023799381a93 100644 --- a/third_party/move/move-compiler-v2/tests/more-v1/parser/spec_parsing_fun_type_fail.exp +++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/spec_parsing_fun_type_fail.exp @@ -4,7 +4,7 @@ error: Only inline functions may have function-typed parameters, but non-inline ┌─ tests/more-v1/parser/spec_parsing_fun_type_fail.move:2:9 │ 2 │ fun fun_type_in_prog(p: |u64|u64) { - │ ^^^^^^^^^^^^^^^^ - Parameter `p` has a function type. + │ ^^^^^^^^^^^^^^^^ - Parameter `p` has function-valued type `|u64|u64`. warning: Unused parameter `p`. Consider removing or prefixing with an underscore: `_p` ┌─ tests/more-v1/parser/spec_parsing_fun_type_fail.move:2:26 diff --git a/third_party/move/move-compiler-v2/tests/op-equal/valid0.exp b/third_party/move/move-compiler-v2/tests/op-equal/valid0.exp index 3d819831e8a3e..e3a00fa6e9edf 100644 --- a/third_party/move/move-compiler-v2/tests/op-equal/valid0.exp +++ b/third_party/move/move-compiler-v2/tests/op-equal/valid0.exp @@ -3,8 +3,8 @@ module 0x42::test { struct Coin { 0: u256, } - struct Wrapper { - 0: #0, + struct Wrapper { + 0: T, } private fun add1_new(x: u256): u256 { x: u256 = Add(x, 1); @@ -40,7 +40,7 @@ module 0x42::test { } } private fun inc_coin_at(addr: address) - acquires 0x42::test::Coin(*) + acquires Coin(*) { { let coin: &mut Coin = BorrowGlobal(Mutable)(addr); diff --git a/third_party/move/move-compiler-v2/tests/op-equal/valid1.exp b/third_party/move/move-compiler-v2/tests/op-equal/valid1.exp index 1369ebdbc51c5..d75c575a32c78 100644 --- a/third_party/move/move-compiler-v2/tests/op-equal/valid1.exp +++ b/third_party/move/move-compiler-v2/tests/op-equal/valid1.exp @@ -3,8 +3,8 @@ module 0x42::test { struct Coin { 0: u256, } - struct Wrapper { - 0: #0, + struct Wrapper { + 0: T, } private fun bitand_vec_coin_new(x: vector,index: u64) { { @@ -49,7 +49,7 @@ module 0x42::test { Tuple() } private fun shr_coin_at(addr: address) - acquires 0x42::test::Coin(*) + acquires Coin(*) { { let coin: &mut Coin = BorrowGlobal(Mutable)(addr); diff --git a/third_party/move/move-compiler-v2/tests/simplifier-elimination/assign_unpack_references.exp b/third_party/move/move-compiler-v2/tests/simplifier-elimination/assign_unpack_references.exp index ecbeecf5320d2..b14d08d9ae98f 100644 --- a/third_party/move/move-compiler-v2/tests/simplifier-elimination/assign_unpack_references.exp +++ b/third_party/move/move-compiler-v2/tests/simplifier-elimination/assign_unpack_references.exp @@ -1,8 +1,8 @@ // -- Model dump before bytecode pipeline module 0x8675309::M { struct R { - s1: 0x8675309::M::S, - s2: 0x8675309::M::S, + s1: S, + s2: S, } struct S { f: u64, diff --git a/third_party/move/move-compiler-v2/tests/testsuite.rs b/third_party/move/move-compiler-v2/tests/testsuite.rs index ba34279b86a38..3bd4ea13694d8 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 @@ -169,15 +169,10 @@ const TEST_CONFIGS: Lazy> = Lazy::new(|| { exp_suffix: None, options: opts .clone() - // Need to turn off usage checks because they complain about - // lambda parameters outside of inline functions. Other checks - // also turned off for now since they mess up baseline. - .set_experiment(Experiment::CHECKS, false) - .set_experiment(Experiment::OPTIMIZE, false) - .set_experiment(Experiment::OPTIMIZE_WAITING_FOR_COMPARE_TESTS, false) - .set_experiment(Experiment::INLINING, false) - .set_experiment(Experiment::RECURSIVE_TYPE_CHECK, false) - .set_experiment(Experiment::SPEC_REWRITE, false) + .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, dump_ast: DumpLevel::AllStages, diff --git a/third_party/move/move-compiler/src/typing/core.rs b/third_party/move/move-compiler/src/typing/core.rs index 1b1c196e57f3a..df4bf1dae52c6 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 51dfb276b5342..b0d908310701a 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 e305bdc9c047b..8f5acce33805a 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 e59ad1ba145cf..f3bf11a387c2c 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 c5e29275c3d28..92e24c0c36a90 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 new file mode 100644 index 0000000000000..6a329bd27c5d2 --- /dev/null +++ b/third_party/move/move-compiler/tests/move_check/typing/lambda2.exp @@ -0,0 +1,24 @@ +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-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-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-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-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 new file mode 100644 index 0000000000000..0a3ede2f22a19 --- /dev/null +++ b/third_party/move/move-compiler/tests/move_check/typing/lambda2.move @@ -0,0 +1,99 @@ +module 0x8675309::M { + + // *** 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; + // 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/lambda3.exp b/third_party/move/move-compiler/tests/move_check/typing/lambda3.exp new file mode 100644 index 0000000000000..fcc8ff722d396 --- /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 0000000000000..bc302cc3ee3be --- /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 0000000000000..7e44d487754e8 --- /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 0000000000000..bd93f64575ac6 --- /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 0000000000000..a14e1a5ff0d5c --- /dev/null +++ b/third_party/move/move-compiler/tests/move_check/typing/lambda_returning_lambda2.exp @@ -0,0 +1,6 @@ +warning[W09003]: unused assignment + ┌─ tests/move_check/typing/lambda_returning_lambda2.move:9:13 + │ +9 │ let sum = 0; + │ ^^^ Unused assignment or binding for local 'sum'. Consider removing, replacing with '_', or prefixing with '_' (e.g., '_sum') + 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 0000000000000..a77ab5421fcd8 --- /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/model_builder.rs b/third_party/move/move-model/src/builder/model_builder.rs index 3fb7e1afa5322..7faa85f057f97 100644 --- a/third_party/move/move-model/src/builder/model_builder.rs +++ b/third_party/move/move-model/src/builder/model_builder.rs @@ -151,8 +151,9 @@ pub(crate) struct StructVariant { /// A declaration of a function. #[derive(Debug, Clone)] pub(crate) struct FunEntry { - pub loc: Loc, // location of the entire function span - pub name_loc: Loc, // location of just the function name + pub loc: Loc, // location of the entire function span + pub name_loc: Loc, // location of just the function name + pub result_type_loc: Loc, // location of the result type declaration pub module_id: ModuleId, pub fun_id: FunId, pub visibility: Visibility, 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 8b4d7133ae2b1..5b5cdaeae904c 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::{ @@ -568,9 +568,11 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> { let is_native = matches!(def.body.value, EA::FunctionBody_::Native); let def_loc = et.to_loc(&def.loc); let name_loc = et.to_loc(&name.loc()); + let result_type_loc = et.to_loc(&def.signature.return_type.loc); et.parent.parent.define_fun(qsym.clone(), FunEntry { loc: def_loc.clone(), name_loc, + result_type_loc, module_id: et.parent.module_id, fun_id, visibility, @@ -3683,8 +3685,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(), + 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 c32fe3781f105..752f6da29f2ba 100644 --- a/third_party/move/move-model/src/model.rs +++ b/third_party/move/move-model/src/model.rs @@ -1875,8 +1875,11 @@ impl GlobalEnv { let called_funs = def.called_funs(); let data = FunctionData { name, - loc: loc.clone(), - id_loc: loc, + loc: FunctionLoc { + full: loc.clone(), + id_loc: loc.clone(), + result_type_loc: loc, + }, def_idx: None, handle_idx: None, visibility, @@ -2374,7 +2377,6 @@ impl GlobalEnv { pub fn internal_dump_env(&self, all: bool) -> String { let spool = self.symbol_pool(); - let tctx = &self.get_type_display_ctx(); let writer = CodeWriter::new(self.internal_loc()); for module in self.get_modules() { if !all && !module.is_target() { @@ -2428,8 +2430,26 @@ impl GlobalEnv { emitln!(writer, "{}", self.display(&*module_spec)); } for str in module.get_structs() { + let tctx = str.get_type_display_ctx(); + let type_params = str.get_type_parameters(); + let type_params_str = if !type_params.is_empty() { + format!( + "<{}>", + type_params + .iter() + .map(|p| p.0.display(spool).to_string()) + .join(",") + ) + } else { + "".to_owned() + }; if str.has_variants() { - emitln!(writer, "enum {} {{", str.get_name().display(spool)); + emitln!( + writer, + "enum {}{} {{", + str.get_name().display(spool), + type_params_str + ); writer.indent(); for variant in str.get_variants() { emit!(writer, "{}", variant.display(spool)); @@ -2438,7 +2458,7 @@ impl GlobalEnv { emitln!(writer, " {"); writer.indent(); for fld in fields { - emitln!(writer, "{},", self.dump_field(tctx, &fld)) + emitln!(writer, "{},", self.dump_field(&tctx, &fld)) } writer.unindent(); emitln!(writer, "}") @@ -2447,10 +2467,15 @@ impl GlobalEnv { } } } else { - emitln!(writer, "struct {} {{", str.get_name().display(spool)); + emitln!( + writer, + "struct {}{} {{", + str.get_name().display(spool), + type_params_str + ); writer.indent(); for fld in str.get_fields() { - emitln!(writer, "{},", self.dump_field(tctx, &fld)) + emitln!(writer, "{},", self.dump_field(&tctx, &fld)) } } writer.unindent(); @@ -2461,7 +2486,8 @@ impl GlobalEnv { } } for fun in module.get_functions() { - self.dump_fun_internal(&writer, tctx, &fun); + let tctx = fun.get_type_display_ctx(); + self.dump_fun_internal(&writer, &tctx, &fun); } for (_, fun) in module.get_spec_funs() { emit!( @@ -4009,16 +4035,26 @@ impl EqIgnoringLoc for Parameter { } } +/// Represents source code locations associated with a function. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct FunctionLoc { + /// Location of this function. + 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, - /// Location of this function. - pub(crate) loc: Loc, - - /// Location of the function identifier, suitable for error messages alluding to the function. - pub(crate) id_loc: Loc, + /// 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. @@ -4139,7 +4175,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. @@ -4154,12 +4190,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.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 97434c3fb8716..07ee9d11abba8 100644 --- a/third_party/move/move-model/src/ty.rs +++ b/third_party/move/move-model/src/ty.rs @@ -155,6 +155,9 @@ pub enum Constraint { /// a pseudo constraint which never fails, but used to generate a default for /// inference. WithDefault(Type), + /// The type must not be function because it is used as the type of some field or + /// as a type argument. + NoFunction, } /// A type to describe the context from where a constraint stems. Used for @@ -384,7 +387,10 @@ impl Constraint { /// for internal constraints which would be mostly confusing to users. pub fn hidden(&self) -> bool { use Constraint::*; - matches!(self, NoPhantom | NoReference | NoTuple | WithDefault(..)) + matches!( + self, + NoPhantom | NoReference | NoTuple | NoFunction | WithDefault(..) + ) } /// Returns true if this context is accumulating. When adding a new constraint @@ -402,6 +408,7 @@ impl Constraint { | Constraint::NoPhantom | Constraint::NoTuple | Constraint::NoReference + | Constraint::NoFunction ) } @@ -420,7 +427,10 @@ impl Constraint { /// the same type. pub fn report_only_once(&self) -> bool { use Constraint::*; - matches!(self, HasAbilities(..) | NoReference | NoPhantom | NoTuple) + matches!( + self, + HasAbilities(..) | NoReference | NoFunction | NoPhantom | NoTuple + ) } /// Joins the two constraints. If they are incompatible, produces a type unification error. @@ -505,6 +515,7 @@ impl Constraint { )) } }, + (Constraint::NoFunction, Constraint::NoFunction) => Ok(true), (Constraint::NoReference, Constraint::NoReference) => Ok(true), (Constraint::NoTuple, Constraint::NoTuple) => Ok(true), (Constraint::NoPhantom, Constraint::NoPhantom) => Ok(true), @@ -524,11 +535,15 @@ 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]; + let mut result = vec![ + Constraint::NoReference, + Constraint::NoTuple, + Constraint::NoFunction, // TODO(LAMBDA) - remove when implement LAMBDA_AS_TYPE_PARAMETERS + ]; let TypeParameter( _, TypeParameterKind { @@ -552,6 +567,7 @@ impl Constraint { Constraint::NoPhantom, Constraint::NoReference, Constraint::NoTuple, + Constraint::NoFunction, // TODO(LAMBDA) - remove when we implement LAMBDA_IN_VECTORS ] } @@ -562,6 +578,7 @@ impl Constraint { Constraint::NoPhantom, Constraint::NoTuple, Constraint::NoReference, + Constraint::NoFunction, ]; let abilities = if !field_ty.depends_from_type_parameter() { if struct_abilities.has_ability(Ability::Key) { @@ -632,6 +649,7 @@ impl Constraint { ) }, Constraint::NoReference => "no-ref".to_string(), + Constraint::NoFunction => "no-func".to_string(), Constraint::NoTuple => "no-tuple".to_string(), Constraint::NoPhantom => "no-phantom".to_string(), Constraint::HasAbilities(required_abilities) => { @@ -801,6 +819,21 @@ impl Type { matches!(self, Type::Primitive(_)) } + /// Determines whether this is a function. + pub fn is_function(&self) -> bool { + matches!(self, Type::Fun(..)) + } + + /// Determines whether this is a function or a tuple with a function; + /// this is useful to test a function parameter/return type for function values. + pub fn has_function(&self) -> bool { + match self { + Type::Tuple(tys) => tys.iter().any(|ty| ty.is_function()), + Type::Fun(..) => true, + _ => false, + } + } + /// Determines whether this is a reference. pub fn is_reference(&self) -> bool { matches!(self, Type::Reference(_, _)) @@ -1774,6 +1807,13 @@ impl Substitution { Ok(()) } }, + (Constraint::NoFunction, ty) => { + if ty.is_function() { + constraint_unsatisfied_error() + } else { + Ok(()) + } + }, (Constraint::NoTuple, ty) => { if ty.is_tuple() { constraint_unsatisfied_error() @@ -2944,6 +2984,13 @@ impl TypeUnificationError { item_name() ) }, + Constraint::NoFunction => { + format!( + "function type `{}` is not allowed {}", + ty.display(display_context), + item_name() + ) + }, Constraint::NoPhantom => { format!( "phantom type `{}` can only be used as an argument for another phantom type parameter",