From cac57d58c816a935fa322183cf7faeef119983d0 Mon Sep 17 00:00:00 2001 From: "Brian R. Murphy" <132495859+brmataptos@users.noreply.github.com> Date: Tue, 24 Sep 2024 12:26:00 -0700 Subject: [PATCH] fix #14633: fix error messages for lambdas, identify change points for more complete lambda implementation --- .../src/bytecode_generator.rs | 28 +- .../src/env_pipeline/function_checker.rs | 34 +- .../src/env_pipeline/lambda_lifter.rs | 4 +- .../env_pipeline/recursive_struct_checker.rs | 2 +- .../src/env_pipeline/unused_params_checker.rs | 10 +- .../move/move-compiler-v2/src/experiments.rs | 25 + .../file_format_generator/module_generator.rs | 15 +- .../bug_14471_receiver_inference.exp | 4 +- .../tests/bytecode-generator/fields.exp | 2 +- .../tests/bytecode-generator/matching_ok.exp | 2 +- .../abilities/v1/ability_constraints.exp | 6 +- .../v1/phantom_param_op_abilities.exp | 10 +- .../phantom_params_constraint_abilities.exp | 20 +- .../v1/phantom_params_field_abilities.exp | 8 +- .../tests/checking/dotdot/dotdot_valid.exp | 10 +- .../tests/checking/inlining/lambda3.exp | 17 + .../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 +- .../naming/unused_type_parameter_struct.exp | 8 +- .../checking/naming/warning_dependency.exp | 8 +- .../checking/positional_fields/decl_ok.exp | 4 +- .../named_tuple_ability_decl_ok.exp | 10 +- .../named_tuple_construct_ok.exp | 4 +- .../variant_ability_decl_ok.exp | 4 +- .../tests/checking/receiver/decl_errors.exp | 4 +- .../tests/checking/receiver/generic_calls.exp | 2 +- .../checking/receiver/generic_calls_typed.exp | 2 +- .../tests/checking/specs/schemas_ok.exp | 2 +- .../tests/checking/specs/structs_ok.exp | 2 +- .../tests/checking/typing/eq.exp | 2 +- .../tests/checking/typing/exp_list.exp | 2 +- .../tests/checking/typing/lambda.exp | 8 + .../tests/checking/typing/lambda2.exp | 25 + .../tests/checking/typing/lambda2.move | 100 ++++ .../tests/checking/typing/lambda_typed.exp | 8 + .../typing/main_arguments_various_caes.exp | 2 +- .../tests/checking/typing/neq.exp | 2 +- .../checking/typing/nested_post_process.exp | 6 +- .../typing/phantom_param_struct_decl.exp | 10 +- .../typing/type_variable_join_single_pack.exp | 4 +- .../type_variable_join_single_unpack.exp | 4 +- ...ype_variable_join_single_unpack_assign.exp | 4 +- .../type_variable_join_threaded_pack.exp | 6 +- .../multi_pool_money_market_token.exp | 4 +- .../v1-examples/simple_money_market_token.exp | 4 +- .../variants_test_no_parenthesis_ok.exp | 2 +- .../checking/variants/variants_test_ok.exp | 2 +- ...mutually_recursive_non_generic_type_ok.exp | 2 +- .../infinite_instantiations_valid.exp | 2 +- .../tests/lambda-lifting/basic.exp | 258 ++++++++++ .../tests/lambda-lifting/modify.exp | 457 ++++++++++++++++++ .../tests/lambda-lifting/nested.exp | 180 +++++++ .../tests/lambda-lifting/pattern.exp | 220 ++++++++- .../parser/spec_parsing_fun_type_fail.exp | 2 +- .../move/move-compiler-v2/tests/testsuite.rs | 13 +- .../tests/move_check/typing/lambda2.exp | 30 ++ .../tests/move_check/typing/lambda2.move | 100 ++++ .../move-model/src/builder/model_builder.rs | 5 +- .../move-model/src/builder/module_builder.rs | 3 + third_party/move/move-model/src/model.rs | 20 +- third_party/move/move-model/src/ty.rs | 43 +- 65 files changed, 1972 insertions(+), 126 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/tests/move_check/typing/lambda2.exp create mode 100644 third_party/move/move-compiler/tests/move_check/typing/lambda2.move 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 e20f3b09bf19e..bda4618bc204e 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) => { @@ -476,9 +479,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") }, @@ -803,7 +813,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..05e86f37e82be 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,7 +3,7 @@ //! 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::{ @@ -17,17 +17,44 @@ type QualifiedFunId = QualifiedId; /// check that non-inline function parameters do not have function type. pub fn check_for_function_typed_parameters(env: &mut GlobalEnv) { + let options = env + .get_extension::() + .expect("Options is available"); + let lambda_params_ok = options.experiment_on(Experiment::LAMBDA_PARAMS); + let lambda_return_ok = options.experiment_on(Experiment::LAMBDA_RESULTS); + 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 no functions have function return type + if !lambda_return_ok { + let caller_name = caller_func.get_full_name_str(); + let return_type = caller_func.get_result_type(); + let has_function_value = + return_type.clone().flatten().iter().any(Type::is_function); + if has_function_value { + let type_display_ctx = caller_func.get_type_display_ctx(); + env.diag( + Severity::Error, + &caller_func.get_id_loc(), + &format!("Functions may not return function-typed values, but function `{}` return type is `{}`:", + caller_name, + return_type.display(&type_display_ctx)), + ); + } + } // Check that non-inline function parameters don't have function type - if !caller_func.is_inline() { + if !caller_func.is_inline() && !lambda_params_ok { let parameters = caller_func.get_parameters(); let bad_params: Vec<_> = parameters .iter() .filter(|param| matches!(param.1, Type::Fun(_, _))) .collect(); if !bad_params.is_empty() { + let type_display_ctx = caller_func.get_type_display_ctx(); let caller_name = caller_func.get_full_name_str(); let reasons: Vec<(Loc, String)> = bad_params .iter() @@ -35,8 +62,9 @@ pub fn check_for_function_typed_parameters(env: &mut GlobalEnv) { ( param.2.clone(), format!( - "Parameter `{}` has a function type.", + "Parameter `{}` has function-valued type `{}`.", param.0.display(env.symbol_pool()), + param.1.display(&type_display_ctx) ), ) }) 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..1246ac0ea5ba0 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(); 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..c067d2f243ee1 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_PARAMS.to_string(), + description: "Turns on or off function values as parameters to non-inline functions" + .to_string(), + default: Given(false), + }, + Experiment { + name: Experiment::LAMBDA_RESULTS.to_string(), + description: "Turns on or off function values in function results".to_string(), + 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_LIFTING: &'static str = "lambda-lifting"; + pub const LAMBDA_PARAMS: &'static str = "lambda-params"; + pub const LAMBDA_RESULTS: &'static str = "lambda-results"; + pub const LAMBDA_VALUES: &'static str = "lambda-values"; pub const LINT_CHECKS: &'static str = "lint-checks"; pub const OPTIMIZE: &'static str = "optimize"; 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..b371d7f17cf2e 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,20 @@ impl ModuleGenerator { ReferenceKind::Mutable => FF::SignatureToken::MutableReference(target_ty), } }, - Fun(_, _) | TypeDomain(_) | ResourceDomain(_, _, _) | Error | Var(_) => { + Fun(_param_ty, _result_ty) => { + // let _param_ty = Box::new(self.signature_token(ctx, loc, param_ty)); + // let _result_ty = Box::new(self.signature_token(ctx, loc, 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/bug_14471_receiver_inference.exp b/third_party/move/move-compiler-v2/tests/bytecode-generator/bug_14471_receiver_inference.exp index c8a13847d8cae..9a7714eaeae4c 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 @@ -4,8 +4,8 @@ module 0x815::m { table: m::Table, } struct Table { - x: #0, - y: #1, + x: T1, + y: T2, } struct ValueWrap { val: u64, 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 9a0e87baab823..54c0d2bf6f939 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 @@ -4,7 +4,7 @@ module 0x42::fields { h: u64, } struct G { - f: #0, + f: X, } struct S { f: u64, 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 27c69ad451e84..016fcc4ac5bee 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 @@ -42,7 +42,7 @@ module 0xc0ffee::m { enum Option { None, Some { - value: #0, + value: A, } } enum Outer { 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 93bcfd12e634f..d6fff4b1fb6bf 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, + f: T, } struct Pair { - f1: #0, - f2: #1, + f1: T1, + f2: T2, } struct R { dummy_field: bool, 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 438f27a7322ab..d5ccb52b48d21 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, + a: T2, } struct HasDrop { - a: #1, + a: T2, } struct HasKey { - a: #1, + a: T2, } struct HasStore { - a: #1, + a: T2, } struct NoAbilities { dummy_field: bool, } struct RequireStore { - a: #0, + a: T, } private fun f1(ref: &mut M::HasDrop) { ref = pack M::HasDrop(1); 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 cbc230acd5142..4b1929b32c2ae 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,34 +1,34 @@ // -- Model dump before bytecode pipeline module 0x42::M { struct HasAbilities { - a: #1, + a: T2, } struct HasCopy { - a: #1, + a: T2, } struct HasDrop { - a: #1, + a: T2, } struct HasKey { - a: #1, + a: T2, } struct HasStore { - a: #1, + a: T2, } struct NoAbilities { a: bool, } struct S1 { - a: #0, + a: T, } struct S2 { a: M::S1>, } struct S3 { - a: #0, - b: #1, - c: #2, - d: #3, + a: T1, + b: T2, + c: T3, + d: T4, } struct S4 { a: M::S3, M::HasCopy, M::HasStore, M::HasKey>, 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 bfa5c712d716a..c989623b114ba 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,16 +1,16 @@ // -- Model dump before bytecode pipeline module 0x42::M { struct HasCopy { - a: #1, + a: T2, } struct HasDrop { - a: #1, + a: T2, } struct HasKey { - a: #1, + a: T2, } struct HasStore { - a: #1, + a: T2, } struct NoAbilities { dummy_field: bool, 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 cd061f4b76d74..87b52a3c44aec 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 @@ -28,16 +28,16 @@ module 0x42::test { y: u8, } struct S4 { - x: #0, + x: T, y: test::S3, } struct S5 { - 0: #0, - 1: #1, + 0: T, + 1: U, } struct S6 { - x: #0, - y: #1, + x: T, + y: U, } struct S7 { 0: u8, 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..e9bb6db171607 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda3.exp @@ -0,0 +1,17 @@ +// -- Model dump before bytecode pipeline +module 0x8675309::M { + public fun lambda_not_allowed() { + { + let _x: |u64|u64 = |i: u64| Add(i, 1); + Tuple() + } + } +} // end 0x8675309::M + + +Diagnostics: +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/checking/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..7a6fd81d69593 --- /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 `|u64|`: + ┌─ tests/checking/inlining/lambda4.move:86:23 + │ +86 │ public inline fun macro_result_lambda_not_allowed(): |u64| { // expected lambda not allowed + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Functions may not return function-typed values, but function `M::fun_result_lambda_not_allowed` return type is `|u64|`: + ┌─ tests/checking/inlining/lambda4.move:89:16 + │ +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..8dc25cb601fb4 --- /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 `|u64|`: + ┌─ tests/checking/inlining/lambda5.move:86:23 + │ +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/naming/unused_type_parameter_struct.exp b/third_party/move/move-compiler-v2/tests/checking/naming/unused_type_parameter_struct.exp index bc74029181400..24c92c36b428b 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 @@ -49,16 +49,16 @@ module 0x42::test { dummy_field: bool, } struct S2 { - f: test::S3<#1>, + f: test::S3, } struct S3 { dummy_field: bool, } struct S4 { - f: vector<#0>, + f: vector, } struct S5 { - f: vector<#0>, - g: vector<#1>, + 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 d18cbc88a3820..0bed925598e10 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 @@ -18,16 +18,16 @@ module 0x42::test { dummy_field: bool, } struct S2 { - f: test::S3<#1>, + f: test::S3, } struct S3 { dummy_field: bool, } struct S4 { - f: vector<#0>, + f: vector, } struct S5 { - f: vector<#0>, - g: vector<#1>, + f: vector, + g: vector, } } // end 0x42::test 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 5280e3ddd0a51..456ba4a877dcc 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 @@ -16,9 +16,9 @@ module 0x42::test { 1: bool, } struct S3 { - 0: #1, + 0: T2, 1: u8, - 2: #0, + 2: T1, } private fun bar(x: test::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 3271dea2b7566..19444714c6765 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 @@ -7,20 +7,20 @@ module 0x42::test { 0: u8, } struct S2 { - 0: #0, + 0: T, 1: u8, } struct S3 { - 0: #0, + 0: T, 1: u8, } struct S4 { x: u8, - y: #0, + y: T, } struct S5 { - 0: #0, - 1: test::S3<#0>, + 0: T, + 1: test::S3, } struct S6 { dummy_field: bool, 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 c56d7f9c7a5c1..286130d5412c0 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 @@ -19,14 +19,14 @@ module 0x42::test { 1: bool, } struct S3 { - 0: #0, + 0: T, 1: u8, } struct S4 { dummy_field: bool, } struct S5 { - x: #0, + x: T, y: u8, } private fun S0_inhabited(): test::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 2b5cb1622dfa7..82b91830ecb21 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 @@ -2,7 +2,7 @@ module 0x42::test { enum Bar { A { - 0: #0, + 0: T, } B { 0: u8, @@ -11,7 +11,7 @@ module 0x42::test { } 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 8df2af098de89..701b2269dd3ee 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 @@ -39,8 +39,8 @@ module 0x42::n { module 0x42::m { use 0x42::n::{T}; // resolved as: 0x42::n struct G { - x: #0, - y: #1, + 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 b396815647805..045df0a157638 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, + x: T, } private fun id(self: m::S<#0>): m::S<#0> { 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 b396815647805..045df0a157638 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, + x: T, } private fun id(self: m::S<#0>): m::S<#0> { self 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 3ef30afac08f9..18adeb54b8b68 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 @@ -53,7 +53,7 @@ note: unused schema M::SchemaExp // -- Model dump before bytecode pipeline module 0x42::M { struct S { - x: #0, + 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 591fc4fd388df..9212527bc1ea8 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 @@ -4,7 +4,7 @@ module 0x42::M { x: u64, } struct G { - x: #0, + x: T, y: bool, } struct R { 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 e36049a6df034..0d20bff8595b6 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, + 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 2545066f07559..5bf0a3e5f29ee 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, + f: T, } struct S { dummy_field: bool, 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/lambda2.exp b/third_party/move/move-compiler-v2/tests/checking/typing/lambda2.exp new file mode 100644 index 0000000000000..3488e91208849 --- /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::macro_result_lambda_not_allowed` return type is `|u64|`: + ┌─ tests/checking/typing/lambda2.move:86:23 + │ +86 │ public inline fun macro_result_lambda_not_allowed(): |u64| { // expected lambda not allowed + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Functions may not return function-typed values, but function `M::fun_result_lambda_not_allowed` return type is `|u64|`: + ┌─ tests/checking/typing/lambda2.move:89:16 + │ +89 │ public fun fun_result_lambda_not_allowed(): |u64| { // expected lambda not allowed + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/lambda2.move b/third_party/move/move-compiler-v2/tests/checking/typing/lambda2.move new file mode 100644 index 0000000000000..5d7cc52daf2ae --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda2.move @@ -0,0 +1,100 @@ +module 0x8675309::M { + // use 0x1::XVector; + + // public inline fun foreach(v: &vector, action: |&T|) { // expected to be not implemented + // let i = 0; + // while (i < XVector::length(v)) { + // action(XVector::borrow(v, i)); + // i = i + 1; + // } + // } + + // public inline fun reduce(v: vector, accu: R, reducer: |T, R|R): R { + // while (!XVector::is_empty(&v)) { + // accu = reducer(XVector::pop_back(&mut v), accu); + // }; + // accu + // } + + + // public fun correct_foreach() { + // let v = vector[1, 2, 3]; + // let sum = 0; + // foreach(&v, |e| sum = sum + *e) // expected to be not implemented + // } + + // public fun correct_reduce(): u64 { + // let v = vector[1, 2, 3]; + // reduce(v, 0, |t, r| t + r) + // } + + // public fun corrected_nested() { + // let v = vector[vector[1,2], vector[3]]; + // let sum = 0; + // foreach(&v, |e| sum = sum + reduce!(*e, 0, |t, r| t + r)); + // } + + // public inline fun wrong_local_call_arg_count(v: &vector, action: |&T|) { + // let i = 0; + // while (i < XVector::length(v)) { + // action(XVector::borrow(v, i), i); // expected to have wrong argument count + // i = i + 1; + // } + // } + + // public inline fun wrong_local_call_arg_type(v: &vector, action: |&T|) { + // let i = 0; + // while (i < XVector::length(v)) { + // action(i); // expected to have wrong argument type + // i = i + 1; + // } + // } + + // public inline fun wrong_local_call_result_type(v: &vector, action: |&T|) { + // let i = 0; + // while (i < XVector::length(v)) { + // i = i + action(XVector::borrow(v, i)); // expected to have wrong result type + // } + // } + + // public fun wrong_local_call_no_fun(x: u64) { + // x(1) // expected to be not a function + // } + + // public fun wrong_lambda_inferred_type() { + // let v = vector[1, 2, 3]; + // let sum = 0; + // foreach(&v, |e| sum = sum + e) // expected to cannot infer type + // } + + // public fun wrong_lambda_result_type() { + // let v = vector[1, 2, 3]; + // let sum = 0; + // foreach(&v, |e| { sum = sum + *e; *e }) // expected to have wrong result type of lambda + // } + + public fun lambda_not_allowed() { + let _x = |i| i + 1; // expected lambda not allowed + } + + // struct FieldFunNotAllowed { + // f: |u64|u64, // expected lambda not allowed + // } + + public fun fun_arg_lambda_not_allowed(x: |u64|) {} // expected lambda not allowed + + public inline fun macro_result_lambda_not_allowed(): |u64| { // expected lambda not allowed + abort (1) + } + public fun fun_result_lambda_not_allowed(): |u64| { // expected lambda not allowed + abort (1) + } + +} + +// module 0x1::XVector { +// public fun length(v: &vector): u64 { abort(1) } +// public fun is_empty(v: &vector): bool { abort(1) } +// public fun borrow(v: &vector, i: u64): &T { abort(1) } +// public fun pop_back(v: &mut vector): T { abort(1) } +// } diff --git a/third_party/move/move-compiler-v2/tests/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 a729ac9e9d988..3b0b0935d3d28 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, + f1: T, } struct R { dummy_field: bool, 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 c4c982bba8e20..b2e5e4ab46938 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, + 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 d82dc536aca59..8710d11f47b25 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 @@ -4,11 +4,11 @@ module 0x42::simple_map { use std::option; use std::vector; struct Element { - key: #0, - value: #1, + key: Key, + value: Value, } struct SimpleMap { - data: vector>, + data: vector>, } public fun borrow(map: &simple_map::SimpleMap<#0, #1>,key: �):  { { 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 4e1a345132678..7002b18f808e9 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 @@ -4,17 +4,17 @@ module 0x42::M1 { a: u64, } struct S2 { - a: M1::S1<#0>, - b: vector>, + a: M1::S1, + b: vector>, } struct S3 { - a: #1, - b: #3, + a: T2, + b: T4, } struct S4 { a: u64, } struct S5 { - a: M1::S4<#0>, + a: M1::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 0d0ae4c52ac2e..c006b28884c9f 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, + 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 63252d1509136..0c41fd90aff73 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, + f1: T, + f2: T, } private fun new(): M::Box<#0> { 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 141500cd03452..d638034ca2547 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, + f1: T, + f2: T, } private fun new(): M::Box<#0> { 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 00bbfae97d9e5..0369a3da12beb 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, + f: V, } public fun get(_self: &Container::T<#0>): #0 { Abort(0) @@ -16,8 +16,8 @@ module 0x2::Container { module 0x2::M { use 0x2::Container; // resolved as: 0x2::Container struct Box { - f1: #0, - f2: #0, + f1: T, + f2: T, } private fun t0(): M::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 afd5f2f73d767..f02b528d31840 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 @@ -19,7 +19,7 @@ warning: unused type parameter // -- Model dump before bytecode pipeline module 0x2::Token { struct Coin { - type: #0, + type: AssetType, value: u64, } public fun create(type: #0,value: u64): Token::Coin<#0> { @@ -91,7 +91,7 @@ module 0x3::OneToOneMarket { record: Map::T, } struct Pool { - coin: Token::Coin<#0>, + coin: Token::Coin, } struct Price { price: u64, 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 b2f8b5a64657b..454ba0a69976f 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, + type: AssetType, value: u64, } public fun create(type: #0,value: u64): Token::Coin<#0> { @@ -93,7 +93,7 @@ module 0xb055::OneToOneMarket { record: u64, } struct Pool { - coin: Token::Coin<#0>, + coin: Token::Coin, } struct Price { price: u64, 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 2662bcbd649a7..75510f9e49735 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 @@ -11,7 +11,7 @@ module 0x815::m { } 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 2662bcbd649a7..75510f9e49735 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 @@ -11,7 +11,7 @@ module 0x815::m { } 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 079ed8439d493..cade5cdd10043 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, + 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 01e7a4ee24a6a..f0995c038ecd2 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, + 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 c61dde92a484d..e62a7f7bcb71e 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, + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (m::S, u64)| { + let y: u64 = x; + Add(x, y) + }) + } +} // end 0xcafe::m + + +// -- Model dump after env processor unused checks: +module 0xcafe::m { + struct S { + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (m::S, u64)| { + let y: u64 = x; + Add(x, y) + }) + } +} // end 0xcafe::m + + +// -- Model dump after env processor type parameter check: +module 0xcafe::m { + struct S { + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (m::S, u64)| { + let y: u64 = x; + Add(x, y) + }) + } +} // end 0xcafe::m + + +// -- Model dump after env processor check recursive struct definition: +module 0xcafe::m { + struct S { + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (m::S, u64)| { + let y: u64 = x; + Add(x, y) + }) + } +} // end 0xcafe::m + + +// -- Model dump after env processor check cyclic type instantiation: +module 0xcafe::m { + struct S { + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (m::S, u64)| { + let y: u64 = x; + Add(x, y) + }) + } +} // end 0xcafe::m + + +// -- Model dump after env processor unused struct params check: +module 0xcafe::m { + struct S { + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (m::S, u64)| { + let y: u64 = x; + Add(x, y) + }) + } +} // end 0xcafe::m + + +// -- Model dump after env processor access and use check before inlining: +module 0xcafe::m { + struct S { + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (m::S, u64)| { + let y: u64 = x; + Add(x, y) + }) + } +} // end 0xcafe::m + + +// -- Model dump after env processor inlining: +module 0xcafe::m { + struct S { + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (m::S, u64)| { + let y: u64 = x; + Add(x, y) + }) + } +} // end 0xcafe::m + + +// -- Model dump after env processor access and use check after inlining: +module 0xcafe::m { + struct S { + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (m::S, u64)| { + let y: u64 = x; + Add(x, y) + }) + } +} // end 0xcafe::m + + +// -- Model dump after env processor acquires check: +module 0xcafe::m { + struct S { + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, |(m::S{ x }, _y: u64): (m::S, u64)| { + let y: u64 = x; + Add(x, y) + }) + } +} // end 0xcafe::m + + +// -- Model dump after env processor simplifier: +module 0xcafe::m { + struct S { + x: T, } private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { (f)(s, x) @@ -18,7 +188,53 @@ module 0xcafe::m { // -- Model dump after env processor lambda-lifting: module 0xcafe::m { struct S { - x: #0, + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, closure m::pattern$lambda$1()) + } + private fun pattern$lambda$1(param$0: m::S,_y: u64): u64 { + { + let m::S{ x } = param$0; + { + let y: u64 = x; + Add(x, y) + } + } + } +} // end 0xcafe::m + + +// -- Model dump after env processor specification checker: +module 0xcafe::m { + struct S { + x: T, + } + private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { + (f)(s, x) + } + private fun pattern(s: m::S,x: u64): u64 { + m::consume(s, x, closure m::pattern$lambda$1()) + } + private fun pattern$lambda$1(param$0: m::S,_y: u64): u64 { + { + let m::S{ x } = param$0; + { + let y: u64 = x; + Add(x, y) + } + } + } +} // end 0xcafe::m + + +// -- Model dump after env processor specification rewriter: +module 0xcafe::m { + struct S { + x: T, } private fun consume(s: m::S<#0>,x: #0,f: |(m::S<#0>, #0)|#0): #0 { (f)(s, x) 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/testsuite.rs b/third_party/move/move-compiler-v2/tests/testsuite.rs index 850dd563cc379..eb0d506c1f699 100644 --- a/third_party/move/move-compiler-v2/tests/testsuite.rs +++ b/third_party/move/move-compiler-v2/tests/testsuite.rs @@ -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_PARAMS, true) + .set_experiment(Experiment::LAMBDA_RESULTS, 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/tests/move_check/typing/lambda2.exp b/third_party/move/move-compiler/tests/move_check/typing/lambda2.exp new file mode 100644 index 0000000000000..073ed797528e3 --- /dev/null +++ b/third_party/move/move-compiler/tests/move_check/typing/lambda2.exp @@ -0,0 +1,30 @@ +error[E04024]: invalid usage of function type + ┌─ tests/move_check/typing/lambda2.move:77:18 + │ +77 │ let _x = |i| i + 1; // expected lambda not allowed + │ ^^^^^^^^^ function type only allowed for inline function arguments + +error[E04024]: invalid usage of function type + ┌─ tests/move_check/typing/lambda2.move:81:12 + │ +81 │ f: |u64|u64, // expected lambda not allowed + │ ^^^^^^^^ function type only allowed for inline function arguments + +error[E04024]: invalid usage of function type + ┌─ tests/move_check/typing/lambda2.move:84:46 + │ +84 │ public fun fun_arg_lambda_not_allowed(x: |u64|) {} // expected lambda not allowed + │ ^^^^^ function type only allowed for inline function arguments + +error[E04024]: invalid usage of function type + ┌─ tests/move_check/typing/lambda2.move:86:58 + │ +86 │ public inline fun macro_result_lambda_not_allowed(): |u64| { // expected lambda not allowed + │ ^^^^^ function type only allowed for inline function arguments + +error[E04024]: invalid usage of function type + ┌─ tests/move_check/typing/lambda2.move:89:49 + │ +89 │ public fun fun_result_lambda_not_allowed(): |u64| { // expected lambda not allowed + │ ^^^^^ function type only allowed for inline function arguments + 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..50bdd1270ce25 --- /dev/null +++ b/third_party/move/move-compiler/tests/move_check/typing/lambda2.move @@ -0,0 +1,100 @@ +module 0x8675309::M { + // use 0x1::XVector; + + // public inline fun foreach(v: &vector, action: |&T|) { // expected to be not implemented + // let i = 0; + // while (i < XVector::length(v)) { + // action(XVector::borrow(v, i)); + // i = i + 1; + // } + // } + + // public inline fun reduce(v: vector, accu: R, reducer: |T, R|R): R { + // while (!XVector::is_empty(&v)) { + // accu = reducer(XVector::pop_back(&mut v), accu); + // }; + // accu + // } + + + // public fun correct_foreach() { + // let v = vector[1, 2, 3]; + // let sum = 0; + // foreach(&v, |e| sum = sum + *e) // expected to be not implemented + // } + + // public fun correct_reduce(): u64 { + // let v = vector[1, 2, 3]; + // reduce(v, 0, |t, r| t + r) + // } + + // public fun corrected_nested() { + // let v = vector[vector[1,2], vector[3]]; + // let sum = 0; + // foreach(&v, |e| sum = sum + reduce!(*e, 0, |t, r| t + r)); + // } + + // public inline fun wrong_local_call_arg_count(v: &vector, action: |&T|) { + // let i = 0; + // while (i < XVector::length(v)) { + // action(XVector::borrow(v, i), i); // expected to have wrong argument count + // i = i + 1; + // } + // } + + // public inline fun wrong_local_call_arg_type(v: &vector, action: |&T|) { + // let i = 0; + // while (i < XVector::length(v)) { + // action(i); // expected to have wrong argument type + // i = i + 1; + // } + // } + + // public inline fun wrong_local_call_result_type(v: &vector, action: |&T|) { + // let i = 0; + // while (i < XVector::length(v)) { + // i = i + action(XVector::borrow(v, i)); // expected to have wrong result type + // } + // } + + // public fun wrong_local_call_no_fun(x: u64) { + // x(1) // expected to be not a function + // } + + // public fun wrong_lambda_inferred_type() { + // let v = vector[1, 2, 3]; + // let sum = 0; + // foreach(&v, |e| sum = sum + e) // expected to cannot infer type + // } + + // public fun wrong_lambda_result_type() { + // let v = vector[1, 2, 3]; + // let sum = 0; + // foreach(&v, |e| { sum = sum + *e; *e }) // expected to have wrong result type of lambda + // } + + public fun lambda_not_allowed() { + let _x = |i| i + 1; // expected lambda not allowed + } + + struct FieldFunNotAllowed { + f: |u64|u64, // expected lambda not allowed + } + + public fun fun_arg_lambda_not_allowed(x: |u64|) {} // expected lambda not allowed + + public inline fun macro_result_lambda_not_allowed(): |u64| { // expected lambda not allowed + abort (1) + } + public fun fun_result_lambda_not_allowed(): |u64| { // expected lambda not allowed + abort (1) + } + +} + +// module 0x1::XVector { +// public fun length(v: &vector): u64 { abort(1) } +// public fun is_empty(v: &vector): bool { abort(1) } +// public fun borrow(v: &vector, i: u64): &T { abort(1) } +// public fun pop_back(v: &mut vector): T { abort(1) } +// } diff --git a/third_party/move/move-model/src/builder/model_builder.rs b/third_party/move/move-model/src/builder/model_builder.rs index 2be015a56a8dd..91d8a77e39d93 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 7cf73ae32f664..95d45397af623 100644 --- a/third_party/move/move-model/src/builder/module_builder.rs +++ b/third_party/move/move-model/src/builder/module_builder.rs @@ -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, @@ -3552,6 +3554,7 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> { name: name.symbol, loc: 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 a03fc714e1674..71f4059e609b9 100644 --- a/third_party/move/move-model/src/model.rs +++ b/third_party/move/move-model/src/model.rs @@ -1870,7 +1870,8 @@ impl GlobalEnv { let data = FunctionData { name, loc: loc.clone(), - id_loc: loc, + id_loc: loc.clone(), + result_type_loc: loc, def_idx: None, handle_idx: None, visibility, @@ -2368,7 +2369,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() { @@ -2422,6 +2422,7 @@ impl GlobalEnv { emitln!(writer, "{}", self.display(&*module_spec)); } for str in module.get_structs() { + let tctx = str.get_type_display_ctx(); if str.has_variants() { emitln!(writer, "enum {} {{", str.get_name().display(spool)); writer.indent(); @@ -2432,7 +2433,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, "}") @@ -2444,7 +2445,7 @@ impl GlobalEnv { emitln!(writer, "struct {} {{", str.get_name().display(spool)); writer.indent(); for fld in str.get_fields() { - emitln!(writer, "{},", self.dump_field(tctx, &fld)) + emitln!(writer, "{},", self.dump_field(&tctx, &fld)) } } writer.unindent(); @@ -2455,7 +2456,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!( @@ -3977,6 +3979,9 @@ pub struct FunctionData { /// 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, + /// The definition index of this function in its bytecode module, if a bytecode module /// is attached to the parent module data. pub(crate) def_idx: Option, @@ -4119,6 +4124,11 @@ impl<'env> FunctionEnv<'env> { self.data.id_loc.clone() } + /// Returns the location of the function identifier. + pub fn get_result_type_loc(&self) -> Loc { + self.data.result_type_loc.clone() + } + /// Returns the attributes of this function. pub fn get_attributes(&self) -> &[Attribute] { &self.data.attributes diff --git a/third_party/move/move-model/src/ty.rs b/third_party/move/move-model/src/ty.rs index 449be66bad45f..985a75766055d 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), @@ -528,7 +539,11 @@ impl Constraint { /// type parameter. This creates NoReference, 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, + ]; let TypeParameter( _, TypeParameterKind { @@ -552,6 +567,7 @@ impl Constraint { Constraint::NoPhantom, Constraint::NoReference, Constraint::NoTuple, + Constraint::NoFunction, ] } @@ -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) => { @@ -806,6 +824,11 @@ impl Type { matches!(self, Type::Reference(_, _)) } + /// Determines whether this is a function. + pub fn is_function(&self) -> bool { + matches!(self, Type::Fun(..)) + } + /// If this is a reference, return the kind of the reference, otherwise None. pub fn ref_kind(&self) -> Option { if let Type::Reference(kind, _) = self { @@ -1774,6 +1797,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 +2974,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",