diff --git a/Cargo.lock b/Cargo.lock index dbe8b1c7df442..59c962d5ccc1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11452,6 +11452,7 @@ dependencies = [ "codespan", "codespan-reporting", "datatest-stable", + "either", "internment", "itertools 0.13.0", "log", diff --git a/third_party/move/evm/move-to-yul/src/context.rs b/third_party/move/evm/move-to-yul/src/context.rs index ef8e251ee89e8..a8e9b29deef17 100644 --- a/third_party/move/evm/move-to-yul/src/context.rs +++ b/third_party/move/evm/move-to-yul/src/context.rs @@ -784,7 +784,7 @@ impl<'a> Context<'a> { Tuple(_) | TypeParameter(_) | Reference(_, _) - | Fun(_, _) + | Fun(..) | TypeDomain(_) | ResourceDomain(_, _, _) | Error diff --git a/third_party/move/evm/move-to-yul/src/solidity_ty.rs b/third_party/move/evm/move-to-yul/src/solidity_ty.rs index b47d59e5dfa48..7f44b34c35e4e 100644 --- a/third_party/move/evm/move-to-yul/src/solidity_ty.rs +++ b/third_party/move/evm/move-to-yul/src/solidity_ty.rs @@ -368,7 +368,7 @@ impl SolidityType { }, TypeParameter(_) | Reference(_, _) - | Fun(_, _) + | Fun(..) | TypeDomain(_) | ResourceDomain(_, _, _) | Error diff --git a/third_party/move/move-binary-format/src/file_format.rs b/third_party/move/move-binary-format/src/file_format.rs index 3037cec1eaea5..468bdcca9fd32 100644 --- a/third_party/move/move-binary-format/src/file_format.rs +++ b/third_party/move/move-binary-format/src/file_format.rs @@ -851,11 +851,19 @@ impl AbilitySet { ); /// The empty ability set pub const EMPTY: Self = Self(0); - /// Abilities for `Functions` + /// Minimal abilities for all `Functions` pub const FUNCTIONS: AbilitySet = Self(Ability::Drop as u8); + /// Maximal abilities for all `Functions`. This is used for identity when unifying function types. + pub const MAXIMAL_FUNCTIONS: AbilitySet = Self::PUBLIC_FUNCTIONS; /// Abilities for `Bool`, `U8`, `U64`, `U128`, and `Address` pub const PRIMITIVES: AbilitySet = Self((Ability::Copy as u8) | (Ability::Drop as u8) | (Ability::Store as u8)); + /// Abilities for `private` user-defined/"primitive" functions (not closures). + /// These can be be changed in module upgrades, so should not be stored + pub const PRIVATE_FUNCTIONS: AbilitySet = Self((Ability::Copy as u8) | (Ability::Drop as u8)); + /// Abilities for `public` user-defined/"primitive" functions (not closures) + pub const PUBLIC_FUNCTIONS: AbilitySet = + Self((Ability::Copy as u8) | (Ability::Drop as u8) | (Ability::Store as u8)); /// Abilities for `Reference` and `MutableReference` pub const REFERENCES: AbilitySet = Self((Ability::Copy as u8) | (Ability::Drop as u8)); /// Abilities for `Signer` 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 9cb45341d9743..19d571863998a 100644 --- a/third_party/move/move-compiler-v2/src/bytecode_generator.rs +++ b/third_party/move/move-compiler-v2/src/bytecode_generator.rs @@ -480,13 +480,13 @@ impl<'env> Generator<'env> { self.emit_with(*id, |attr| Bytecode::SpecBlock(attr, spec)); }, // TODO(LAMBDA) - ExpData::Lambda(id, _, _) => self.error( + 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(), + ExpData::Invoke(id, _exp, _) => self.error( + *id, "Calls to function values other than inline function parameters not yet supported", ), ExpData::Quant(id, _, _, _, _, _) => { @@ -564,6 +564,12 @@ impl<'env> Generator<'env> { Constant::Bool(false) } }, + Value::Function(_mid, _fid) => { + self.error( + id, + "Function-typed values not yet supported except as parameters to calls to inline functions"); + Constant::Bool(false) + }, } } } @@ -785,6 +791,11 @@ impl<'env> Generator<'env> { Operation::MoveFunction(m, f) => { self.gen_function_call(targets, id, m.qualified(*f), args) }, + // TODO(LAMBDA) + Operation::EarlyBind => self.error( + id, + "Function-typed values not yet supported except as parameters to calls to inline functions", + ), Operation::TestVariants(mid, sid, variants) => { self.gen_test_variants(targets, id, mid.qualified(*sid), variants, args) }, @@ -813,12 +824,6 @@ impl<'env> Generator<'env> { Operation::NoOp => {}, // do nothing - // 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(_)) | Operation::SpecFunction(_, _, _) diff --git a/third_party/move/move-compiler-v2/src/env_pipeline/ast_simplifier.rs b/third_party/move/move-compiler-v2/src/env_pipeline/ast_simplifier.rs index f60012a917544..62c9a6cf63d12 100644 --- a/third_party/move/move-compiler-v2/src/env_pipeline/ast_simplifier.rs +++ b/third_party/move/move-compiler-v2/src/env_pipeline/ast_simplifier.rs @@ -359,7 +359,7 @@ fn find_possibly_modified_vars( _ => {}, } }, - Lambda(node_id, pat, _) => { + Lambda(node_id, pat, _, _, _) => { // Define a new scope for bound vars, and turn off `modifying` within. match pos { VisitorPosition::Pre => { @@ -978,7 +978,8 @@ impl<'env> ExpRewriterFunctions for SimplifierRewriter<'env> { let ability_set = self .env() .type_abilities(&ty, self.func_env.get_type_parameters_ref()); - ability_set.has_ability(Ability::Drop) + // Don't drop a function-valued expression so we don't lose errors. + !ty.has_function() && ability_set.has_ability(Ability::Drop) } else { // We're missing type info, be conservative false diff --git a/third_party/move/move-compiler-v2/src/env_pipeline/flow_insensitive_checkers.rs b/third_party/move/move-compiler-v2/src/env_pipeline/flow_insensitive_checkers.rs index dd6dabec91723..72bbd295d5853 100644 --- a/third_party/move/move-compiler-v2/src/env_pipeline/flow_insensitive_checkers.rs +++ b/third_party/move/move-compiler-v2/src/env_pipeline/flow_insensitive_checkers.rs @@ -147,7 +147,7 @@ impl<'env, 'params> SymbolVisitor<'env, 'params> { Pre | Post | BeforeBody | MidMutate | BeforeThen | BeforeElse | PreSequenceValue => {}, }, - Lambda(_, pat, _) => { + Lambda(_, pat, _, _, _) => { match position { Pre => self.seen_uses.enter_scope(), Post => { 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 d7dbcc3cfce2b..958a13bde6425 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 @@ -11,7 +11,7 @@ use move_model::{ model::{FunId, FunctionEnv, GlobalEnv, Loc, ModuleEnv, NodeId, Parameter, QualifiedId}, ty::Type, }; -use std::{collections::BTreeSet, iter::Iterator, ops::Deref, vec::Vec}; +use std::{collections::BTreeSet, iter::Iterator, vec::Vec}; type QualifiedFunId = QualifiedId<FunId>; @@ -20,8 +20,8 @@ fn identify_function_types_with_functions_in_args(func_types: Vec<Type>) -> Vec< func_types .into_iter() .filter_map(|ty| { - if let Type::Fun(argt, _) = &ty { - if argt.deref().has_function() { + if let Type::Fun(args, _, _) = &ty { + if args.as_ref().has_function() { Some(ty) } else { None @@ -41,8 +41,8 @@ fn identify_function_typed_params_with_functions_in_rets( func_types .iter() .filter_map(|param| { - if let Type::Fun(_argt, rest) = ¶m.1 { - let rest_unboxed = rest.deref(); + if let Type::Fun(_args, result, _) = ¶m.1 { + let rest_unboxed = result.as_ref(); if rest_unboxed.has_function() { Some((*param, rest_unboxed)) } else { @@ -270,7 +270,7 @@ fn check_privileged_operations_on_structs(env: &GlobalEnv, fun_env: &FunctionEnv }, ExpData::Assign(_, pat, _) | ExpData::Block(_, pat, _, _) - | ExpData::Lambda(_, pat, _) => { + | ExpData::Lambda(_, pat, _, _, _) => { pat.visit_pre_post(&mut |_, pat| { if let Pattern::Struct(id, str, _, _) = pat { let module_id = str.module_id; @@ -344,7 +344,7 @@ pub fn check_access_and_use(env: &mut GlobalEnv, before_inlining: bool) { // Check that functions being called are accessible. if let Some(def) = caller_func.get_def() { - let callees_with_sites = def.called_funs_with_callsites(); + let callees_with_sites = def.used_funs_with_uses(); for (callee, sites) in &callees_with_sites { let callee_func = env.get_function(*callee); // Check visibility. diff --git a/third_party/move/move-compiler-v2/src/env_pipeline/inliner.rs b/third_party/move/move-compiler-v2/src/env_pipeline/inliner.rs index 636f0d95d6728..06eaa909705dd 100644 --- a/third_party/move/move-compiler-v2/src/env_pipeline/inliner.rs +++ b/third_party/move/move-compiler-v2/src/env_pipeline/inliner.rs @@ -90,7 +90,7 @@ pub fn run_inlining(env: &mut GlobalEnv, scope: RewritingScope, keep_inline_func let mut visited_targets = BTreeSet::new(); while let Some(target) = todo.pop_first() { if visited_targets.insert(target.clone()) { - let callees_with_sites = target.called_funs_with_call_sites(env); + let callees_with_sites = target.used_funs_with_uses(env); for (callee, sites) in callees_with_sites { todo.insert(RewriteTarget::MoveFun(callee)); targets.entry(RewriteTarget::MoveFun(callee)); @@ -1161,7 +1161,7 @@ impl<'env, 'rewriter> ExpRewriterFunctions for InlinedRewriter<'env, 'rewriter> }; let call_loc = self.env.get_node_loc(id); if let Some(lambda_target) = optional_lambda_target { - if let ExpData::Lambda(_, pat, body) = lambda_target.as_ref() { + if let ExpData::Lambda(_, pat, body, _, _) = lambda_target.as_ref() { let args_vec: Vec<Exp> = args.to_vec(); Some(InlinedRewriter::construct_inlined_call_expression( self.env, 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 8326c3e8af618..d16593bac2da0 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 @@ -13,15 +13,17 @@ //! not modify free variables. //! //! Lambda lifting rewrites lambda expressions into construction -//! of *closures*. A closure refers to a function and contains a partial list -//! of arguments for that function, essentially currying it. Example: +//! of *closures* using the `EarlyBind` operation. A closure refers to a function and contains a list +//! of "early bound" leading arguments for that function, essentially currying it. We use the +//! `EarlyBind` operation to construct a closure from a function and set of arguments, +//! which must be the first `k` arguments to the function argument list. //! //! ```ignore //! let c = 1; //! vec.any(|x| x > c) //! ==> //! let c = 1; -//! vec.any(Closure(lifted, c)) +//! vec.any(EarlyBind(lifted, c)) //! where //! fun lifted(c: u64, x: u64): bool { x > c } //! ``` @@ -34,19 +36,19 @@ //! vec.any(|S{x}| x > c) //! ==> //! let c = 1; -//! vec.any(Closure(lifted, c)) +//! vec.any(EarlyBind(lifted, c)) //! where //! fun lifted(c: u64, arg$2: S): bool { let S{x} = arg$2; x > y } //! ``` use itertools::Itertools; -use move_binary_format::file_format::Visibility; +use move_binary_format::file_format::{AbilitySet, Visibility}; use move_model::{ - ast::{Exp, ExpData, Operation, Pattern, TempIndex}, + ast::{self, Exp, ExpData, LambdaCaptureKind, Operation, Pattern, TempIndex}, exp_rewriter::{ExpRewriter, ExpRewriterFunctions, RewriteTarget}, - model::{FunId, FunctionEnv, GlobalEnv, Loc, NodeId, Parameter, TypeParameter}, + model::{FunId, FunctionEnv, GlobalEnv, Loc, ModuleId, NodeId, Parameter, TypeParameter}, symbol::Symbol, - ty::{ReferenceKind, Type}, + ty::{AbilityInference, AbilityInferer, ReferenceKind, Type}, }; use std::{ collections::{BTreeMap, BTreeSet}, @@ -185,13 +187,360 @@ impl<'a> LambdaLifter<'a> { let env = self.fun_env.module_env.env; let body = self.bind(bindings, exp); let loc = env.get_node_loc(pat.node_id()); - let ty = env.get_node_type(body.node_id()); + let body_id = body.node_id(); + let ty = env.get_node_type(body_id); let new_id = env.new_node(loc, ty); + if let Some(inst) = env.get_node_instantiation_opt(body_id) { + env.set_node_instantiation(new_id, inst); + } ExpData::Block(new_id, pat, Some(binding), body).into_exp() } else { exp } } + + /// For the current state, calculate: (params, closure_args, param_index_mapping), where + /// - `params` = new Parameter for each free var to represent it in the lifted function + /// - `closure_args` = corresponding expressions to provide as actual arg for each param + /// - `param_index_mapping` = for each free var which is a Parameter from the enclosing function, + /// a mapping from index there to index in the params list + fn get_params_for_freevars( + &mut self, + ) -> Option<(Vec<Parameter>, Vec<Exp>, BTreeMap<usize, usize>)> { + let env = self.fun_env.module_env.env; + let mut closure_args = vec![]; + + // Add captured parameters. We also need to record a mapping of + // parameter indices in the lambda context to indices in the lifted + // functions (courtesy of #12317) + let mut param_index_mapping = BTreeMap::new(); + let mut params = vec![]; + let ty_params = self.fun_env.get_type_parameters_ref(); + let ability_inferer = AbilityInferer::new(env, ty_params); + let mut saw_error = false; + + for (used_param_count, (param, var_info)) in + mem::take(&mut self.free_params).into_iter().enumerate() + { + let name = self.fun_env.get_local_name(param); + let var_node_id = var_info.node_id; + let ty = env.get_node_type(var_node_id); + let loc = env.get_node_loc(var_node_id); + if var_info.modified { + env.error( + &loc, + &format!( + "captured variable `{}` cannot be modified inside of a lambda", // TODO(LAMBDA) + name.display(env.symbol_pool()) + ), + ); + saw_error = true; + } + let param_abilities = ability_inferer.infer_abilities(&ty).1; + if !param_abilities.has_copy() { + env.error( + &loc, + &format!( + "captured variable `{}` must have a value with `copy` ability", // TODO(LAMBDA) + name.display(env.symbol_pool()) + ), + ); + saw_error = true; + } + params.push(Parameter(name, ty.clone(), loc.clone())); + let new_id = env.new_node(loc, ty); + if let Some(inst) = env.get_node_instantiation_opt(var_node_id) { + env.set_node_instantiation(new_id, inst); + } + closure_args.push(ExpData::Temporary(new_id, param).into_exp()); + param_index_mapping.insert(param, used_param_count); + } + + // Add captured LocalVar parameters + for (name, var_info) in mem::take(&mut self.free_locals) { + let var_info_id = var_info.node_id; + let ty = env.get_node_type(var_info_id); + let loc = env.get_node_loc(var_info_id); + if var_info.modified { + env.error( + &loc, + &format!( + "captured variable `{}` cannot be modified inside of a lambda", // TODO(LAMBDA) + name.display(env.symbol_pool()) + ), + ); + saw_error = true; + } + params.push(Parameter(name, ty.clone(), loc.clone())); + let new_id = env.new_node(loc, ty); + if let Some(inst) = env.get_node_instantiation_opt(var_info_id) { + env.set_node_instantiation(new_id, inst); + } + closure_args.push(ExpData::LocalVar(new_id, name).into_exp()) + } + + if !saw_error { + Some((params, closure_args, param_index_mapping)) + } else { + None + } + } + + // If final `args` match `lambda_params`, and all other args are simple, then returns + // the simple prefix of `args`. + fn get_args_if_simple<'b>( + lambda_params: &[Parameter], + args: &'b [Exp], + ) -> Option<Vec<&'b Exp>> { + if lambda_params.len() <= args.len() { + let mut simple_args: Vec<&Exp> = + args.iter().filter(|arg| Self::exp_is_simple(arg)).collect(); + if simple_args.len() == args.len() + && lambda_params + .iter() + .rev() + .zip(simple_args.iter().rev()) + .all(|(param, arg)| { + if let ExpData::LocalVar(_, name) = arg.as_ref() { + *name == param.get_name() + } else { + false + } + }) + { + let remaining_size = args.len() - lambda_params.len(); + simple_args.truncate(remaining_size); + return Some(simple_args); + } + } + None + } + + // Only allow simple expressions which cannot vary or abort, since we are pulling + // them out of the lambda expression and evaluating them in order to bind them to + // the closure eary. + fn exp_is_simple(exp: &Exp) -> bool { + use ExpData::*; + match exp.as_ref() { + Call(_, Operation::EarlyBind, args) => args.iter().all(Self::exp_is_simple), + Call(_, op, args) => { + op.is_ok_to_remove_from_code() && args.iter().all(Self::exp_is_simple) + }, + Sequence(_, exp_vec) => { + if let [exp] = &exp_vec[..] { + Self::exp_is_simple(exp) + } else { + false + } + }, + IfElse(_, e1, e2, e3) => { + Self::exp_is_simple(e1) && Self::exp_is_simple(e2) && Self::exp_is_simple(e3) + }, + Lambda(_, _pat, _body, _capture_kind, _abilities) => { + // Maybe could test lambda_is_direct_curry(pat, body) + // and do something with it, but it is nontrivial. + false + }, + LocalVar(..) | Temporary(..) | Value(..) => true, + Invalid(..) | Invoke(..) | Quant(..) | Block(..) | Match(..) | Return(..) + | Loop(..) | LoopCont(..) | Assign(..) | Mutate(..) | SpecBlock(..) => false, + } + } + + fn make_move_fn_exp( + &mut self, + loc: Loc, + fn_type: Type, + module_id: ModuleId, + fun_id: FunId, + instantiation: Option<Vec<Type>>, + ) -> Exp { + let env = self.fun_env.module_env.env; + let id = env.new_node(loc, fn_type); + if let Some(inst) = instantiation { + env.set_node_instantiation(id, inst); + } + let fn_exp = ExpData::Value(id, ast::Value::Function(module_id, fun_id)); + fn_exp.into_exp() + } + + fn get_move_fn_type(&mut self, expr_id: NodeId, module_id: ModuleId, fun_id: FunId) -> Type { + let env = self.fun_env.module_env.env; + let fn_env = env.get_function(module_id.qualified(fun_id)); + let fun_abilities = if fn_env.visibility().is_public() { + AbilitySet::PUBLIC_FUNCTIONS + } else { + AbilitySet::PRIVATE_FUNCTIONS + }; + let params = fn_env.get_parameters_ref(); + let param_types = params.iter().map(|param| param.get_type()).collect(); + let node_instantiation = env.get_node_instantiation(expr_id); + let result_type = fn_env.get_result_type(); + Type::Fun( + Box::new(Type::Tuple(param_types)), + Box::new(result_type), + fun_abilities, + ) + .instantiate(&node_instantiation) + } + + // If body is a function call expression with the function value and each parameter a + // simple expression (constant, var, or Move function name), with the last arguments the + // provided `lambda_params` in sequence, then returns the function name and the prefix + // arguments. Otherwise, returns `None`. + fn lambda_reduces_to_curry<'b>( + &mut self, + lambda_params: &Vec<Parameter>, + body: &'b Exp, + ) -> Option<(Exp, Vec<&'b Exp>)> { + use ExpData::*; + let env = self.fun_env.module_env.env; + match body.as_ref() { + Call(id, oper, args) => { + match oper { + Operation::EarlyBind => { + // TODO(LAMBDA): We might be able to to do something with this, + // but skip for now because it will be complicated. + None + }, + Operation::MoveFunction(mid, fid) => { + Self::get_args_if_simple(lambda_params, args).map(|args| { + let fn_type = self.get_move_fn_type(*id, *mid, *fid); + let loc = env.get_node_loc(*id); + let fn_exp = self.make_move_fn_exp( + loc, + fn_type, + *mid, + *fid, + env.get_node_instantiation_opt(*id), + ); + (fn_exp, args) + }) + }, + _ => None, + } + }, + Invoke(_id, fn_exp, args) => { + Self::get_args_if_simple(lambda_params, args).and_then(|args| { + // Function expression may not contain lambda params + let free_vars = fn_exp.as_ref().free_vars(); + if lambda_params + .iter() + .all(|param| !free_vars.contains(¶m.get_name())) + && Self::exp_is_simple(fn_exp) + { + Some((fn_exp.clone(), args)) + } else { + None + } + }) + }, + ExpData::Sequence(_id, exp_vec) => { + if let [exp] = &exp_vec[..] { + self.lambda_reduces_to_curry(lambda_params, exp) + } else { + None + } + }, + _ => None, + } + } + + // We can rewrite a lambda directly into a curry expression if: + // - lambda parameters are a simple variable tuple (v1, v2, ...) === (bindings.is_empty()) + // Caller should already check that, and place the tuple of variables in parameter list lambda_params. + // + // Then, we can reduce to curry if: + // - lambda body is a function call with + // - lambda parameters used (in order) as the last arguments to the function call. + // - the function called and every other argument is a simple expression containing only + // constants and free variables which cannot abort + // Arguments here are + // - id: original lambda expr NodeId + // - body: body of lambda + // - lambda_params: a Parameter corresponding to each lambda param + fn try_to_reduce_lambda_to_curry( + &mut self, + id: NodeId, + body: &Exp, + lambda_params: Vec<Parameter>, + abilities: &AbilitySet, + ) -> Option<Exp> { + if let Some((fn_exp, args)) = self.lambda_reduces_to_curry(&lambda_params, body) { + // lambda has form |lambda_params| fn_exp(args, ...lambda_params) + // where each arg is a constant or simple variable, not in lambda_params, + // except the trailing k params which are all lambda_params + let mut new_args: Vec<_> = args.into_iter().cloned().collect(); + + let env = self.fun_env.module_env.env; + let fn_id = fn_exp.node_id(); + let fn_type = env.get_node_type(fn_id); + if let Type::Fun(_fn_param_type, _fn_result_type, fun_abilities) = &fn_type { + // First param to EarlyBind is the function expr + new_args.insert(0, fn_exp); + let ty_params = self.fun_env.get_type_parameters_ref(); + // Check bound value abilities + let ability_inferer = AbilityInferer::new(env, ty_params); + let bound_value_abilities: Vec<_> = new_args + .iter() + .map(|exp| { + let node = exp.as_ref().node_id(); + let ty = env.get_node_type(node); + let node_abilities = ability_inferer.infer_abilities(&ty).1; + (env.get_node_loc(node), node_abilities) + }) + .collect(); + let mut bound_value_missing_abilities: Vec<_> = bound_value_abilities + .iter() + .filter_map(|(loc, node_abilities)| { + if !abilities.is_subset(*node_abilities) { + let missing = abilities.setminus(*node_abilities); + Some(( + loc.clone(), + format!("Captured free value is missing abilities: {}", missing), + )) + } else { + None + } + }) + .collect(); + if !abilities.is_subset(*fun_abilities) { + let missing = abilities.setminus(*fun_abilities); + let tdc = env.get_type_display_ctx(); + bound_value_missing_abilities.push(( + env.get_node_loc(fn_id), + format!( + "Base function of closure has type {}, is missing abilities: {}", + fn_type.display(&tdc), + missing + ), + )); + } + let closure_abilities = bound_value_abilities + .iter() + .map(|(_loc, node_abilities)| *node_abilities) + .reduce(|abs1, abs2| abs1.intersect(abs2)) + .unwrap_or(*fun_abilities); + if !bound_value_missing_abilities.is_empty() { + let missing_abilities = abilities.setminus(closure_abilities); + let loc = env.get_node_loc(id); + env.error_with_labels( + &loc, + &format!("Lambda captures free variables with types that do not have some declared abilities: {}", + missing_abilities), + bound_value_missing_abilities); + return None; + }; + if new_args.len() == 1 { + // We have no parameters, just use the function directly. + return Some(new_args.pop().unwrap()); + } else { + return Some(ExpData::Call(id, Operation::EarlyBind, new_args).into_exp()); + } + } + } + None + } } impl<'a> ExpRewriterFunctions for LambdaLifter<'a> { @@ -288,79 +637,92 @@ impl<'a> ExpRewriterFunctions for LambdaLifter<'a> { None } - fn rewrite_lambda(&mut self, id: NodeId, pat: &Pattern, body: &Exp) -> Option<Exp> { + fn rewrite_lambda( + &mut self, + id: NodeId, + pat: &Pattern, + body: &Exp, + capture_kind: LambdaCaptureKind, + abilities: AbilitySet, // TODO(LAMBDA): do something with this + ) -> Option<Exp> { if self.exempted_lambdas.contains(&id) { return None; } let env = self.fun_env.module_env.env; - let mut params = vec![]; - let mut closure_args = vec![]; - // Add captured parameters. We also need to record a mapping of - // parameter indices in the lambda context to indices in the lifted - // functions (courtesy of #12317) - let mut param_index_mapping = BTreeMap::new(); - for (used_param_count, (param, var_info)) in - mem::take(&mut self.free_params).into_iter().enumerate() - { - let name = self.fun_env.get_local_name(param); - let ty = env.get_node_type(var_info.node_id); - let loc = env.get_node_loc(var_info.node_id); - if var_info.modified { - env.error( - &loc, - &format!( - "captured variable `{}` cannot be modified inside of a lambda", // TODO(LAMBDA) - name.display(env.symbol_pool()) - ), - ); - } - params.push(Parameter(name, ty.clone(), loc.clone())); - let new_id = env.new_node(loc, ty); - closure_args.push(ExpData::Temporary(new_id, param).into_exp()); - param_index_mapping.insert(param, used_param_count); - } - // Add captured locals - for (name, var_info) in mem::take(&mut self.free_locals) { - let ty = env.get_node_type(var_info.node_id); - let loc = env.get_node_loc(var_info.node_id); - if var_info.modified { + let module_id = self.fun_env.module_env.get_id(); + + match capture_kind { + LambdaCaptureKind::Move => { + // OK. + }, + LambdaCaptureKind::Default | LambdaCaptureKind::Copy => { + let loc = env.get_node_loc(id); env.error( &loc, - &format!( - "captured variable `{}` cannot be modified inside of a lambda", // TODO(LAMBDA) - name.display(env.symbol_pool()) - ), + // TODO(LAMBDA) + "Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call." ); - } - params.push(Parameter(name, ty.clone(), loc.clone())); - let new_id = env.new_node(loc, ty); - closure_args.push(ExpData::LocalVar(new_id, name).into_exp()) - } + return None; + }, + }; + + // params = new Parameter for each free var to represent it in the lifted function + // closure_args = corresponding expressions to provide as actual arg for each param + // param_index_mapping = for each free var which is a Parameter from the enclosing function, + // a mapping from index there to index in the params list; other free vars are + // substituted automatically by using the same symbol for the param + let (mut params, mut closure_args, param_index_mapping) = self.get_params_for_freevars()?; + + // Some(ExpData::Invalid(env.clone_node(id)).into_exp()); // Add lambda args. For dealing with patterns in lambdas (`|S{..}|e`) we need // to collect a list of bindings. let mut bindings = vec![]; + let mut lambda_params = vec![]; for (i, arg) in pat.clone().flatten().into_iter().enumerate() { let id = arg.node_id(); let ty = env.get_node_type(id); let loc = env.get_node_loc(id); if let Pattern::Var(_, name) = arg { - params.push(Parameter(name, ty, loc)) + lambda_params.push(Parameter(name, ty, loc)); } else { let name = self.gen_parameter_name(i); - params.push(Parameter(name, ty.clone(), loc.clone())); + lambda_params.push(Parameter(name, ty.clone(), loc.clone())); let new_id = env.new_node(loc, ty); + if let Some(inst) = env.get_node_instantiation_opt(id) { + env.set_node_instantiation(new_id, inst); + } bindings.push((arg.clone(), ExpData::LocalVar(new_id, name).into_exp())) } } + + // We can rewrite a lambda directly into a curry expression if: + // - lambda parameters are a simple variable tuple (v1, v2, ...) === (bindings.is_empty()) + // + // - lambda body is a function call with + // - each lambda parameter used exactly once as a call argument, in order (possibly with gaps) + // - every other argument is a simple expression containing only constants and free variables + if bindings.is_empty() { + let possible_curry_exp = + self.try_to_reduce_lambda_to_curry(id, body, lambda_params.clone(), &abilities); + if possible_curry_exp.is_some() { + return possible_curry_exp; + } + } + + // Following code assumes params include lambda_params + params.append(&mut lambda_params); + // Add new closure function let fun_name = self.gen_closure_function_name(); let lambda_loc = env.get_node_loc(id).clone(); let lambda_type = env.get_node_type(id); - let result_type = if let Type::Fun(_, result_type) = &lambda_type { + let lambda_inst_opt = env.get_node_instantiation_opt(id); + let result_type = if let Type::Fun(_, result_type, _) = &lambda_type { *result_type.clone() } else { Type::Error // type error reported }; + // Rewrite references to Temporary in the new functions body (#12317) let mut replacer = |id: NodeId, target: RewriteTarget| { if let RewriteTarget::Temporary(temp) = target { @@ -370,23 +732,52 @@ impl<'a> ExpRewriterFunctions for LambdaLifter<'a> { None }; let body = ExpRewriter::new(env, &mut replacer).rewrite_exp(body.clone()); + let fun_id = FunId::new(fun_name); + let params_types = params.iter().map(|param| param.get_type()).collect(); + if abilities.has_store() { + let loc = env.get_node_loc(id); + env.error( + &loc, + // TODO(LAMBDA) + "Lambdas expressions with `store` ability currently may only be a simple call to an existing `public` function. This lambda expression requires defining a `public` helper function, which is not yet supported." + ); + return None; + }; self.lifted.push(ClosureFunction { loc: lambda_loc.clone(), - fun_id: FunId::new(fun_name), + fun_id, type_params: self.fun_env.get_type_parameters(), params, - result_type, + result_type: result_type.clone(), def: self.bind(bindings, body), }); - // Return closure expression - let id = env.new_node(lambda_loc, lambda_type); - Some( - ExpData::Call( - id, - Operation::Closure(self.fun_env.module_env.get_id(), FunId::new(fun_name)), - closure_args, - ) - .into_exp(), - ) + + // Create an expression for the function reference + let fn_type = Type::Fun( + Box::new(Type::Tuple(params_types)), + Box::new(result_type), + abilities, + ); + let fn_exp = self.make_move_fn_exp( + lambda_loc.clone(), + fn_type, + module_id, + fun_id, + lambda_inst_opt.clone(), + ); + + let bound_param_count = closure_args.len(); + if bound_param_count == 0 { + // No free variables, just return the function reference + Some(fn_exp) + } else { + // Create and return closure expression + let id = env.new_node(lambda_loc, lambda_type); + if let Some(inst) = lambda_inst_opt { + env.set_node_instantiation(id, inst); + } + closure_args.insert(0, fn_exp); + Some(ExpData::Call(id, Operation::EarlyBind, closure_args).into_exp()) + } } } diff --git a/third_party/move/move-compiler-v2/src/env_pipeline/rewrite_target.rs b/third_party/move/move-compiler-v2/src/env_pipeline/rewrite_target.rs index 2851f5c2b79c3..9e7adfe62d3b1 100644 --- a/third_party/move/move-compiler-v2/src/env_pipeline/rewrite_target.rs +++ b/third_party/move/move-compiler-v2/src/env_pipeline/rewrite_target.rs @@ -159,8 +159,8 @@ impl RewriteTargets { } impl RewriteTarget { - /// Gets the call sites for the target. - pub fn called_funs_with_call_sites( + /// Gets the functions called or referenced in the target. + pub fn used_funs_with_uses( &self, env: &GlobalEnv, ) -> BTreeMap<QualifiedId<FunId>, BTreeSet<NodeId>> { @@ -179,7 +179,7 @@ impl RewriteTarget { .unwrap_or_default(), SpecBlock(target) => { let spec = env.get_spec_block(target); - spec.called_funs_with_callsites() + spec.used_funs_with_uses() }, } } diff --git a/third_party/move/move-compiler-v2/src/env_pipeline/spec_rewriter.rs b/third_party/move/move-compiler-v2/src/env_pipeline/spec_rewriter.rs index dd9fd65ae1402..1251e40f021ee 100644 --- a/third_party/move/move-compiler-v2/src/env_pipeline/spec_rewriter.rs +++ b/third_party/move/move-compiler-v2/src/env_pipeline/spec_rewriter.rs @@ -70,7 +70,7 @@ pub fn run_spec_rewriter(env: &mut GlobalEnv) { if let RewriteState::Def(def) = target.get_env_state(env) { let mut spec_callees = BTreeSet::new(); def.visit_inline_specs(&mut |spec| { - spec_callees.extend(spec.called_funs_with_callsites().into_keys()); + spec_callees.extend(spec.used_funs_with_uses().into_keys()); true // keep going }); spec_callees @@ -78,10 +78,9 @@ pub fn run_spec_rewriter(env: &mut GlobalEnv) { BTreeSet::new() } }, - RewriteTarget::SpecFun(_) | RewriteTarget::SpecBlock(_) => target - .called_funs_with_call_sites(env) - .into_keys() - .collect(), + RewriteTarget::SpecFun(_) | RewriteTarget::SpecBlock(_) => { + target.used_funs_with_uses(env).into_keys().collect() + }, }; for callee in callees { called_funs.insert(callee); 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 e9da0d5cbb053..a7a22a0186aca 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 @@ -60,7 +60,7 @@ fn used_type_parameters_in_ty(ty: &Type) -> BTreeSet<u16> { }, Type::TypeParameter(i) => BTreeSet::from([*i]), Type::Vector(ty) => used_type_parameters_in_ty(ty), - Type::Fun(t1, t2) => [t1, t2] + Type::Fun(t1, t2, _) => [t1, t2] .iter() .flat_map(|t| used_type_parameters_in_ty(t)) .collect(), 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 ab7c9b862dbd0..ce120a5ca1170 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 @@ -367,7 +367,7 @@ impl ModuleGenerator { ReferenceKind::Mutable => FF::SignatureToken::MutableReference(target_ty), } }, - Fun(_param_ty, _result_ty) => { + Fun(_param_ty, _result_ty, _abilities) => { // TODO(LAMBDA) ctx.error( loc, @@ -1077,7 +1077,7 @@ impl<'env> ModuleContext<'env> { if fun.is_inline() { continue; } - if let Some(callees) = fun.get_called_functions() { + if let Some(callees) = fun.get_used_functions() { let mut usage = usage_map[&fun.get_id()].clone(); let count = usage.len(); // Extend usage by that of callees from the same module. Acquires is only 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 index 7d3fd078fd386..a6dcbc1ea7faf 100644 --- a/third_party/move/move-compiler-v2/tests/checking/inlining/lambda3.exp +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda3.exp @@ -2,7 +2,7 @@ module 0x8675309::M { public fun lambda_not_allowed() { { - let _x: |u64|u64 = |i: u64| Add<u64>(i, 1); + let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1); Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_cast_err.exp b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_cast_err.exp index be195864c9919..0ad81c2553b97 100644 --- a/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_cast_err.exp +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_cast_err.exp @@ -1,6 +1,6 @@ Diagnostics: -error: cannot pass `|(u64, integer)|u64` to a function which expects argument of type `|(u64, vector<u8>)|u64` +error: cannot pass `|(u64, integer)|u64 with copy+store` to a function which expects argument of type `|(u64, vector<u8>)|u64` ┌─ tests/checking/inlining/lambda_cast_err.move:7:53 │ 7 │ vector::fold(gas_schedule_blob, (0 as u64), |sum, addend| sum + (addend as u64)) diff --git a/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_param_mismatch.exp b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_param_mismatch.exp index 3ed89d4ab8da6..a4c911fe997fd 100644 --- a/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_param_mismatch.exp +++ b/third_party/move/move-compiler-v2/tests/checking/inlining/lambda_param_mismatch.exp @@ -1,6 +1,6 @@ Diagnostics: -error: cannot pass `|u64|u64` to a function which expects argument of type `|u64|` +error: cannot pass `|u64|u64 with copy+store` to a function which expects argument of type `|u64|` ┌─ tests/checking/inlining/lambda_param_mismatch.move:12:33 │ 12 │ vector::for_each(input, |item| { diff --git a/third_party/move/move-compiler-v2/tests/checking/specs/expressions_err.exp b/third_party/move/move-compiler-v2/tests/checking/specs/expressions_err.exp index 3e4cf9f7f3155..fccf940f86384 100644 --- a/third_party/move/move-compiler-v2/tests/checking/specs/expressions_err.exp +++ b/third_party/move/move-compiler-v2/tests/checking/specs/expressions_err.exp @@ -36,7 +36,7 @@ error: cannot pass `u256` to a function which expects argument of type `bool` 32 │ wrongly_typed_callee(1, 1) // Wrongly typed function application │ ^ -error: cannot pass `|num|bool` to a function which expects argument of type `|num|num` +error: cannot pass `|num|bool with copy+store` to a function which expects argument of type `|num|num` ┌─ tests/checking/specs/expressions_err.move:37:36 │ 37 │ wrongly_typed_fun_arg_callee(|x| false) // Wrongly typed function argument. 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 ebcdc1fcfcfdb..51ad60912dcd3 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 @@ -24,7 +24,7 @@ error: cannot use `()` with an operator which expects a value of type `u64` 56 │ i = i + action(XVector::borrow(v, i)); // expected to have wrong result type │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: cannot return `u64` from a function with result type `|integer|` +error: cannot return `u64` from a function with result type `|integer| with copy+store` ┌─ tests/checking/typing/lambda.move:61:9 │ 61 │ x(1) // expected to be not a function diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/lambda3.exp b/third_party/move/move-compiler-v2/tests/checking/typing/lambda3.exp index f89935a0c3358..2d5f47f0bb197 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/lambda3.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/lambda3.exp @@ -2,7 +2,7 @@ module 0x8675309::M { public fun lambda_not_allowed() { { - let _x: |u64|u64 = |i: u64| Add<u64>(i, 1); + let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1); Tuple() } } 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 7817686444d8f..b3c6fa59c5fb7 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 @@ -18,7 +18,7 @@ error: cannot use `()` with an operator which expects a value of type `u64` 56 │ i = i + action(XVector::borrow(v, i)); // expected to have wrong result type │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: cannot return `u64` from a function with result type `|integer|` +error: cannot return `u64` from a function with result type `|integer| with copy+store` ┌─ tests/checking/typing/lambda_typed.move:61:9 │ 61 │ x(1) // expected to be not a function @@ -30,7 +30,7 @@ error: cannot use `&u64` with an operator which expects a value of type `integer 67 │ foreach(&v, |e: &u64| sum = sum + e) // expected to cannot infer type │ ^ -error: cannot pass `|&u64|u64` to a function which expects argument of type `|&u64|` +error: cannot pass `|&u64|u64 with copy+store` to a function which expects argument of type `|&u64|` ┌─ tests/checking/typing/lambda_typed.move:73:21 │ 73 │ foreach(&v, |e: &u64| { sum = sum + *e; *e }) // expected to have wrong result type of lambda diff --git a/third_party/move/move-compiler-v2/tests/lambda-lifting/basic.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda-lifting/basic.lambda.exp index aecce2d0e9059..0571c26b0aa88 100644 --- a/third_party/move/move-compiler-v2/tests/lambda-lifting/basic.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda-lifting/basic.lambda.exp @@ -218,114 +218,21 @@ module 0xcafe::m { } // end 0xcafe::m -// -- Model dump after env processor lambda-lifting: -module 0xcafe::m { - private fun map(x: u64,f: |u64|u64): u64 { - (f)(x) - } - private fun no_name_clash(x: u64,c: u64): u64 { - m::map(x, closure m::no_name_clash$lambda$1(c)) - } - private fun with_name_clash1(x: u64,c: u64): u64 { - m::map(x, closure m::with_name_clash1$lambda$1(c)) - } - private fun with_name_clash2(x: u64,c: u64): u64 { - m::map(x, closure m::with_name_clash2$lambda$1(c)) - } - private fun no_name_clash$lambda$1(c: u64,y: u64): u64 { - Add<u64>(y, c) - } - private fun with_name_clash1$lambda$1(c: u64,x: u64): u64 { - Add<u64>(x, c) - } - private fun with_name_clash2$lambda$1(c: u64,x: u64): u64 { - Add<u64>({ - let x: u64 = Add<u64>(c, 1); - x - }, x) - } -} // end 0xcafe::m - - -// -- Model dump after env processor specification checker: -module 0xcafe::m { - private fun map(x: u64,f: |u64|u64): u64 { - (f)(x) - } - private fun no_name_clash(x: u64,c: u64): u64 { - m::map(x, closure m::no_name_clash$lambda$1(c)) - } - private fun with_name_clash1(x: u64,c: u64): u64 { - m::map(x, closure m::with_name_clash1$lambda$1(c)) - } - private fun with_name_clash2(x: u64,c: u64): u64 { - m::map(x, closure m::with_name_clash2$lambda$1(c)) - } - private fun no_name_clash$lambda$1(c: u64,y: u64): u64 { - Add<u64>(y, c) - } - private fun with_name_clash1$lambda$1(c: u64,x: u64): u64 { - Add<u64>(x, c) - } - private fun with_name_clash2$lambda$1(c: u64,x: u64): u64 { - Add<u64>({ - let x: u64 = Add<u64>(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<u64>(y, c) - } - private fun with_name_clash1$lambda$1(c: u64,x: u64): u64 { - Add<u64>(x, c) - } - private fun with_name_clash2$lambda$1(c: u64,x: u64): u64 { - Add<u64>({ - let x: u64 = Add<u64>(c, 1); - x - }, x) - } -} // end 0xcafe::m - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda-lifting/basic.move:5:9 - │ -5 │ f(x) - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda-lifting/basic.move:10:16 │ 10 │ map(x, |y| y + c) │ ^^^^^^^^^ -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda-lifting/basic.move:15:16 │ 15 │ map(x, |x| x + c) │ ^^^^^^^^^ -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda-lifting/basic.move:20:16 │ 20 │ map(x, |x| { diff --git a/third_party/move/move-compiler-v2/tests/lambda-lifting/modify.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda-lifting/modify.lambda.exp index 3664bd2e163bb..74dee022d7295 100644 --- a/third_party/move/move-compiler-v2/tests/lambda-lifting/modify.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda-lifting/modify.lambda.exp @@ -503,26 +503,52 @@ module 0xcafe::m { Diagnostics: -error: captured variable `x` cannot be modified inside of a lambda - ┌─ tests/lambda-lifting/modify.move:14:13 +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda-lifting/modify.move:13:16 │ -14 │ x = 2; - │ ^ +13 │ map(x, |y| { + │ ╭────────────────^ +14 │ │ x = 2; +15 │ │ y + c +16 │ │ }) + │ ╰─────────^ -error: captured variable `c` cannot be modified inside of a lambda - ┌─ tests/lambda-lifting/modify.move:21:26 +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda-lifting/modify.move:20:16 │ -21 │ let r = &mut c; - │ ^ +20 │ map(x, |y| { + │ ╭────────────────^ +21 │ │ let r = &mut c; +22 │ │ y + *r +23 │ │ }) + │ ╰─────────^ -error: captured variable `z` cannot be modified inside of a lambda - ┌─ tests/lambda-lifting/modify.move:29:13 +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda-lifting/modify.move:28:16 │ -29 │ z = 2; - │ ^ +28 │ map(x, |y| { + │ ╭────────────────^ +29 │ │ z = 2; +30 │ │ y + c +31 │ │ }) + │ ╰─────────^ -error: captured variable `z` cannot be modified inside of a lambda - ┌─ tests/lambda-lifting/modify.move:37:26 +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda-lifting/modify.move:36:16 │ -37 │ let r = &mut z; - │ ^ +36 │ map(x, |y| { + │ ╭────────────────^ +37 │ │ let r = &mut z; +38 │ │ y + *r +39 │ │ }) + │ ╰─────────^ + +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda-lifting/modify.move:44:16 + │ +44 │ map(x, |y| { + │ ╭────────────────^ +45 │ │ let r = &z; +46 │ │ y + *r +47 │ │ }) + │ ╰─────────^ diff --git a/third_party/move/move-compiler-v2/tests/lambda-lifting/nested.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda-lifting/nested.lambda.exp index cb00e1c4256e8..8686807511bc5 100644 --- a/third_party/move/move-compiler-v2/tests/lambda-lifting/nested.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda-lifting/nested.lambda.exp @@ -152,87 +152,15 @@ module 0xcafe::m { } // end 0xcafe::m -// -- Model dump after env processor lambda-lifting: -module 0xcafe::m { - private fun map1(x: u64,f: |u64|u64): u64 { - (f)(x) - } - private fun map2(x: u8,f: |u8|u8): u8 { - (f)(x) - } - private fun nested(x: u64,c: u64): u64 { - m::map1(x, closure m::nested$lambda$2(c)) - } - private fun nested$lambda$1(c: u64,y: u8): u8 { - Add<u8>(y, Cast<u8>(c)) - } - private fun nested$lambda$2(c: u64,y: u64): u64 { - Cast<u64>(m::map2(Cast<u8>(Sub<u64>(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<u8>(y, Cast<u8>(c)) - } - private fun nested$lambda$2(c: u64,y: u64): u64 { - Cast<u64>(m::map2(Cast<u8>(Sub<u64>(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<u8>(y, Cast<u8>(c)) - } - private fun nested$lambda$2(c: u64,y: u64): u64 { - Cast<u64>(m::map2(Cast<u8>(Sub<u64>(y, c)), closure m::nested$lambda$1(c))) - } -} // end 0xcafe::m - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda-lifting/nested.move:5:9 - │ -5 │ f(x) - │ ^ - -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda-lifting/nested.move:10:9 - │ -10 │ f(x) - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda-lifting/nested.move:15:42 │ 15 │ map1(x, |y| (map2((y - c as u8), |y| y + (c as u8)) as u64)) │ ^^^^^^^^^^^^^^^^^ -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda-lifting/nested.move:15:17 │ 15 │ map1(x, |y| (map2((y - c as u8), |y| y + (c as u8)) as u64)) diff --git a/third_party/move/move-compiler-v2/tests/lambda-lifting/pattern.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda-lifting/pattern.lambda.exp index 6a897fa9ce92d..61e3d5839f064 100644 --- a/third_party/move/move-compiler-v2/tests/lambda-lifting/pattern.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda-lifting/pattern.lambda.exp @@ -185,84 +185,9 @@ module 0xcafe::m { } // end 0xcafe::m -// -- Model dump after env processor lambda-lifting: -module 0xcafe::m { - struct S<T> { - x: T, - } - private fun consume<T>(s: S<T>,x: T,f: |(S<T>, T)|T): T { - (f)(s, x) - } - private fun pattern(s: S<u64>,x: u64): u64 { - m::consume<u64>(s, x, closure m::pattern$lambda$1()) - } - private fun pattern$lambda$1(param$0: S<u64>,_y: u64): u64 { - { - let m::S<u64>{ x } = param$0; - { - let y: u64 = x; - Add<u64>(x, y) - } - } - } -} // end 0xcafe::m - - -// -- Model dump after env processor specification checker: -module 0xcafe::m { - struct S<T> { - x: T, - } - private fun consume<T>(s: S<T>,x: T,f: |(S<T>, T)|T): T { - (f)(s, x) - } - private fun pattern(s: S<u64>,x: u64): u64 { - m::consume<u64>(s, x, closure m::pattern$lambda$1()) - } - private fun pattern$lambda$1(param$0: S<u64>,_y: u64): u64 { - { - let m::S<u64>{ x } = param$0; - { - let y: u64 = x; - Add<u64>(x, y) - } - } - } -} // end 0xcafe::m - - -// -- Model dump after env processor specification rewriter: -module 0xcafe::m { - struct S<T> { - x: T, - } - private fun consume<T>(s: S<T>,x: T,f: |(S<T>, T)|T): T { - (f)(s, x) - } - private fun pattern(s: S<u64>,x: u64): u64 { - m::consume<u64>(s, x, closure m::pattern$lambda$1()) - } - private fun pattern$lambda$1(param$0: S<u64>,_y: u64): u64 { - { - let m::S<u64>{ x } = param$0; - { - let y: u64 = x; - Add<u64>(x, y) - } - } - } -} // end 0xcafe::m - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda-lifting/pattern.move:10:9 - │ -10 │ f(s, x) - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda-lifting/pattern.move:15:23 │ 15 │ consume(s, x, |S{x}, _y| { let y = x; x + y}) diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda.lambda.exp index 356f716bf1076..bb292947347d0 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/break_continue_in_lambda.lambda.exp @@ -1043,364 +1043,22 @@ module 0xc0ffee::m { } // end 0xc0ffee::m -// -- Model dump after env processor lambda-lifting: -module 0xc0ffee::m { - public fun bar(): u64 { - { - let i: u64 = 0; - loop { - if Lt<u64>(i, 10) { - i: u64 = Add<u64>(i, 1); - if Eq<u64>(i, 5) { - m::brk2(closure m::bar$lambda$1()); - m::brk2(closure m::bar$lambda$2()); - m::brk2(closure m::bar$lambda$3()); - Tuple() - } else { - Tuple() - } - } else { - break - } - }; - i - } - } - private fun brk() { - break; - Tuple() - } - private fun brk2(f: |()|) { - (f)(); - Tuple() - } - private fun brk3() { - loop { - if true { - break; - Tuple() - } else { - break - } - } - } - private fun brk4() { - loop { - if true { - continue; - Tuple() - } else { - break - } - } - } - private fun broken() { - break; - Tuple() - } - private fun continued() { - continue; - Tuple() - } - public fun foo(): u64 { - { - let i: u64 = 0; - loop { - if Lt<u64>(i, 10) { - i: u64 = Add<u64>(i, 1); - if Eq<u64>(i, 5) { - m::brk(); - m::brk3(); - m::brk4(); - Tuple() - } else { - Tuple() - } - } else { - break - } - }; - i - } - } - private fun bar$lambda$1() { - break - } - private fun bar$lambda$2() { - loop { - if true { - break - } else { - break - } - } - } - private fun bar$lambda$3() { - loop { - if true { - continue - } else { - break - } - } - } -} // end 0xc0ffee::m - - -// -- Model dump after env processor specification checker: -module 0xc0ffee::m { - public fun bar(): u64 { - { - let i: u64 = 0; - loop { - if Lt<u64>(i, 10) { - i: u64 = Add<u64>(i, 1); - if Eq<u64>(i, 5) { - m::brk2(closure m::bar$lambda$1()); - m::brk2(closure m::bar$lambda$2()); - m::brk2(closure m::bar$lambda$3()); - Tuple() - } else { - Tuple() - } - } else { - break - } - }; - i - } - } - private fun brk() { - break; - Tuple() - } - private fun brk2(f: |()|) { - (f)(); - Tuple() - } - private fun brk3() { - loop { - if true { - break; - Tuple() - } else { - break - } - } - } - private fun brk4() { - loop { - if true { - continue; - Tuple() - } else { - break - } - } - } - private fun broken() { - break; - Tuple() - } - private fun continued() { - continue; - Tuple() - } - public fun foo(): u64 { - { - let i: u64 = 0; - loop { - if Lt<u64>(i, 10) { - i: u64 = Add<u64>(i, 1); - if Eq<u64>(i, 5) { - m::brk(); - m::brk3(); - m::brk4(); - Tuple() - } else { - Tuple() - } - } else { - break - } - }; - i - } - } - private fun bar$lambda$1() { - break - } - private fun bar$lambda$2() { - loop { - if true { - break - } else { - break - } - } - } - private fun bar$lambda$3() { - loop { - if true { - continue - } else { - break - } - } - } -} // end 0xc0ffee::m - - -// -- Model dump after env processor specification rewriter: -module 0xc0ffee::m { - public fun bar(): u64 { - { - let i: u64 = 0; - loop { - if Lt<u64>(i, 10) { - i: u64 = Add<u64>(i, 1); - if Eq<u64>(i, 5) { - m::brk2(closure m::bar$lambda$1()); - m::brk2(closure m::bar$lambda$2()); - m::brk2(closure m::bar$lambda$3()); - Tuple() - } else { - Tuple() - } - } else { - break - } - }; - i - } - } - private fun brk() { - break; - Tuple() - } - private fun brk2(f: |()|) { - (f)(); - Tuple() - } - private fun brk3() { - loop { - if true { - break; - Tuple() - } else { - break - } - } - } - private fun brk4() { - loop { - if true { - continue; - Tuple() - } else { - break - } - } - } - private fun broken() { - break; - Tuple() - } - private fun continued() { - continue; - Tuple() - } - public fun foo(): u64 { - { - let i: u64 = 0; - loop { - if Lt<u64>(i, 10) { - i: u64 = Add<u64>(i, 1); - if Eq<u64>(i, 5) { - m::brk(); - m::brk3(); - m::brk4(); - Tuple() - } else { - Tuple() - } - } else { - break - } - }; - i - } - } - private fun bar$lambda$1() { - break - } - private fun bar$lambda$2() { - loop { - if true { - break - } else { - break - } - } - } - private fun bar$lambda$3() { - loop { - if true { - continue - } else { - break - } - } - } -} // end 0xc0ffee::m - - Diagnostics: -error: missing enclosing loop statement - ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:3:9 - │ -3 │ break; - │ ^^^^^ - -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:7:9 - │ -7 │ f(); - │ ^ - -error: missing enclosing loop statement - ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:40:26 - │ -40 │ brk2(| | break); - │ ^^^^^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:40:22 │ 40 │ brk2(| | break); │ ^^^^^^^^^ -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:41:8 │ 41 │ brk2(| | while (true) { break }); │ ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:42:8 │ 42 │ brk2(| | while (true) { continue }); │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: missing enclosing loop statement - ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:49:2 - │ -49 │ break; - │ ^^^^^ - -error: missing enclosing loop statement - ┌─ tests/lambda/inline-parity/break_continue_in_lambda.move:53:2 - │ -53 │ continue; - │ ^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991.lambda.exp index fea2410cdc948..b0ca3260fc823 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991.lambda.exp @@ -174,111 +174,15 @@ module 0x42::Test { } // end 0x42::Test -// -- Model dump after env processor lambda-lifting: -module 0x42::Test { - private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { - Add<u64>((f)(x, _y), (g)(x, _y)) - } - public fun test() { - if Eq<u64>(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 110) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - private fun test$lambda$1(x: u64,param$1: u64): u64 { - { - let _: u64 = param$1; - x - } - } - private fun test$lambda$2(param$0: u64,y: u64): u64 { - { - let _: u64 = param$0; - y - } - } -} // end 0x42::Test - - -// -- Model dump after env processor specification checker: -module 0x42::Test { - private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { - Add<u64>((f)(x, _y), (g)(x, _y)) - } - public fun test() { - if Eq<u64>(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 110) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - private fun test$lambda$1(x: u64,param$1: u64): u64 { - { - let _: u64 = param$1; - x - } - } - private fun test$lambda$2(param$0: u64,y: u64): u64 { - { - let _: u64 = param$0; - y - } - } -} // end 0x42::Test - - -// -- Model dump after env processor specification rewriter: -module 0x42::Test { - private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { - Add<u64>((f)(x, _y), (g)(x, _y)) - } - public fun test() { - if Eq<u64>(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 110) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - private fun test$lambda$1(x: u64,param$1: u64): u64 { - { - let _: u64 = param$1; - x - } - } - private fun test$lambda$2(param$0: u64,y: u64): u64 { - { - let _: u64 = param$0; - y - } - } -} // end 0x42::Test - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/bug_10991.move:4:9 - │ -4 │ f(x, _y) + g(x, _y) - │ ^ - -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/bug_10991.move:4:20 - │ -4 │ f(x, _y) + g(x, _y) - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/bug_10991.move:8:21 │ 8 │ assert!(foo(|x, _| x, |_, y| y, 10, 100) == 110, 0); │ ^^^^^^^^ -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/bug_10991.move:8:31 │ 8 │ assert!(foo(|x, _| x, |_, y| y, 10, 100) == 110, 0); diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam.lambda.exp index b1ce2d980a7d7..613fae6c520e4 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam.lambda.exp @@ -174,129 +174,15 @@ module 0x42::Test { } // end 0x42::Test -// -- Model dump after env processor lambda-lifting: -module 0x42::Test { - private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { - Add<u64>((f)(x, _y), (g)(x, _y)) - } - public fun test() { - if Eq<u64>(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 13) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - private fun test$lambda$1(param$0: u64,param$1: u64): u64 { - { - let _: u64 = param$1; - { - let _: u64 = param$0; - 3 - } - } - } - private fun test$lambda$2(param$0: u64,param$1: u64): u64 { - { - let _: u64 = param$1; - { - let _: u64 = param$0; - 10 - } - } - } -} // end 0x42::Test - - -// -- Model dump after env processor specification checker: -module 0x42::Test { - private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { - Add<u64>((f)(x, _y), (g)(x, _y)) - } - public fun test() { - if Eq<u64>(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 13) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - private fun test$lambda$1(param$0: u64,param$1: u64): u64 { - { - let _: u64 = param$1; - { - let _: u64 = param$0; - 3 - } - } - } - private fun test$lambda$2(param$0: u64,param$1: u64): u64 { - { - let _: u64 = param$1; - { - let _: u64 = param$0; - 10 - } - } - } -} // end 0x42::Test - - -// -- Model dump after env processor specification rewriter: -module 0x42::Test { - private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { - Add<u64>((f)(x, _y), (g)(x, _y)) - } - public fun test() { - if Eq<u64>(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 13) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - private fun test$lambda$1(param$0: u64,param$1: u64): u64 { - { - let _: u64 = param$1; - { - let _: u64 = param$0; - 3 - } - } - } - private fun test$lambda$2(param$0: u64,param$1: u64): u64 { - { - let _: u64 = param$1; - { - let _: u64 = param$0; - 10 - } - } - } -} // end 0x42::Test - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/bug_10991_noparam.move:4:9 - │ -4 │ f(x, _y) + g(x, _y) - │ ^ - -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/bug_10991_noparam.move:4:20 - │ -4 │ f(x, _y) + g(x, _y) - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/bug_10991_noparam.move:8:21 │ 8 │ assert!(foo(|_, _| 3, |_, _| 10, 10, 100) == 13, 0); │ ^^^^^^^^ -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/bug_10991_noparam.move:8:31 │ 8 │ assert!(foo(|_, _| 3, |_, _| 10, 10, 100) == 13, 0); diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam2.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam2.lambda.exp index f0eec150641eb..e5934586b182d 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam2.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991_noparam2.lambda.exp @@ -174,111 +174,15 @@ module 0x42::Test { } // end 0x42::Test -// -- Model dump after env processor lambda-lifting: -module 0x42::Test { - private fun foo(f: |u64|u64,g: |u64|u64,x: u64,_: u64): u64 { - Add<u64>((f)(x), (g)(x)) - } - public fun test() { - if Eq<u64>(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 13) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - private fun test$lambda$1(param$0: u64): u64 { - { - let _: u64 = param$0; - 3 - } - } - private fun test$lambda$2(param$0: u64): u64 { - { - let _: u64 = param$0; - 10 - } - } -} // end 0x42::Test - - -// -- Model dump after env processor specification checker: -module 0x42::Test { - private fun foo(f: |u64|u64,g: |u64|u64,x: u64,_: u64): u64 { - Add<u64>((f)(x), (g)(x)) - } - public fun test() { - if Eq<u64>(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 13) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - private fun test$lambda$1(param$0: u64): u64 { - { - let _: u64 = param$0; - 3 - } - } - private fun test$lambda$2(param$0: u64): u64 { - { - let _: u64 = param$0; - 10 - } - } -} // end 0x42::Test - - -// -- Model dump after env processor specification rewriter: -module 0x42::Test { - private fun foo(f: |u64|u64,g: |u64|u64,x: u64,_: u64): u64 { - Add<u64>((f)(x), (g)(x)) - } - public fun test() { - if Eq<u64>(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 10, 100), 13) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - private fun test$lambda$1(param$0: u64): u64 { - { - let _: u64 = param$0; - 3 - } - } - private fun test$lambda$2(param$0: u64): u64 { - { - let _: u64 = param$0; - 10 - } - } -} // end 0x42::Test - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/bug_10991_noparam2.move:4:9 - │ -4 │ f(x) + g(x) - │ ^ - -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/bug_10991_noparam2.move:4:16 - │ -4 │ f(x) + g(x) - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/bug_10991_noparam2.move:8:21 │ 8 │ assert!(foo(|_| 3, |_| 10, 10, 100) == 13, 0); │ ^^^^^ -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/bug_10991_noparam2.move:8:28 │ 8 │ assert!(foo(|_| 3, |_| 10, 10, 100) == 13, 0); diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991a.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991a.lambda.exp index 172a728293cdf..5638e37c59b27 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991a.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991a.lambda.exp @@ -174,153 +174,27 @@ module 0x42::Test { } // end 0x42::Test -// -- Model dump after env processor lambda-lifting: -module 0x42::Test { - private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,h: |(u64, u64)|u64,i: |(u64, u64)|u64,x: u64,y: u64): u64 { - Add<u64>(Add<u64>(Add<u64>((f)(x, y), (g)(x, y)), (h)(x, y)), (i)(x, y)) - } - public fun test() { - if Eq<u64>(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), closure Test::test$lambda$3(), closure Test::test$lambda$4(), 10, 100), 220) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - private fun test$lambda$1(x: u64,param$1: u64): u64 { - { - let _: u64 = param$1; - x - } - } - private fun test$lambda$2(param$0: u64,y: u64): u64 { - { - let _: u64 = param$0; - y - } - } - private fun test$lambda$3(a: u64,_b: u64): u64 { - a - } - private fun test$lambda$4(_c: u64,d: u64): u64 { - d - } -} // end 0x42::Test - - -// -- Model dump after env processor specification checker: -module 0x42::Test { - private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,h: |(u64, u64)|u64,i: |(u64, u64)|u64,x: u64,y: u64): u64 { - Add<u64>(Add<u64>(Add<u64>((f)(x, y), (g)(x, y)), (h)(x, y)), (i)(x, y)) - } - public fun test() { - if Eq<u64>(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), closure Test::test$lambda$3(), closure Test::test$lambda$4(), 10, 100), 220) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - private fun test$lambda$1(x: u64,param$1: u64): u64 { - { - let _: u64 = param$1; - x - } - } - private fun test$lambda$2(param$0: u64,y: u64): u64 { - { - let _: u64 = param$0; - y - } - } - private fun test$lambda$3(a: u64,_b: u64): u64 { - a - } - private fun test$lambda$4(_c: u64,d: u64): u64 { - d - } -} // end 0x42::Test - - -// -- Model dump after env processor specification rewriter: -module 0x42::Test { - private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,h: |(u64, u64)|u64,i: |(u64, u64)|u64,x: u64,y: u64): u64 { - Add<u64>(Add<u64>(Add<u64>((f)(x, y), (g)(x, y)), (h)(x, y)), (i)(x, y)) - } - public fun test() { - if Eq<u64>(Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), closure Test::test$lambda$3(), closure Test::test$lambda$4(), 10, 100), 220) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - private fun test$lambda$1(x: u64,param$1: u64): u64 { - { - let _: u64 = param$1; - x - } - } - private fun test$lambda$2(param$0: u64,y: u64): u64 { - { - let _: u64 = param$0; - y - } - } - private fun test$lambda$3(a: u64,_b: u64): u64 { - a - } - private fun test$lambda$4(_c: u64,d: u64): u64 { - d - } -} // end 0x42::Test - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/bug_10991a.move:6:13 - │ -6 │ f(x, y) + g(x, y) + h(x, y) + i(x, y) - │ ^ - -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/bug_10991a.move:6:23 - │ -6 │ f(x, y) + g(x, y) + h(x, y) + i(x, y) - │ ^ - -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/bug_10991a.move:6:33 - │ -6 │ f(x, y) + g(x, y) + h(x, y) + i(x, y) - │ ^ - -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/bug_10991a.move:6:43 - │ -6 │ f(x, y) + g(x, y) + h(x, y) + i(x, y) - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/bug_10991a.move:10:21 │ 10 │ assert!(foo(|x, _| x, |_, y| y, │ ^^^^^^^^ -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/bug_10991a.move:10:31 │ 10 │ assert!(foo(|x, _| x, |_, y| y, │ ^^^^^^^^ -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/bug_10991a.move:11:6 │ 11 │ |a, _b| a, |_c, d| d, │ ^^^^^^^^^ -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/bug_10991a.move:11:17 │ 11 │ |a, _b| a, |_c, d| d, diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991b.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991b.lambda.exp index 4d75c19204ac0..3bacb83364f2b 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991b.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991b.lambda.exp @@ -174,81 +174,9 @@ module 0x42::Test { } // end 0x42::Test -// -- Model dump after env processor lambda-lifting: -module 0x42::Test { - private fun foo(g: |(u64, u64)|u64,x: u64,_y: u64): u64 { - (g)(x, _y) - } - public fun test() { - if Eq<u64>(Test::foo(closure Test::test$lambda$1(), 10, 100), 100) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - private fun test$lambda$1(param$0: u64,y: u64): u64 { - { - let _: u64 = param$0; - y - } - } -} // end 0x42::Test - - -// -- Model dump after env processor specification checker: -module 0x42::Test { - private fun foo(g: |(u64, u64)|u64,x: u64,_y: u64): u64 { - (g)(x, _y) - } - public fun test() { - if Eq<u64>(Test::foo(closure Test::test$lambda$1(), 10, 100), 100) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - private fun test$lambda$1(param$0: u64,y: u64): u64 { - { - let _: u64 = param$0; - y - } - } -} // end 0x42::Test - - -// -- Model dump after env processor specification rewriter: -module 0x42::Test { - private fun foo(g: |(u64, u64)|u64,x: u64,_y: u64): u64 { - (g)(x, _y) - } - public fun test() { - if Eq<u64>(Test::foo(closure Test::test$lambda$1(), 10, 100), 100) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - private fun test$lambda$1(param$0: u64,y: u64): u64 { - { - let _: u64 = param$0; - y - } - } -} // end 0x42::Test - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/bug_10991b.move:4:9 - │ -4 │ g(x, _y) - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/bug_10991b.move:8:21 │ 8 │ assert!(foo(|_, y| y, diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991c.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991c.lambda.exp index 486526cead33b..43b8d5d0216de 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991c.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/bug_10991c.lambda.exp @@ -174,90 +174,9 @@ module 0x42::Test { } // end 0x42::Test -// -- Model dump after env processor lambda-lifting: -module 0x42::Test { - private fun foo(g: |(u64, u64, u64, u64)|u64,x: u64,y: u64,z: u64,q: u64): u64 { - (g)(x, y, z, q) - } - public fun test() { - if Eq<u64>(Test::foo(closure Test::test$lambda$1(), 10, 100, 1000, 10000), 10100) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - private fun test$lambda$1(param$0: u64,y: u64,param$2: u64,q: u64): u64 { - { - let _: u64 = param$2; - { - let _: u64 = param$0; - Add<u64>(y, q) - } - } - } -} // end 0x42::Test - - -// -- Model dump after env processor specification checker: -module 0x42::Test { - private fun foo(g: |(u64, u64, u64, u64)|u64,x: u64,y: u64,z: u64,q: u64): u64 { - (g)(x, y, z, q) - } - public fun test() { - if Eq<u64>(Test::foo(closure Test::test$lambda$1(), 10, 100, 1000, 10000), 10100) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - private fun test$lambda$1(param$0: u64,y: u64,param$2: u64,q: u64): u64 { - { - let _: u64 = param$2; - { - let _: u64 = param$0; - Add<u64>(y, q) - } - } - } -} // end 0x42::Test - - -// -- Model dump after env processor specification rewriter: -module 0x42::Test { - private fun foo(g: |(u64, u64, u64, u64)|u64,x: u64,y: u64,z: u64,q: u64): u64 { - (g)(x, y, z, q) - } - public fun test() { - if Eq<u64>(Test::foo(closure Test::test$lambda$1(), 10, 100, 1000, 10000), 10100) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - private fun test$lambda$1(param$0: u64,y: u64,param$2: u64,q: u64): u64 { - { - let _: u64 = param$2; - { - let _: u64 = param$0; - Add<u64>(y, q) - } - } - } -} // end 0x42::Test - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/bug_10991c.move:4:9 - │ -4 │ g(x, y, z, q) - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/bug_10991c.move:8:21 │ 8 │ assert!(foo(|_, y, _, q| y + q, diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/dotdot_valid.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/dotdot_valid.lambda.exp index de57ae7f20e1a..1855166775783 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/dotdot_valid.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/dotdot_valid.lambda.exp @@ -3265,940 +3265,9 @@ module 0x42::test { } // end 0x42::test -// -- Model dump after env processor lambda-lifting: -module 0x42::test { - enum E1 { - A { - 0: u8, - 1: bool, - } - B { - 0: u8, - } - C { - x: u8, - y: S1, - } - } - struct S0 { - dummy_field: bool, - } - struct S1 { - 0: u8, - } - struct S2 { - 0: bool, - 1: S0, - } - struct S3 { - x: bool, - y: u8, - } - struct S4<T> { - x: T, - y: S3, - } - struct S5<T,U> { - 0: T, - 1: U, - } - struct S6<T,U> { - x: T, - y: U, - } - struct S7 { - 0: u8, - 1: u16, - 2: u32, - 3: u64, - } - private fun lambda_param(f: |S2|bool): bool { - { - let x: S2 = pack test::S2(true, pack test::S0(false)); - (f)(x) - } - } - private fun nested1(x: S4<bool>) { - { - let test::S4<bool>{ x: _x, y: _ } = x; - { - let test::S4<bool>{ x: _, y: _y } = x; - { - let test::S4<bool>{ x: _, y: test::S3{ x: _, y: _ } } = x; - { - let test::S4<bool>{ x: _, y: test::S3{ x: _x, y: _ } } = x; - { - let test::S4<bool>{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; - { - let test::S4<bool>{ x: _, y: test::S3{ x: _, y: _y } } = x; - { - let test::S4<bool>{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; - Tuple() - } - } - } - } - } - } - } - } - private fun nested1_ref(x: &S4<bool>) { - { - let test::S4<bool>{ x: _x, y: _ } = x; - { - let test::S4<bool>{ x: _, y: _y } = x; - { - let test::S4<bool>{ x: _, y: test::S3{ x: _, y: _ } } = x; - { - let test::S4<bool>{ x: _, y: test::S3{ x: _x, y: _ } } = x; - { - let test::S4<bool>{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; - { - let test::S4<bool>{ x: _, y: test::S3{ x: _, y: _y } } = x; - { - let test::S4<bool>{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; - Tuple() - } - } - } - } - } - } - } - } - private fun nested2(x: S5<bool, S1>) { - { - let test::S5<bool, S1>{ 0: _, 1: test::S1{ 0: _ } } = x; - Tuple() - } - } - private fun nested2_ref(x: &S5<bool, S1>) { - { - let test::S5<bool, S1>{ 0: _, 1: test::S1{ 0: _ } } = x; - Tuple() - } - } - private fun nested3(x: S5<bool, S4<bool>>) { - { - let test::S5<bool, S4<bool>>{ 0: _, 1: test::S4<bool>{ x: _, y: _ } } = x; - Tuple() - } - } - private fun nested3_ref(x: &S5<bool, S4<bool>>) { - { - let test::S5<bool, S4<bool>>{ 0: _, 1: test::S4<bool>{ x: _, y: _ } } = x; - Tuple() - } - } - private fun nested4(x: S4<S1>) { - { - let test::S4<S1>{ x: test::S1{ 0: _ }, y: _ } = x; - Tuple() - } - } - private fun nested4_ref(x: &S4<S1>) { - { - let test::S4<S1>{ x: test::S1{ 0: _ }, y: _ } = x; - Tuple() - } - } - private fun simple_0(x: S0) { - { - let test::S0{ dummy_field: _ } = x; - Tuple() - } - } - private fun simple_0_ref(x: &S0) { - { - let test::S0{ dummy_field: _ } = x; - Tuple() - } - } - private fun simple_1(x: S1) { - { - let test::S1{ 0: _ } = x; - Tuple() - } - } - private fun simple_1_ref(x: &mut S1) { - { - let test::S1{ 0: _ } = x; - Tuple() - } - } - private fun simple_2(x: S2) { - { - let test::S2{ 0: _, 1: _ } = x; - { - let test::S2{ 0: _x, 1: _ } = x; - { - let test::S2{ 0: _, 1: _x } = x; - { - let test::S2{ 0: _, 1: _ } = x; - { - let test::S2{ 0: _, 1: _ } = x; - { - let test::S2{ 0: _x, 1: _y } = x; - { - let test::S2{ 0: _x, 1: _y } = x; - { - let test::S2{ 0: _x, 1: _y } = x; - Tuple() - } - } - } - } - } - } - } - } - } - private fun simple_2_ref(x: &S2) { - { - let test::S2{ 0: _, 1: _ } = x; - { - let test::S2{ 0: _x, 1: _ } = x; - { - let test::S2{ 0: _, 1: _x } = x; - { - let test::S2{ 0: _, 1: _ } = x; - { - let test::S2{ 0: _, 1: _ } = x; - { - let test::S2{ 0: _x, 1: _y } = x; - { - let test::S2{ 0: _x, 1: _y } = x; - { - let test::S2{ 0: _x, 1: _y } = x; - Tuple() - } - } - } - } - } - } - } - } - } - private fun simple_3(x: S3) { - { - let test::S3{ x: _, y: _ } = x; - { - let test::S3{ x: _x, y: _ } = x; - { - let test::S3{ x: _, y: _y } = x; - Tuple() - } - } - } - } - private fun simple_3_ref(x: S3) { - { - let test::S3{ x: _, y: _ } = x; - { - let test::S3{ x: _x, y: _ } = x; - { - let test::S3{ x: _, y: _y } = x; - Tuple() - } - } - } - } - private fun simple_4(x: E1): u8 { - match (x) { - test::E1::A{ 0: x, 1: _ } => { - x - } - test::E1::B{ 0: x } => { - x - } - test::E1::C{ x, y: _ } => { - x - } - } - - } - private fun simple_4_ref(x: &E1): &u8 { - match (x) { - test::E1::A{ 0: x, 1: _ } => { - x - } - test::E1::B{ 0: x } => { - x - } - } - - } - private fun simple_5(x: E1): u8 { - match (x) { - test::E1::A{ 0: _, 1: y } => { - if y { - 1 - } else { - 0 - } - } - test::E1::B{ 0: x } => { - x - } - test::E1::C{ x: _, y: test::S1{ 0: x } } => { - x - } - } - - } - private fun simple_6(x: &S7) { - { - let test::S7{ 0: _w, 1: _, 2: _, 3: _z } = x; - { - let test::S7{ 0: _w, 1: _x, 2: _y, 3: _z } = x; - Tuple() - } - } - } - private fun test_lambda_param(): bool { - test::lambda_param(closure test::test_lambda_param$lambda$1()) - } - private fun test_lambda_param$lambda$1(param$0: S2): bool { - { - let test::S2{ 0: x, 1: _ } = param$0; - x - } - } -} // end 0x42::test - - -// -- Model dump after env processor specification checker: -module 0x42::test { - enum E1 { - A { - 0: u8, - 1: bool, - } - B { - 0: u8, - } - C { - x: u8, - y: S1, - } - } - struct S0 { - dummy_field: bool, - } - struct S1 { - 0: u8, - } - struct S2 { - 0: bool, - 1: S0, - } - struct S3 { - x: bool, - y: u8, - } - struct S4<T> { - x: T, - y: S3, - } - struct S5<T,U> { - 0: T, - 1: U, - } - struct S6<T,U> { - x: T, - y: U, - } - struct S7 { - 0: u8, - 1: u16, - 2: u32, - 3: u64, - } - private fun lambda_param(f: |S2|bool): bool { - { - let x: S2 = pack test::S2(true, pack test::S0(false)); - (f)(x) - } - } - private fun nested1(x: S4<bool>) { - { - let test::S4<bool>{ x: _x, y: _ } = x; - { - let test::S4<bool>{ x: _, y: _y } = x; - { - let test::S4<bool>{ x: _, y: test::S3{ x: _, y: _ } } = x; - { - let test::S4<bool>{ x: _, y: test::S3{ x: _x, y: _ } } = x; - { - let test::S4<bool>{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; - { - let test::S4<bool>{ x: _, y: test::S3{ x: _, y: _y } } = x; - { - let test::S4<bool>{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; - Tuple() - } - } - } - } - } - } - } - } - private fun nested1_ref(x: &S4<bool>) { - { - let test::S4<bool>{ x: _x, y: _ } = x; - { - let test::S4<bool>{ x: _, y: _y } = x; - { - let test::S4<bool>{ x: _, y: test::S3{ x: _, y: _ } } = x; - { - let test::S4<bool>{ x: _, y: test::S3{ x: _x, y: _ } } = x; - { - let test::S4<bool>{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; - { - let test::S4<bool>{ x: _, y: test::S3{ x: _, y: _y } } = x; - { - let test::S4<bool>{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; - Tuple() - } - } - } - } - } - } - } - } - private fun nested2(x: S5<bool, S1>) { - { - let test::S5<bool, S1>{ 0: _, 1: test::S1{ 0: _ } } = x; - Tuple() - } - } - private fun nested2_ref(x: &S5<bool, S1>) { - { - let test::S5<bool, S1>{ 0: _, 1: test::S1{ 0: _ } } = x; - Tuple() - } - } - private fun nested3(x: S5<bool, S4<bool>>) { - { - let test::S5<bool, S4<bool>>{ 0: _, 1: test::S4<bool>{ x: _, y: _ } } = x; - Tuple() - } - } - private fun nested3_ref(x: &S5<bool, S4<bool>>) { - { - let test::S5<bool, S4<bool>>{ 0: _, 1: test::S4<bool>{ x: _, y: _ } } = x; - Tuple() - } - } - private fun nested4(x: S4<S1>) { - { - let test::S4<S1>{ x: test::S1{ 0: _ }, y: _ } = x; - Tuple() - } - } - private fun nested4_ref(x: &S4<S1>) { - { - let test::S4<S1>{ x: test::S1{ 0: _ }, y: _ } = x; - Tuple() - } - } - private fun simple_0(x: S0) { - { - let test::S0{ dummy_field: _ } = x; - Tuple() - } - } - private fun simple_0_ref(x: &S0) { - { - let test::S0{ dummy_field: _ } = x; - Tuple() - } - } - private fun simple_1(x: S1) { - { - let test::S1{ 0: _ } = x; - Tuple() - } - } - private fun simple_1_ref(x: &mut S1) { - { - let test::S1{ 0: _ } = x; - Tuple() - } - } - private fun simple_2(x: S2) { - { - let test::S2{ 0: _, 1: _ } = x; - { - let test::S2{ 0: _x, 1: _ } = x; - { - let test::S2{ 0: _, 1: _x } = x; - { - let test::S2{ 0: _, 1: _ } = x; - { - let test::S2{ 0: _, 1: _ } = x; - { - let test::S2{ 0: _x, 1: _y } = x; - { - let test::S2{ 0: _x, 1: _y } = x; - { - let test::S2{ 0: _x, 1: _y } = x; - Tuple() - } - } - } - } - } - } - } - } - } - private fun simple_2_ref(x: &S2) { - { - let test::S2{ 0: _, 1: _ } = x; - { - let test::S2{ 0: _x, 1: _ } = x; - { - let test::S2{ 0: _, 1: _x } = x; - { - let test::S2{ 0: _, 1: _ } = x; - { - let test::S2{ 0: _, 1: _ } = x; - { - let test::S2{ 0: _x, 1: _y } = x; - { - let test::S2{ 0: _x, 1: _y } = x; - { - let test::S2{ 0: _x, 1: _y } = x; - Tuple() - } - } - } - } - } - } - } - } - } - private fun simple_3(x: S3) { - { - let test::S3{ x: _, y: _ } = x; - { - let test::S3{ x: _x, y: _ } = x; - { - let test::S3{ x: _, y: _y } = x; - Tuple() - } - } - } - } - private fun simple_3_ref(x: S3) { - { - let test::S3{ x: _, y: _ } = x; - { - let test::S3{ x: _x, y: _ } = x; - { - let test::S3{ x: _, y: _y } = x; - Tuple() - } - } - } - } - private fun simple_4(x: E1): u8 { - match (x) { - test::E1::A{ 0: x, 1: _ } => { - x - } - test::E1::B{ 0: x } => { - x - } - test::E1::C{ x, y: _ } => { - x - } - } - - } - private fun simple_4_ref(x: &E1): &u8 { - match (x) { - test::E1::A{ 0: x, 1: _ } => { - x - } - test::E1::B{ 0: x } => { - x - } - } - - } - private fun simple_5(x: E1): u8 { - match (x) { - test::E1::A{ 0: _, 1: y } => { - if y { - 1 - } else { - 0 - } - } - test::E1::B{ 0: x } => { - x - } - test::E1::C{ x: _, y: test::S1{ 0: x } } => { - x - } - } - - } - private fun simple_6(x: &S7) { - { - let test::S7{ 0: _w, 1: _, 2: _, 3: _z } = x; - { - let test::S7{ 0: _w, 1: _x, 2: _y, 3: _z } = x; - Tuple() - } - } - } - private fun test_lambda_param(): bool { - test::lambda_param(closure test::test_lambda_param$lambda$1()) - } - private fun test_lambda_param$lambda$1(param$0: S2): bool { - { - let test::S2{ 0: x, 1: _ } = param$0; - x - } - } -} // end 0x42::test - - -// -- Model dump after env processor specification rewriter: -module 0x42::test { - enum E1 { - A { - 0: u8, - 1: bool, - } - B { - 0: u8, - } - C { - x: u8, - y: S1, - } - } - struct S0 { - dummy_field: bool, - } - struct S1 { - 0: u8, - } - struct S2 { - 0: bool, - 1: S0, - } - struct S3 { - x: bool, - y: u8, - } - struct S4<T> { - x: T, - y: S3, - } - struct S5<T,U> { - 0: T, - 1: U, - } - struct S6<T,U> { - x: T, - y: U, - } - struct S7 { - 0: u8, - 1: u16, - 2: u32, - 3: u64, - } - private fun lambda_param(f: |S2|bool): bool { - { - let x: S2 = pack test::S2(true, pack test::S0(false)); - (f)(x) - } - } - private fun nested1(x: S4<bool>) { - { - let test::S4<bool>{ x: _x, y: _ } = x; - { - let test::S4<bool>{ x: _, y: _y } = x; - { - let test::S4<bool>{ x: _, y: test::S3{ x: _, y: _ } } = x; - { - let test::S4<bool>{ x: _, y: test::S3{ x: _x, y: _ } } = x; - { - let test::S4<bool>{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; - { - let test::S4<bool>{ x: _, y: test::S3{ x: _, y: _y } } = x; - { - let test::S4<bool>{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; - Tuple() - } - } - } - } - } - } - } - } - private fun nested1_ref(x: &S4<bool>) { - { - let test::S4<bool>{ x: _x, y: _ } = x; - { - let test::S4<bool>{ x: _, y: _y } = x; - { - let test::S4<bool>{ x: _, y: test::S3{ x: _, y: _ } } = x; - { - let test::S4<bool>{ x: _, y: test::S3{ x: _x, y: _ } } = x; - { - let test::S4<bool>{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; - { - let test::S4<bool>{ x: _, y: test::S3{ x: _, y: _y } } = x; - { - let test::S4<bool>{ x: _x2, y: test::S3{ x: _x1, y: _ } } = x; - Tuple() - } - } - } - } - } - } - } - } - private fun nested2(x: S5<bool, S1>) { - { - let test::S5<bool, S1>{ 0: _, 1: test::S1{ 0: _ } } = x; - Tuple() - } - } - private fun nested2_ref(x: &S5<bool, S1>) { - { - let test::S5<bool, S1>{ 0: _, 1: test::S1{ 0: _ } } = x; - Tuple() - } - } - private fun nested3(x: S5<bool, S4<bool>>) { - { - let test::S5<bool, S4<bool>>{ 0: _, 1: test::S4<bool>{ x: _, y: _ } } = x; - Tuple() - } - } - private fun nested3_ref(x: &S5<bool, S4<bool>>) { - { - let test::S5<bool, S4<bool>>{ 0: _, 1: test::S4<bool>{ x: _, y: _ } } = x; - Tuple() - } - } - private fun nested4(x: S4<S1>) { - { - let test::S4<S1>{ x: test::S1{ 0: _ }, y: _ } = x; - Tuple() - } - } - private fun nested4_ref(x: &S4<S1>) { - { - let test::S4<S1>{ x: test::S1{ 0: _ }, y: _ } = x; - Tuple() - } - } - private fun simple_0(x: S0) { - { - let test::S0{ dummy_field: _ } = x; - Tuple() - } - } - private fun simple_0_ref(x: &S0) { - { - let test::S0{ dummy_field: _ } = x; - Tuple() - } - } - private fun simple_1(x: S1) { - { - let test::S1{ 0: _ } = x; - Tuple() - } - } - private fun simple_1_ref(x: &mut S1) { - { - let test::S1{ 0: _ } = x; - Tuple() - } - } - private fun simple_2(x: S2) { - { - let test::S2{ 0: _, 1: _ } = x; - { - let test::S2{ 0: _x, 1: _ } = x; - { - let test::S2{ 0: _, 1: _x } = x; - { - let test::S2{ 0: _, 1: _ } = x; - { - let test::S2{ 0: _, 1: _ } = x; - { - let test::S2{ 0: _x, 1: _y } = x; - { - let test::S2{ 0: _x, 1: _y } = x; - { - let test::S2{ 0: _x, 1: _y } = x; - Tuple() - } - } - } - } - } - } - } - } - } - private fun simple_2_ref(x: &S2) { - { - let test::S2{ 0: _, 1: _ } = x; - { - let test::S2{ 0: _x, 1: _ } = x; - { - let test::S2{ 0: _, 1: _x } = x; - { - let test::S2{ 0: _, 1: _ } = x; - { - let test::S2{ 0: _, 1: _ } = x; - { - let test::S2{ 0: _x, 1: _y } = x; - { - let test::S2{ 0: _x, 1: _y } = x; - { - let test::S2{ 0: _x, 1: _y } = x; - Tuple() - } - } - } - } - } - } - } - } - } - private fun simple_3(x: S3) { - { - let test::S3{ x: _, y: _ } = x; - { - let test::S3{ x: _x, y: _ } = x; - { - let test::S3{ x: _, y: _y } = x; - Tuple() - } - } - } - } - private fun simple_3_ref(x: S3) { - { - let test::S3{ x: _, y: _ } = x; - { - let test::S3{ x: _x, y: _ } = x; - { - let test::S3{ x: _, y: _y } = x; - Tuple() - } - } - } - } - private fun simple_4(x: E1): u8 { - match (x) { - test::E1::A{ 0: x, 1: _ } => { - x - } - test::E1::B{ 0: x } => { - x - } - test::E1::C{ x, y: _ } => { - x - } - } - - } - private fun simple_4_ref(x: &E1): &u8 { - match (x) { - test::E1::A{ 0: x, 1: _ } => { - x - } - test::E1::B{ 0: x } => { - x - } - } - - } - private fun simple_5(x: E1): u8 { - match (x) { - test::E1::A{ 0: _, 1: y } => { - if y { - 1 - } else { - 0 - } - } - test::E1::B{ 0: x } => { - x - } - test::E1::C{ x: _, y: test::S1{ 0: x } } => { - x - } - } - - } - private fun simple_6(x: &S7) { - { - let test::S7{ 0: _w, 1: _, 2: _, 3: _z } = x; - { - let test::S7{ 0: _w, 1: _x, 2: _y, 3: _z } = x; - Tuple() - } - } - } - private fun test_lambda_param(): bool { - test::lambda_param(closure test::test_lambda_param$lambda$1()) - } - private fun test_lambda_param$lambda$1(param$0: S2): bool { - { - let test::S2{ 0: x, 1: _ } = param$0; - x - } - } -} // end 0x42::test - - Diagnostics: -error: match not exhaustive - ┌─ tests/lambda/inline-parity/dotdot_valid.move:142:16 - │ -142 │ match (x) { - │ ^ - │ - = missing `E1::C{..}` - -error: match not exhaustive - ┌─ tests/lambda/inline-parity/dotdot_valid.move:153:16 - │ -153 │ match (x) { - │ ^ - │ - = missing `E1::C{..}` - -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/dotdot_valid.move:177:9 - │ -177 │ f(x) - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/dotdot_valid.move:181:22 │ 181 │ lambda_param(|S2(x, ..)| x) diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eq_inline.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eq_inline.lambda.exp index 7fc8364520041..b512cde064cf7 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eq_inline.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eq_inline.lambda.exp @@ -141,54 +141,6 @@ module 0x42::m { } // end 0x42::m -// -- Model dump after env processor lambda-lifting: -module 0x42::m { - private fun foo(f: |&u64|) { - Tuple() - } - private fun g() { - m::foo(closure m::g$lambda$1()); - Tuple() - } - private fun g$lambda$1(v: &u64) { - Eq<u64>(v, Borrow(Immutable)(1)); - Tuple() - } -} // end 0x42::m - - -// -- Model dump after env processor specification checker: -module 0x42::m { - private fun foo(f: |&u64|) { - Tuple() - } - private fun g() { - m::foo(closure m::g$lambda$1()); - Tuple() - } - private fun g$lambda$1(v: &u64) { - Eq<u64>(v, Borrow(Immutable)(1)); - Tuple() - } -} // end 0x42::m - - -// -- Model dump after env processor specification rewriter: -module 0x42::m { - private fun foo(f: |&u64|) { - Tuple() - } - private fun g() { - m::foo(closure m::g$lambda$1()); - Tuple() - } - private fun g$lambda$1(v: &u64) { - Eq<u64>(v, Borrow(Immutable)(1)); - Tuple() - } -} // end 0x42::m - - Diagnostics: warning: Unused parameter `f`. Consider removing or prefixing with an underscore: `_f` @@ -197,9 +149,7 @@ warning: Unused parameter `f`. Consider removing or prefixing with an underscore 3 │ fun foo(f: |&u64|) { │ ^ - -Diagnostics: -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/eq_inline.move:7:13 │ 7 │ foo(|v| { diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eval_ignored_param.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eval_ignored_param.lambda.exp index 2bbc4c4bfd603..678e8fa29367f 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eval_ignored_param.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/eval_ignored_param.lambda.exp @@ -339,165 +339,15 @@ module 0x42::Test { } // end 0x42::Test -// -- Model dump after env processor lambda-lifting: -module 0x42::Test { - private fun foo(f: |(u64, u64, u64)|u64,g: |(u64, u64, u64)|u64,x: u64,_: u64,y: u64,z: u64): u64 { - { - let r1: u64 = (f)(x: u64 = Add<u64>(x, 1); - x, y: u64 = Add<u64>(y, 1); - y, z: u64 = Add<u64>(z, 1); - z); - { - let r2: u64 = (g)(x: u64 = Add<u64>(x, 1); - x, y: u64 = Add<u64>(y, 1); - y, z: u64 = Add<u64>(z, 1); - z); - Add<u64>(Add<u64>(Add<u64>(Add<u64>(r1, r2), Mul<u64>(3, x)), Mul<u64>(5, y)), Mul<u64>(7, z)) - } - } - } - public fun test() { - { - let r: u64 = Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 1, 10, 100, 1000); - if Eq<u64>(r, 9637) { - Tuple() - } else { - Abort(r) - }; - Tuple() - } - } - private fun test$lambda$1(x: u64,param$1: u64,z: u64): u64 { - { - let _: u64 = param$1; - Mul<u64>(x, z) - } - } - private fun test$lambda$2(param$0: u64,y: u64,param$2: u64): u64 { - { - let _: u64 = param$2; - { - let _: u64 = param$0; - y - } - } - } -} // end 0x42::Test - - -// -- Model dump after env processor specification checker: -module 0x42::Test { - private fun foo(f: |(u64, u64, u64)|u64,g: |(u64, u64, u64)|u64,x: u64,_: u64,y: u64,z: u64): u64 { - { - let r1: u64 = (f)(x: u64 = Add<u64>(x, 1); - x, y: u64 = Add<u64>(y, 1); - y, z: u64 = Add<u64>(z, 1); - z); - { - let r2: u64 = (g)(x: u64 = Add<u64>(x, 1); - x, y: u64 = Add<u64>(y, 1); - y, z: u64 = Add<u64>(z, 1); - z); - Add<u64>(Add<u64>(Add<u64>(Add<u64>(r1, r2), Mul<u64>(3, x)), Mul<u64>(5, y)), Mul<u64>(7, z)) - } - } - } - public fun test() { - { - let r: u64 = Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 1, 10, 100, 1000); - if Eq<u64>(r, 9637) { - Tuple() - } else { - Abort(r) - }; - Tuple() - } - } - private fun test$lambda$1(x: u64,param$1: u64,z: u64): u64 { - { - let _: u64 = param$1; - Mul<u64>(x, z) - } - } - private fun test$lambda$2(param$0: u64,y: u64,param$2: u64): u64 { - { - let _: u64 = param$2; - { - let _: u64 = param$0; - y - } - } - } -} // end 0x42::Test - - -// -- Model dump after env processor specification rewriter: -module 0x42::Test { - private fun foo(f: |(u64, u64, u64)|u64,g: |(u64, u64, u64)|u64,x: u64,_: u64,y: u64,z: u64): u64 { - { - let r1: u64 = (f)(x: u64 = Add<u64>(x, 1); - x, y: u64 = Add<u64>(y, 1); - y, z: u64 = Add<u64>(z, 1); - z); - { - let r2: u64 = (g)(x: u64 = Add<u64>(x, 1); - x, y: u64 = Add<u64>(y, 1); - y, z: u64 = Add<u64>(z, 1); - z); - Add<u64>(Add<u64>(Add<u64>(Add<u64>(r1, r2), Mul<u64>(3, x)), Mul<u64>(5, y)), Mul<u64>(7, z)) - } - } - } - public fun test() { - { - let r: u64 = Test::foo(closure Test::test$lambda$1(), closure Test::test$lambda$2(), 1, 10, 100, 1000); - if Eq<u64>(r, 9637) { - Tuple() - } else { - Abort(r) - }; - Tuple() - } - } - private fun test$lambda$1(x: u64,param$1: u64,z: u64): u64 { - { - let _: u64 = param$1; - Mul<u64>(x, z) - } - } - private fun test$lambda$2(param$0: u64,y: u64,param$2: u64): u64 { - { - let _: u64 = param$2; - { - let _: u64 = param$0; - y - } - } - } -} // end 0x42::Test - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/eval_ignored_param.move:4:11 - │ -4 │ let r1 = f({x = x + 1; x}, {y = y + 1; y}, {z = z + 1; z}); - │ ^ - -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/eval_ignored_param.move:5:11 - │ -5 │ let r2 = g({x = x + 1; x}, {y = y + 1; y}, {z = z + 1 ; z}); - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/eval_ignored_param.move:10:14 │ 10 │ let r = foo(|x, _, z| x*z, |_, y, _| y, 1, 10, 100, 1000); │ ^^^^^^^^^^^^^ -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/eval_ignored_param.move:10:29 │ 10 │ let r = foo(|x, _, z| x*z, |_, y, _| y, 1, 10, 100, 1000); diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generic_calls.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generic_calls.lambda.exp index 3381b1bbcf75c..6f699942c47f1 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generic_calls.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generic_calls.lambda.exp @@ -460,150 +460,9 @@ module 0x42::m { } // end 0x42::m -// -- Model dump after env processor lambda-lifting: -module 0x42::m { - struct S<T> { - x: T, - } - private fun id<T>(self: S<T>): S<T> { - self - } - private fun inlined<T>(f: |S<T>|S<T>,s: S<T>) { - (f)(s); - Tuple() - } - private fun receiver<T>(self: S<T>,y: T) { - select m::S.x<S<T>>(self) = y; - Tuple() - } - private fun receiver_more_generics<T,R>(self: S<T>,_y: R) { - Tuple() - } - private fun receiver_needs_type_args<T,R>(self: S<T>,_y: T) { - Abort(1) - } - private fun receiver_ref<T>(self: &S<T>,_y: T) { - Tuple() - } - private fun receiver_ref_mut<T>(self: &mut S<T>,y: T) { - select m::S.x<&mut S<T>>(self) = y - } - private fun test_call_styles(s: S<u64>,x: u64) { - m::receiver<u64>(s, x); - m::receiver_ref<u64>(Borrow(Immutable)(s), x); - m::receiver_ref_mut<u64>(Borrow(Mutable)(s), x); - m::receiver_more_generics<u64, u64>(s, 22); - m::receiver_needs_type_args<u64, u8>(s, x); - Tuple() - } - private fun test_receiver_inference(s: S<u64>) { - m::inlined<u64>(closure m::test_receiver_inference$lambda$1(), s) - } - private fun test_receiver_inference$lambda$1(s: S<u64>): S<u64> { - m::id<u64>(s) - } -} // end 0x42::m - - -// -- Model dump after env processor specification checker: -module 0x42::m { - struct S<T> { - x: T, - } - private fun id<T>(self: S<T>): S<T> { - self - } - private fun inlined<T>(f: |S<T>|S<T>,s: S<T>) { - (f)(s); - Tuple() - } - private fun receiver<T>(self: S<T>,y: T) { - select m::S.x<S<T>>(self) = y; - Tuple() - } - private fun receiver_more_generics<T,R>(self: S<T>,_y: R) { - Tuple() - } - private fun receiver_needs_type_args<T,R>(self: S<T>,_y: T) { - Abort(1) - } - private fun receiver_ref<T>(self: &S<T>,_y: T) { - Tuple() - } - private fun receiver_ref_mut<T>(self: &mut S<T>,y: T) { - select m::S.x<&mut S<T>>(self) = y - } - private fun test_call_styles(s: S<u64>,x: u64) { - m::receiver<u64>(s, x); - m::receiver_ref<u64>(Borrow(Immutable)(s), x); - m::receiver_ref_mut<u64>(Borrow(Mutable)(s), x); - m::receiver_more_generics<u64, u64>(s, 22); - m::receiver_needs_type_args<u64, u8>(s, x); - Tuple() - } - private fun test_receiver_inference(s: S<u64>) { - m::inlined<u64>(closure m::test_receiver_inference$lambda$1(), s) - } - private fun test_receiver_inference$lambda$1(s: S<u64>): S<u64> { - m::id<u64>(s) - } -} // end 0x42::m - - -// -- Model dump after env processor specification rewriter: -module 0x42::m { - struct S<T> { - x: T, - } - private fun id<T>(self: S<T>): S<T> { - self - } - private fun inlined<T>(f: |S<T>|S<T>,s: S<T>) { - (f)(s); - Tuple() - } - private fun receiver<T>(self: S<T>,y: T) { - select m::S.x<S<T>>(self) = y; - Tuple() - } - private fun receiver_more_generics<T,R>(self: S<T>,_y: R) { - Tuple() - } - private fun receiver_needs_type_args<T,R>(self: S<T>,_y: T) { - Abort(1) - } - private fun receiver_ref<T>(self: &S<T>,_y: T) { - Tuple() - } - private fun receiver_ref_mut<T>(self: &mut S<T>,y: T) { - select m::S.x<&mut S<T>>(self) = y - } - private fun test_call_styles(s: S<u64>,x: u64) { - m::receiver<u64>(s, x); - m::receiver_ref<u64>(Borrow(Immutable)(s), x); - m::receiver_ref_mut<u64>(Borrow(Mutable)(s), x); - m::receiver_more_generics<u64, u64>(s, 22); - m::receiver_needs_type_args<u64, u8>(s, x); - Tuple() - } - private fun test_receiver_inference(s: S<u64>) { - m::inlined<u64>(closure m::test_receiver_inference$lambda$1(), s) - } - private fun test_receiver_inference$lambda$1(s: S<u64>): S<u64> { - m::id<u64>(s) - } -} // end 0x42::m - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/generic_calls.move:36:9 - │ -36 │ f(s); - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/generic_calls.move:47:17 │ 47 │ inlined(|s| s.id(), s) diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generics.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generics.lambda.exp index 2a10fb8eecd8e..e1e6a42e3dc86 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generics.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/generics.lambda.exp @@ -327,8 +327,8 @@ module 0x42::Test { Diagnostics: -error: captured variable `sum` cannot be modified inside of a lambda - ┌─ tests/lambda/inline-parity/generics.move:16:30 +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/generics.move:16:26 │ 16 │ foreach<u64>(&v, |e| sum = sum + *e); - │ ^^^ + │ ^^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inline_fun_in_spec.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inline_fun_in_spec.lambda.exp index d4783a884aa54..10d5cf390bb96 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inline_fun_in_spec.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inline_fun_in_spec.lambda.exp @@ -483,163 +483,10 @@ module 0x42::m { } // end 0x42::m -// -- Model dump after env processor lambda-lifting: -module 0x42::m { - spec { - invariant forall a: address: TypeDomain<address>(): Implies(exists<0x42::m::S>(a), m::exec<address, bool>(|a: address| Lt(select m::S.f<0x42::m::S>({ - let (a: address): (address) = Tuple(a); - BorrowGlobal(Immutable)<0x42::m::S>(a) - }), 10), a)); - } - - struct S { - f: u64, - } - spec { - invariant m::exec<num, bool>(|x: num| Gt(x, 0), select m::S.f()); - } - - private fun exec<T,R>(f: |T|R,x: T): R { - { - let r: R = (f)(x); - spec { - assert Eq<#1>(r, (f)($t1)); - } - ; - r - } - } - private fun function_code_spec_block(x: u64): u64 { - spec { - assert m::exec<num, bool>(closure m::function_code_spec_block$lambda$1(), $t0); - } - ; - Add<u64>(x, 1) - } - private fun function_spec_block(x: u64): u64 { - Add<u64>(x, 1) - } - spec { - ensures Eq<u64>(result0(), m::exec<num, num>(|x: num| Add(x, 1), $t0)); - } - - private inline fun get<R>(a: address): &R { - BorrowGlobal(Immutable)<R>(a) - } - private fun function_code_spec_block$lambda$1(y: num): bool { - Gt(y, 0) - } -} // end 0x42::m - - -// -- Model dump after env processor specification checker: -module 0x42::m { - spec { - invariant forall a: address: TypeDomain<address>(): Implies(exists<0x42::m::S>(a), m::exec<address, bool>(|a: address| Lt(select m::S.f<0x42::m::S>({ - let (a: address): (address) = Tuple(a); - BorrowGlobal(Immutable)<0x42::m::S>(a) - }), 10), a)); - } - - struct S { - f: u64, - } - spec { - invariant m::exec<num, bool>(|x: num| Gt(x, 0), select m::S.f()); - } - - private fun exec<T,R>(f: |T|R,x: T): R { - { - let r: R = (f)(x); - spec { - assert Eq<#1>(r, (f)($t1)); - } - ; - r - } - } - private fun function_code_spec_block(x: u64): u64 { - spec { - assert m::exec<num, bool>(closure m::function_code_spec_block$lambda$1(), $t0); - } - ; - Add<u64>(x, 1) - } - private fun function_spec_block(x: u64): u64 { - Add<u64>(x, 1) - } - spec { - ensures Eq<u64>(result0(), m::exec<num, num>(|x: num| Add(x, 1), $t0)); - } - - private inline fun get<R>(a: address): &R { - BorrowGlobal(Immutable)<R>(a) - } - private fun function_code_spec_block$lambda$1(y: num): bool { - Gt(y, 0) - } -} // end 0x42::m - - -// -- Model dump after env processor specification rewriter: -module 0x42::m { - spec { - invariant forall a: address: TypeDomain<address>(): Implies(exists<0x42::m::S>(a), m::$exec<address, bool>(|a: address| Lt(select m::S.f<0x42::m::S>({ - let (a: address): (address) = Tuple(a); - global<0x42::m::S>(a) - }), 10), a)); - } - - struct S { - f: u64, - } - spec { - invariant m::$exec<num, bool>(|x: num| Gt(x, 0), select m::S.f()); - } - - private fun exec<T,R>(f: |T|R,x: T): R { - { - let r: R = (f)(x); - spec { - assert Eq<#1>(r, (f)($t1)); - } - ; - r - } - } - private fun function_code_spec_block(x: u64): u64 { - spec { - assert m::$exec<num, bool>(closure m::function_code_spec_block$lambda$1(), $t0); - } - ; - Add<u64>(x, 1) - } - private fun function_spec_block(x: u64): u64 { - Add<u64>(x, 1) - } - spec { - ensures Eq<u64>(result0(), m::$exec<num, num>(|x: num| Add(x, 1), $t0)); - } - - private inline fun get<R>(a: address): &R { - BorrowGlobal(Immutable)<R>(a) - } - private fun function_code_spec_block$lambda$1(y: num): bool { - Gt(y, 0) - } - spec fun $exec<T,R>(f: |#0|#1,x: #0): #1 { - { - let r: #1 = (f)(x); - r - } - } -} // end 0x42::m - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/inline_fun_in_spec.move:4:17 - │ -4 │ let r = f(x); - │ ^ +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/inline_fun_in_spec.move:19:28 + │ +19 │ spec { assert exec(|y| y > 0, x); }; + │ ^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inlining1.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inlining1.lambda.exp index ccd5c61991485..c94277a84e19c 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inlining1.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/inlining1.lambda.exp @@ -207,90 +207,9 @@ module 0x42::Test { } // end 0x42::Test -// -- Model dump after env processor lambda-lifting: -module 0x42::Test { - private fun foo(f: |u64|u64,x: u64): u64 { - (f)(x) - } - public fun main() { - if Eq<u64>(Test::test(), 3) { - Tuple() - } else { - Abort(5) - }; - Tuple() - } - public fun test(): u64 { - Test::foo(closure Test::test$lambda$1(), 10) - } - private fun test$lambda$1(param$0: u64): u64 { - { - let _: u64 = param$0; - 3 - } - } -} // end 0x42::Test - - -// -- Model dump after env processor specification checker: -module 0x42::Test { - private fun foo(f: |u64|u64,x: u64): u64 { - (f)(x) - } - public fun main() { - if Eq<u64>(Test::test(), 3) { - Tuple() - } else { - Abort(5) - }; - Tuple() - } - public fun test(): u64 { - Test::foo(closure Test::test$lambda$1(), 10) - } - private fun test$lambda$1(param$0: u64): u64 { - { - let _: u64 = param$0; - 3 - } - } -} // end 0x42::Test - - -// -- Model dump after env processor specification rewriter: -module 0x42::Test { - private fun foo(f: |u64|u64,x: u64): u64 { - (f)(x) - } - public fun main() { - if Eq<u64>(Test::test(), 3) { - Tuple() - } else { - Abort(5) - }; - Tuple() - } - public fun test(): u64 { - Test::foo(closure Test::test$lambda$1(), 10) - } - private fun test$lambda$1(param$0: u64): u64 { - { - let _: u64 = param$0; - 3 - } - } -} // end 0x42::Test - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/inlining1.move:4:9 - │ -4 │ f(x) - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/inlining1.move:8:13 │ 8 │ foo(|_| 3, 10) diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda.lambda.exp index 0edf647447ceb..affdfc91b8e16 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda.lambda.exp @@ -745,8 +745,53 @@ module 0x42::LambdaTest { Diagnostics: -error: captured variable `product` cannot be modified inside of a lambda - ┌─ tests/lambda/inline-parity/lambda.move:30:18 +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/lambda.move:30:14 │ 30 │ foreach(&v, |e| product = LambdaTest1::inline_mul(product, *e)); - │ ^^^^^^^ + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/lambda.move:34:29 + │ +34 │ LambdaTest1::inline_apply1(|z|z, g(LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(|x|x, 3)))) + 2 + │ ^^^^ + +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/lambda.move:34:90 + │ +34 │ LambdaTest1::inline_apply1(|z|z, g(LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(|x|x, 3)))) + 2 + │ ^^^^ + +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/lambda.move:40:29 + │ +40 │ LambdaTest1::inline_apply(|y|y, x) + │ ^^^^ + +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/lambda.move:39:59 + │ +39 │ LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(|x| { + │ ╭──────────────────────────────────────────────────────────────^ +40 │ │ LambdaTest1::inline_apply(|y|y, x) +41 │ │ }, + │ ╰─────────^ + +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/lambda.move:54:29 + │ +54 │ LambdaTest2::inline_apply2(|x| x + 1, 3) + + │ ^^^^^^^^^ + +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/lambda.move:55:29 + │ +55 │ LambdaTest2::inline_apply2(|x| x * x, inline_apply(|y|y, 3)) + │ ^^^^^^^^^ + +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/lambda.move:55:53 + │ +55 │ LambdaTest2::inline_apply2(|x| x * x, inline_apply(|y|y, 3)) + │ ^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast.lambda.exp index cc4db35759051..277584ca7ef3f 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast.lambda.exp @@ -434,8 +434,20 @@ module 0x12391283::M { Diagnostics: -error: captured variable `accu` cannot be modified inside of a lambda - ┌─ tests/lambda/inline-parity/lambda_cast.move:18:35 +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/lambda_cast.move:18:28 │ 18 │ vector_for_each(v, |elem| accu = f(accu, elem)); - │ ^^^^ + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/lambda_cast.move:26:61 + │ +26 │ vector_fold<u64, u8>(gas_schedule_blob, (0 as u64), |sum, addend| sum + (addend as u64)) + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/lambda_cast.move:33:52 + │ +33 │ vector_fold(gas_schedule_blob, (0 as u64), |sum, addend| sum + (addend as u64)) + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.exp index d9cd9d072137b..95c37d67c6f26 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.exp @@ -1,6 +1,6 @@ Diagnostics: -error: cannot pass `|(u64, integer)|u64` to a function which expects argument of type `|(u64, vector<u8>)|u64` +error: cannot pass `|(u64, integer)|u64 with copy+store` to a function which expects argument of type `|(u64, vector<u8>)|u64` ┌─ tests/lambda/inline-parity/lambda_cast_err.move:26:52 │ 26 │ vector_fold(gas_schedule_blob, (0 as u64), |sum, addend| sum + (addend as u64)) diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.lambda.exp index d9cd9d072137b..95c37d67c6f26 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_cast_err.lambda.exp @@ -1,6 +1,6 @@ Diagnostics: -error: cannot pass `|(u64, integer)|u64` to a function which expects argument of type `|(u64, vector<u8>)|u64` +error: cannot pass `|(u64, integer)|u64 with copy+store` to a function which expects argument of type `|(u64, vector<u8>)|u64` ┌─ tests/lambda/inline-parity/lambda_cast_err.move:26:52 │ 26 │ vector_fold(gas_schedule_blob, (0 as u64), |sum, addend| sum + (addend as u64)) diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_no_param.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_no_param.lambda.exp index eb23c97b263b2..dd01bdee97745 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_no_param.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_no_param.lambda.exp @@ -207,102 +207,15 @@ module 0xdecafbad::m { } // end 0xdecafbad::m -// -- Model dump after env processor lambda-lifting: -module 0xdecafbad::m { - private fun bar(f: |()|u64): u64 { - (f)() - } - private fun foo(f: |()|) { - (f)(); - Tuple() - } - public fun one() { - m::foo(closure m::one$lambda$1()); - Tuple() - } - public fun two(x: u64): u64 { - m::bar(closure m::two$lambda$1(x)) - } - private fun one$lambda$1() { - Tuple() - } - private fun two$lambda$1(x: u64): u64 { - x - } -} // end 0xdecafbad::m - - -// -- Model dump after env processor specification checker: -module 0xdecafbad::m { - private fun bar(f: |()|u64): u64 { - (f)() - } - private fun foo(f: |()|) { - (f)(); - Tuple() - } - public fun one() { - m::foo(closure m::one$lambda$1()); - Tuple() - } - public fun two(x: u64): u64 { - m::bar(closure m::two$lambda$1(x)) - } - private fun one$lambda$1() { - Tuple() - } - private fun two$lambda$1(x: u64): u64 { - x - } -} // end 0xdecafbad::m - - -// -- Model dump after env processor specification rewriter: -module 0xdecafbad::m { - private fun bar(f: |()|u64): u64 { - (f)() - } - private fun foo(f: |()|) { - (f)(); - Tuple() - } - public fun one() { - m::foo(closure m::one$lambda$1()); - Tuple() - } - public fun two(x: u64): u64 { - m::bar(closure m::two$lambda$1(x)) - } - private fun one$lambda$1() { - Tuple() - } - private fun two$lambda$1(x: u64): u64 { - x - } -} // end 0xdecafbad::m - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/lambda_no_param.move:3:9 - │ -3 │ f(); - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/lambda_no_param.move:7:13 │ 7 │ foo(|| {}); │ ^^^^^ -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/lambda_no_param.move:11:9 - │ -11 │ f() - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/lambda_no_param.move:15:13 │ 15 │ bar(||x) diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param.lambda.exp index b3587c0f077ef..5e54032b12b92 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param.lambda.exp @@ -603,234 +603,27 @@ module 0x42::LambdaParam { } // end 0x42::LambdaParam -// -- Model dump after env processor lambda-lifting: -module 0x42::LambdaParam { - public fun inline_apply(f: |u64|u64,b: u64): u64 { - (f)(b) - } - public fun inline_apply2(f: |u64|u64,b: u64): u64 { - LambdaParam::inline_apply(f, b) - } - public fun inline_apply3(f: |u64|u64,b: u64): u64 { - LambdaParam::inline_apply4(f, b) - } - public fun inline_apply4(_f: |u64|u64,b: u64): u64 { - b - } - private fun test_lambda_symbol_param1() { - { - let a: u64 = LambdaParam::inline_apply2(closure LambdaParam::test_lambda_symbol_param1$lambda$1(), 3); - if Eq<u64>(a, 3) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - } - private fun test_lambda_symbol_param2() { - { - let a: u64 = LambdaParam::inline_apply2(closure LambdaParam::test_lambda_symbol_param2$lambda$1(), 3); - if Eq<u64>(a, 3) { - Tuple() - } else { - Abort(0) - }; - { - let b: u64 = LambdaParam::inline_apply(closure LambdaParam::test_lambda_symbol_param2$lambda$2(), 3); - if Eq<u64>(b, 3) { - Tuple() - } else { - Abort(0) - }; - { - let b: u64 = LambdaParam::inline_apply3(closure LambdaParam::test_lambda_symbol_param2$lambda$3(), 3); - if Eq<u64>(b, 3) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - } - } - } - private fun test_lambda_symbol_param1$lambda$1(x: u64): u64 { - x - } - private fun test_lambda_symbol_param2$lambda$1(x: u64): u64 { - x - } - private fun test_lambda_symbol_param2$lambda$2(x: u64): u64 { - x - } - private fun test_lambda_symbol_param2$lambda$3(x: u64): u64 { - x - } -} // end 0x42::LambdaParam - - -// -- Model dump after env processor specification checker: -module 0x42::LambdaParam { - public fun inline_apply(f: |u64|u64,b: u64): u64 { - (f)(b) - } - public fun inline_apply2(f: |u64|u64,b: u64): u64 { - LambdaParam::inline_apply(f, b) - } - public fun inline_apply3(f: |u64|u64,b: u64): u64 { - LambdaParam::inline_apply4(f, b) - } - public fun inline_apply4(_f: |u64|u64,b: u64): u64 { - b - } - private fun test_lambda_symbol_param1() { - { - let a: u64 = LambdaParam::inline_apply2(closure LambdaParam::test_lambda_symbol_param1$lambda$1(), 3); - if Eq<u64>(a, 3) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - } - private fun test_lambda_symbol_param2() { - { - let a: u64 = LambdaParam::inline_apply2(closure LambdaParam::test_lambda_symbol_param2$lambda$1(), 3); - if Eq<u64>(a, 3) { - Tuple() - } else { - Abort(0) - }; - { - let b: u64 = LambdaParam::inline_apply(closure LambdaParam::test_lambda_symbol_param2$lambda$2(), 3); - if Eq<u64>(b, 3) { - Tuple() - } else { - Abort(0) - }; - { - let b: u64 = LambdaParam::inline_apply3(closure LambdaParam::test_lambda_symbol_param2$lambda$3(), 3); - if Eq<u64>(b, 3) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - } - } - } - private fun test_lambda_symbol_param1$lambda$1(x: u64): u64 { - x - } - private fun test_lambda_symbol_param2$lambda$1(x: u64): u64 { - x - } - private fun test_lambda_symbol_param2$lambda$2(x: u64): u64 { - x - } - private fun test_lambda_symbol_param2$lambda$3(x: u64): u64 { - x - } -} // end 0x42::LambdaParam - - -// -- Model dump after env processor specification rewriter: -module 0x42::LambdaParam { - public fun inline_apply(f: |u64|u64,b: u64): u64 { - (f)(b) - } - public fun inline_apply2(f: |u64|u64,b: u64): u64 { - LambdaParam::inline_apply(f, b) - } - public fun inline_apply3(f: |u64|u64,b: u64): u64 { - LambdaParam::inline_apply4(f, b) - } - public fun inline_apply4(_f: |u64|u64,b: u64): u64 { - b - } - private fun test_lambda_symbol_param1() { - { - let a: u64 = LambdaParam::inline_apply2(closure LambdaParam::test_lambda_symbol_param1$lambda$1(), 3); - if Eq<u64>(a, 3) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - } - private fun test_lambda_symbol_param2() { - { - let a: u64 = LambdaParam::inline_apply2(closure LambdaParam::test_lambda_symbol_param2$lambda$1(), 3); - if Eq<u64>(a, 3) { - Tuple() - } else { - Abort(0) - }; - { - let b: u64 = LambdaParam::inline_apply(closure LambdaParam::test_lambda_symbol_param2$lambda$2(), 3); - if Eq<u64>(b, 3) { - Tuple() - } else { - Abort(0) - }; - { - let b: u64 = LambdaParam::inline_apply3(closure LambdaParam::test_lambda_symbol_param2$lambda$3(), 3); - if Eq<u64>(b, 3) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - } - } - } - private fun test_lambda_symbol_param1$lambda$1(x: u64): u64 { - x - } - private fun test_lambda_symbol_param2$lambda$1(x: u64): u64 { - x - } - private fun test_lambda_symbol_param2$lambda$2(x: u64): u64 { - x - } - private fun test_lambda_symbol_param2$lambda$3(x: u64): u64 { - x - } -} // end 0x42::LambdaParam - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/lambda_param.move:3:2 - │ -3 │ f(b) - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/lambda_param.move:19:24 │ 19 │ let a = inline_apply2(|x| x, 3); │ ^^^^^ -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/lambda_param.move:24:24 │ 24 │ let a = inline_apply2(|x| x, 3); │ ^^^^^ -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/lambda_param.move:26:23 │ 26 │ let b = inline_apply(|x| x, 3); │ ^^^^^ -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/lambda_param.move:28:24 │ 28 │ let b = inline_apply3(|x| x, 3); diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.exp index 33468b26f118d..64614096d6592 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.exp @@ -1,6 +1,6 @@ Diagnostics: -error: cannot pass `|u64|u64` to a function which expects argument of type `|u64|` +error: cannot pass `|u64|u64 with copy+store` to a function which expects argument of type `|u64|` ┌─ tests/lambda/inline-parity/lambda_param_mismatch.move:20:32 │ 20 │ vector_for_each(input, |item| { diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.lambda.exp index 33468b26f118d..64614096d6592 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_param_mismatch.lambda.exp @@ -1,6 +1,6 @@ Diagnostics: -error: cannot pass `|u64|u64` to a function which expects argument of type `|u64|` +error: cannot pass `|u64|u64 with copy+store` to a function which expects argument of type `|u64|` ┌─ tests/lambda/inline-parity/lambda_param_mismatch.move:20:32 │ 20 │ vector_for_each(input, |item| { diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_return.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_return.lambda.exp index 2b9ffb4ba4160..1ea24d42e88ac 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_return.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_return.lambda.exp @@ -207,81 +207,9 @@ module 0x42::LambdaReturn { } // end 0x42::LambdaReturn -// -- Model dump after env processor lambda-lifting: -module 0x42::LambdaReturn { - public fun inline_apply2(f: |u64|u64,b: u64): u64 { - return (f)(b) - } - private fun test_lambda_symbol_param() { - { - let a: u64 = LambdaReturn::inline_apply2(closure LambdaReturn::test_lambda_symbol_param$lambda$1(), 3); - if Eq<u64>(a, 3) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - } - private fun test_lambda_symbol_param$lambda$1(x: u64): u64 { - x - } -} // end 0x42::LambdaReturn - - -// -- Model dump after env processor specification checker: -module 0x42::LambdaReturn { - public fun inline_apply2(f: |u64|u64,b: u64): u64 { - return (f)(b) - } - private fun test_lambda_symbol_param() { - { - let a: u64 = LambdaReturn::inline_apply2(closure LambdaReturn::test_lambda_symbol_param$lambda$1(), 3); - if Eq<u64>(a, 3) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - } - private fun test_lambda_symbol_param$lambda$1(x: u64): u64 { - x - } -} // end 0x42::LambdaReturn - - -// -- Model dump after env processor specification rewriter: -module 0x42::LambdaReturn { - public fun inline_apply2(f: |u64|u64,b: u64): u64 { - return (f)(b) - } - private fun test_lambda_symbol_param() { - { - let a: u64 = LambdaReturn::inline_apply2(closure LambdaReturn::test_lambda_symbol_param$lambda$1(), 3); - if Eq<u64>(a, 3) { - Tuple() - } else { - Abort(0) - }; - Tuple() - } - } - private fun test_lambda_symbol_param$lambda$1(x: u64): u64 { - x - } -} // end 0x42::LambdaReturn - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/lambda_return.move:3:9 - │ -3 │ return f(b) - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/lambda_return.move:7:24 │ 7 │ let a = inline_apply2(|x| { x }, 3); diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_typed.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_typed.lambda.exp index 396fdaf35ada9..ffe457423462b 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_typed.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/lambda_typed.lambda.exp @@ -1285,325 +1285,19 @@ module 0x42::LambdaTest { } // end 0x42::LambdaTest -// -- Model dump after env processor lambda-lifting: -module 0x42::LambdaTest1 { - public inline fun inline_apply(f: |u64|u64,b: u64): u64 { - (f)(b) - } - public inline fun inline_apply1(f: |u64|u64,b: u64): u64 { - { - let (a: u64, b: u64): (u64, u64) = Tuple(Add<u64>((f)(b), 1), 12); - Mul<u64>(a, 12) - } - } - public inline fun inline_mul(a: u64,b: u64): u64 { - Mul<u64>(a, b) - } -} // end 0x42::LambdaTest1 -module 0x42::LambdaTest2 { - use 0x42::LambdaTest1; // resolved as: 0x42::LambdaTest1 - use std::vector; - public inline fun foreach<T>(v: &vector<T>,action: |&T|) { - { - let i: u64 = 0; - loop { - if Lt<u64>(i, vector::length<T>(v)) { - (action)(vector::borrow<T>(v, i)); - i: u64 = Add<u64>(i, 1); - Tuple() - } else { - break - } - } - } - } - public inline fun inline_apply2(g: |u64|u64,c: u64): u64 { - Add<u64>({ - let (b: u64): (u64) = Tuple((g)({ - let (a: u64, b: u64): (u64, u64) = Tuple(c, 3); - Mul<u64>(a, 3) - })); - { - let (a: u64, b: u64): (u64, u64) = Tuple(Add<u64>({ - let (z: u64): (u64) = Tuple(b); - z - }, 1), 12); - Mul<u64>(a, 12) - } - }, 2) - } - public inline fun inline_apply3(g: |u64|u64,c: u64): u64 { - Add<u64>(LambdaTest1::inline_apply1(g, LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(closure LambdaTest2::inline_apply3$lambda$2(), 3))), 4) - } - public fun test_inline_lambda() { - { - let product: u64 = 1; - { - let (v: &vector<u64>): (&vector<u64>) = Tuple(Borrow(Immutable)([Number(1), Number(2), Number(3)])); - { - let i: u64 = 0; - loop { - if Lt<u64>(i, vector::length<u64>(v)) { - { - let (e: &u64): (&u64) = Tuple(vector::borrow<u64>(v, i)); - product: u64 = { - let (a: u64, b: u64): (u64, u64) = Tuple(product, Deref(e)); - Mul<u64>(a, b) - } - }; - i: u64 = Add<u64>(i, 1); - Tuple() - } else { - break - } - } - } - }; - Tuple() - } - } - private fun inline_apply3$lambda$1(y: u64): u64 { - y - } - private fun inline_apply3$lambda$2(x: u64): u64 { - LambdaTest1::inline_apply(closure LambdaTest2::inline_apply3$lambda$1(), x) - } -} // end 0x42::LambdaTest2 -module 0x42::LambdaTest { - use 0x42::LambdaTest2; // resolved as: 0x42::LambdaTest2 - public inline fun inline_apply(f: |u64|u64,b: u64): u64 { - (f)(b) - } - public inline fun inline_apply_test(): u64 { - 1120 - } - private fun test_lambda() { - if false { - Tuple() - } else { - Abort(0) - }; - Tuple() - } -} // end 0x42::LambdaTest - - -// -- Model dump after env processor specification checker: -module 0x42::LambdaTest1 { - public inline fun inline_apply(f: |u64|u64,b: u64): u64 { - (f)(b) - } - public inline fun inline_apply1(f: |u64|u64,b: u64): u64 { - { - let (a: u64, b: u64): (u64, u64) = Tuple(Add<u64>((f)(b), 1), 12); - Mul<u64>(a, 12) - } - } - public inline fun inline_mul(a: u64,b: u64): u64 { - Mul<u64>(a, b) - } -} // end 0x42::LambdaTest1 -module 0x42::LambdaTest2 { - use 0x42::LambdaTest1; // resolved as: 0x42::LambdaTest1 - use std::vector; - public inline fun foreach<T>(v: &vector<T>,action: |&T|) { - { - let i: u64 = 0; - loop { - if Lt<u64>(i, vector::length<T>(v)) { - (action)(vector::borrow<T>(v, i)); - i: u64 = Add<u64>(i, 1); - Tuple() - } else { - break - } - } - } - } - public inline fun inline_apply2(g: |u64|u64,c: u64): u64 { - Add<u64>({ - let (b: u64): (u64) = Tuple((g)({ - let (a: u64, b: u64): (u64, u64) = Tuple(c, 3); - Mul<u64>(a, 3) - })); - { - let (a: u64, b: u64): (u64, u64) = Tuple(Add<u64>({ - let (z: u64): (u64) = Tuple(b); - z - }, 1), 12); - Mul<u64>(a, 12) - } - }, 2) - } - public inline fun inline_apply3(g: |u64|u64,c: u64): u64 { - Add<u64>(LambdaTest1::inline_apply1(g, LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(closure LambdaTest2::inline_apply3$lambda$2(), 3))), 4) - } - public fun test_inline_lambda() { - { - let product: u64 = 1; - { - let (v: &vector<u64>): (&vector<u64>) = Tuple(Borrow(Immutable)([Number(1), Number(2), Number(3)])); - { - let i: u64 = 0; - loop { - if Lt<u64>(i, vector::length<u64>(v)) { - { - let (e: &u64): (&u64) = Tuple(vector::borrow<u64>(v, i)); - product: u64 = { - let (a: u64, b: u64): (u64, u64) = Tuple(product, Deref(e)); - Mul<u64>(a, b) - } - }; - i: u64 = Add<u64>(i, 1); - Tuple() - } else { - break - } - } - } - }; - Tuple() - } - } - private fun inline_apply3$lambda$1(y: u64): u64 { - y - } - private fun inline_apply3$lambda$2(x: u64): u64 { - LambdaTest1::inline_apply(closure LambdaTest2::inline_apply3$lambda$1(), x) - } -} // end 0x42::LambdaTest2 -module 0x42::LambdaTest { - use 0x42::LambdaTest2; // resolved as: 0x42::LambdaTest2 - public inline fun inline_apply(f: |u64|u64,b: u64): u64 { - (f)(b) - } - public inline fun inline_apply_test(): u64 { - 1120 - } - private fun test_lambda() { - if false { - Tuple() - } else { - Abort(0) - }; - Tuple() - } -} // end 0x42::LambdaTest - - -// -- Model dump after env processor specification rewriter: -module 0x42::LambdaTest1 { - public inline fun inline_apply(f: |u64|u64,b: u64): u64 { - (f)(b) - } - public inline fun inline_apply1(f: |u64|u64,b: u64): u64 { - { - let (a: u64, b: u64): (u64, u64) = Tuple(Add<u64>((f)(b), 1), 12); - Mul<u64>(a, 12) - } - } - public inline fun inline_mul(a: u64,b: u64): u64 { - Mul<u64>(a, b) - } -} // end 0x42::LambdaTest1 -module 0x42::LambdaTest2 { - use 0x42::LambdaTest1; // resolved as: 0x42::LambdaTest1 - use std::vector; - public inline fun foreach<T>(v: &vector<T>,action: |&T|) { - { - let i: u64 = 0; - loop { - if Lt<u64>(i, vector::length<T>(v)) { - (action)(vector::borrow<T>(v, i)); - i: u64 = Add<u64>(i, 1); - Tuple() - } else { - break - } - } - } - } - public inline fun inline_apply2(g: |u64|u64,c: u64): u64 { - Add<u64>({ - let (b: u64): (u64) = Tuple((g)({ - let (a: u64, b: u64): (u64, u64) = Tuple(c, 3); - Mul<u64>(a, 3) - })); - { - let (a: u64, b: u64): (u64, u64) = Tuple(Add<u64>({ - let (z: u64): (u64) = Tuple(b); - z - }, 1), 12); - Mul<u64>(a, 12) - } - }, 2) - } - public inline fun inline_apply3(g: |u64|u64,c: u64): u64 { - Add<u64>(LambdaTest1::inline_apply1(g, LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(closure LambdaTest2::inline_apply3$lambda$2(), 3))), 4) - } - public fun test_inline_lambda() { - { - let product: u64 = 1; - { - let (v: &vector<u64>): (&vector<u64>) = Tuple(Borrow(Immutable)([Number(1), Number(2), Number(3)])); - { - let i: u64 = 0; - loop { - if Lt<u64>(i, vector::length<u64>(v)) { - { - let (e: &u64): (&u64) = Tuple(vector::borrow<u64>(v, i)); - product: u64 = { - let (a: u64, b: u64): (u64, u64) = Tuple(product, Deref(e)); - Mul<u64>(a, b) - } - }; - i: u64 = Add<u64>(i, 1); - Tuple() - } else { - break - } - } - } - }; - Tuple() - } - } - private fun inline_apply3$lambda$1(y: u64): u64 { - y - } - private fun inline_apply3$lambda$2(x: u64): u64 { - LambdaTest1::inline_apply(closure LambdaTest2::inline_apply3$lambda$1(), x) - } -} // end 0x42::LambdaTest2 -module 0x42::LambdaTest { - use 0x42::LambdaTest2; // resolved as: 0x42::LambdaTest2 - public inline fun inline_apply(f: |u64|u64,b: u64): u64 { - (f)(b) - } - public inline fun inline_apply_test(): u64 { - 1120 - } - private fun test_lambda() { - if false { - Tuple() - } else { - Abort(0) - }; - Tuple() - } -} // end 0x42::LambdaTest - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/lambda_typed.move:11:2 - │ -11 │ f(b) - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/lambda_typed.move:40:29 │ 40 │ LambdaTest1::inline_apply(|y: u64|y, x) │ ^^^^^^^^^ + +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/lambda_typed.move:39:59 + │ +39 │ LambdaTest1::inline_mul(c, LambdaTest1::inline_apply(|x:u64| { + │ ╭──────────────────────────────────────────────────────────────^ +40 │ │ LambdaTest1::inline_apply(|y: u64|y, x) +41 │ │ }, + │ ╰─────────^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/masking.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/masking.lambda.exp index a89c6271195d1..4f3bf689cb56b 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/masking.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/masking.lambda.exp @@ -119,96 +119,15 @@ module 0x42::Test { } // end 0x42::Test -// -- Model dump after env processor lambda-lifting: -module 0x42::Test { - private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { - Add<u64>((f)(x, _y), (g)(x, _y)) - } - public fun main(): u64 { - Test::foo(closure Test::main$lambda$1(), closure Test::main$lambda$2(), 10, 100) - } - private fun main$lambda$1(x: u64,param$1: u64): u64 { - { - let _: u64 = param$1; - x - } - } - private fun main$lambda$2(param$0: u64,y: u64): u64 { - { - let _: u64 = param$0; - y - } - } -} // end 0x42::Test - - -// -- Model dump after env processor specification checker: -module 0x42::Test { - private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { - Add<u64>((f)(x, _y), (g)(x, _y)) - } - public fun main(): u64 { - Test::foo(closure Test::main$lambda$1(), closure Test::main$lambda$2(), 10, 100) - } - private fun main$lambda$1(x: u64,param$1: u64): u64 { - { - let _: u64 = param$1; - x - } - } - private fun main$lambda$2(param$0: u64,y: u64): u64 { - { - let _: u64 = param$0; - y - } - } -} // end 0x42::Test - - -// -- Model dump after env processor specification rewriter: -module 0x42::Test { - private fun foo(f: |(u64, u64)|u64,g: |(u64, u64)|u64,x: u64,_y: u64): u64 { - Add<u64>((f)(x, _y), (g)(x, _y)) - } - public fun main(): u64 { - Test::foo(closure Test::main$lambda$1(), closure Test::main$lambda$2(), 10, 100) - } - private fun main$lambda$1(x: u64,param$1: u64): u64 { - { - let _: u64 = param$1; - x - } - } - private fun main$lambda$2(param$0: u64,y: u64): u64 { - { - let _: u64 = param$0; - y - } - } -} // end 0x42::Test - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/masking.move:4:9 - │ -4 │ f(x, _y) + g(x, _y) - │ ^ - -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/masking.move:4:20 - │ -4 │ f(x, _y) + g(x, _y) - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/masking.move:8:13 │ 8 │ foo(|x, _| x, |_, y| y, 10, 100) │ ^^^^^^^^ -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/masking.move:8:23 │ 8 │ foo(|x, _| x, |_, y| y, 10, 100) diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/multi_param.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/multi_param.lambda.exp index 79df5cae6a545..855a868e5dcb4 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/multi_param.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/multi_param.lambda.exp @@ -451,8 +451,18 @@ module 0x42::Test { Diagnostics: -error: captured variable `result` cannot be modified inside of a lambda - ┌─ tests/lambda/inline-parity/multi_param.move:21:13 +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/multi_param.move:19:29 │ -21 │ result = result + f(&elem.k, &mut elem.v); - │ ^^^^^^ +19 │ for_each_ref_mut(v, |elem| { + │ ╭─────────────────────────────^ +20 │ │ let elem: &mut Elem<K, V> = elem; // Checks whether scoping is fine +21 │ │ result = result + f(&elem.k, &mut elem.v); +22 │ │ }); + │ ╰─────────^ + +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/multi_param.move:27:64 + │ +27 │ assert!(elem_for_each_ref(&mut vector[Elem{k:1, v:2}], |x,y| *x + *y) == 3, 0) + │ ^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda.lambda.exp index 019feaaebebc4..7793f33a9f484 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda.lambda.exp @@ -119,72 +119,15 @@ module 0x42::Test { } // end 0x42::Test -// -- Model dump after env processor lambda-lifting: -module 0x42::Test { - public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { - (f)(x, y) - } - public fun test(): u64 { - Test::apply(closure Test::test$lambda$1(), 1, Test::apply(closure Test::test$lambda$2(), 2, 1)) - } - private fun test$lambda$1(x: u64,y: u64): u64 { - Add<u64>(x, y) - } - private fun test$lambda$2(x: u64,y: u64): u64 { - Mul<u64>(x, y) - } -} // end 0x42::Test - - -// -- Model dump after env processor specification checker: -module 0x42::Test { - public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { - (f)(x, y) - } - public fun test(): u64 { - Test::apply(closure Test::test$lambda$1(), 1, Test::apply(closure Test::test$lambda$2(), 2, 1)) - } - private fun test$lambda$1(x: u64,y: u64): u64 { - Add<u64>(x, y) - } - private fun test$lambda$2(x: u64,y: u64): u64 { - Mul<u64>(x, y) - } -} // end 0x42::Test - - -// -- Model dump after env processor specification rewriter: -module 0x42::Test { - public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { - (f)(x, y) - } - public fun test(): u64 { - Test::apply(closure Test::test$lambda$1(), 1, Test::apply(closure Test::test$lambda$2(), 2, 1)) - } - private fun test$lambda$1(x: u64,y: u64): u64 { - Add<u64>(x, y) - } - private fun test$lambda$2(x: u64,y: u64): u64 { - Mul<u64>(x, y) - } -} // end 0x42::Test - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/nested_lambda.move:5:9 - │ -5 │ f(x, y) - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/nested_lambda.move:9:15 │ 9 │ apply(|x, y| x + y, 1, apply(|x, y| x * y, 2, 1)) │ ^^^^^^^^^^^^ -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/nested_lambda.move:9:38 │ 9 │ apply(|x, y| x + y, 1, apply(|x, y| x * y, 2, 1)) diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda_module.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda_module.lambda.exp index f5ed4cea4f283..7b08cadad410f 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda_module.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/nested_lambda_module.lambda.exp @@ -152,81 +152,15 @@ module 0x42::Test { } // end 0x42::Test -// -- Model dump after env processor lambda-lifting: -module 0x42::Test1 { - public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { - (f)(x, y) - } -} // end 0x42::Test1 -module 0x42::Test { - use 0x42::Test1; // resolved as: 0x42::Test1 - public fun test(): u64 { - Test1::apply(closure Test::test$lambda$1(), 1, Test1::apply(closure Test::test$lambda$2(), 2, 1)) - } - private fun test$lambda$1(x: u64,y: u64): u64 { - Add<u64>(x, y) - } - private fun test$lambda$2(x: u64,y: u64): u64 { - Mul<u64>(x, y) - } -} // end 0x42::Test - - -// -- Model dump after env processor specification checker: -module 0x42::Test1 { - public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { - (f)(x, y) - } -} // end 0x42::Test1 -module 0x42::Test { - use 0x42::Test1; // resolved as: 0x42::Test1 - public fun test(): u64 { - Test1::apply(closure Test::test$lambda$1(), 1, Test1::apply(closure Test::test$lambda$2(), 2, 1)) - } - private fun test$lambda$1(x: u64,y: u64): u64 { - Add<u64>(x, y) - } - private fun test$lambda$2(x: u64,y: u64): u64 { - Mul<u64>(x, y) - } -} // end 0x42::Test - - -// -- Model dump after env processor specification rewriter: -module 0x42::Test1 { - public fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { - (f)(x, y) - } -} // end 0x42::Test1 -module 0x42::Test { - use 0x42::Test1; // resolved as: 0x42::Test1 - public fun test(): u64 { - Test1::apply(closure Test::test$lambda$1(), 1, Test1::apply(closure Test::test$lambda$2(), 2, 1)) - } - private fun test$lambda$1(x: u64,y: u64): u64 { - Add<u64>(x, y) - } - private fun test$lambda$2(x: u64,y: u64): u64 { - Mul<u64>(x, y) - } -} // end 0x42::Test - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/nested_lambda_module.move:4:9 - │ -4 │ f(x, y) - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/nested_lambda_module.move:13:22 │ 13 │ Test1::apply(|x, y| x + y, 1, Test1::apply(|x, y| x * y, 2, 1)) │ ^^^^^^^^^^^^ -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/nested_lambda_module.move:13:52 │ 13 │ Test1::apply(|x, y| x + y, 1, Test1::apply(|x, y| x * y, 2, 1)) diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/non_lambda_arg.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/non_lambda_arg.lambda.exp index 1095994a02a62..2f733050cb6bd 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/non_lambda_arg.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/non_lambda_arg.lambda.exp @@ -404,13 +404,3 @@ error: local `a_less_b` of type `|(T, T)|bool` does not have the `copy` ability │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ copy needed here because value is still in use 13 │ incorrect_sort_recursive(arr, pi + 1, high, a_less_b); │ ----------------------------------------------------- used here - -error: local `a_less_b` of type `|(T, T)|bool` does not have the `drop` ability - ┌─ tests/lambda/inline-parity/non_lambda_arg.move:10:9 - │ -10 │ ╭ if (low < high) { -11 │ │ let pi = low + high / 2; -12 │ │ incorrect_sort_recursive(arr, low, pi - 1, a_less_b); -13 │ │ incorrect_sort_recursive(arr, pi + 1, high, a_less_b); -14 │ │ }; - │ ╰─────────^ implicitly dropped here since it is no longer used diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/op_with_side_effect_49.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/op_with_side_effect_49.lambda.exp index a9a1dc063d69f..21ea4435d9a91 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/op_with_side_effect_49.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/op_with_side_effect_49.lambda.exp @@ -176,14 +176,14 @@ module 0xc0ffee::m { Diagnostics: -error: captured variable `x` cannot be modified inside of a lambda - ┌─ tests/lambda/inline-parity/op_with_side_effect_49.move:9:22 +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/op_with_side_effect_49.move:9:18 │ 9 │ x + call(|| {x = x + 1; x}) + call(|| {x = x + 7; x}) - │ ^ + │ ^^^^^^^^^^^^^^^^^ -error: captured variable `x` cannot be modified inside of a lambda - ┌─ tests/lambda/inline-parity/op_with_side_effect_49.move:9:48 +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/op_with_side_effect_49.move:9:44 │ 9 │ x + call(|| {x = x + 1; x}) + call(|| {x = x + 7; x}) - │ ^ + │ ^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/options.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/options.lambda.exp index 01a7a59635ddc..a0a20d5e7701d 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/options.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/options.lambda.exp @@ -284,102 +284,9 @@ module 0x42::Test { } // end 0x42::Test -// -- Model dump after env processor lambda-lifting: -module 0x42::map_opt { - use std::option; - public fun map<Element,OtherElement>(t: 0x1::option::Option<Element>,f: |Element|OtherElement): 0x1::option::Option<OtherElement> { - if option::is_some<Element>(Borrow(Immutable)(t)) { - option::some<OtherElement>((f)(option::extract<Element>(Borrow(Mutable)(t)))) - } else { - option::none<OtherElement>() - } - } -} // end 0x42::map_opt -module 0x42::Test { - use std::option; - use 0x42::map_opt; // resolved as: 0x42::map_opt - public fun test(): u64 { - { - let t: 0x1::option::Option<u64> = option::some<u64>(1); - { - let x: 0x1::option::Option<u64> = map_opt::map<u64, u64>(t, closure Test::test$lambda$1()); - option::extract<u64>(Borrow(Mutable)(x)) - } - } - } - private fun test$lambda$1(e: u64): u64 { - Add<u64>(e, 1) - } -} // end 0x42::Test - - -// -- Model dump after env processor specification checker: -module 0x42::map_opt { - use std::option; - public fun map<Element,OtherElement>(t: 0x1::option::Option<Element>,f: |Element|OtherElement): 0x1::option::Option<OtherElement> { - if option::is_some<Element>(Borrow(Immutable)(t)) { - option::some<OtherElement>((f)(option::extract<Element>(Borrow(Mutable)(t)))) - } else { - option::none<OtherElement>() - } - } -} // end 0x42::map_opt -module 0x42::Test { - use std::option; - use 0x42::map_opt; // resolved as: 0x42::map_opt - public fun test(): u64 { - { - let t: 0x1::option::Option<u64> = option::some<u64>(1); - { - let x: 0x1::option::Option<u64> = map_opt::map<u64, u64>(t, closure Test::test$lambda$1()); - option::extract<u64>(Borrow(Mutable)(x)) - } - } - } - private fun test$lambda$1(e: u64): u64 { - Add<u64>(e, 1) - } -} // end 0x42::Test - - -// -- Model dump after env processor specification rewriter: -module 0x42::map_opt { - use std::option; - public fun map<Element,OtherElement>(t: 0x1::option::Option<Element>,f: |Element|OtherElement): 0x1::option::Option<OtherElement> { - if option::is_some<Element>(Borrow(Immutable)(t)) { - option::some<OtherElement>((f)(option::extract<Element>(Borrow(Mutable)(t)))) - } else { - option::none<OtherElement>() - } - } -} // end 0x42::map_opt -module 0x42::Test { - use std::option; - use 0x42::map_opt; // resolved as: 0x42::map_opt - public fun test(): u64 { - { - let t: 0x1::option::Option<u64> = option::some<u64>(1); - { - let x: 0x1::option::Option<u64> = map_opt::map<u64, u64>(t, closure Test::test$lambda$1()); - option::extract<u64>(Borrow(Mutable)(x)) - } - } - } - private fun test$lambda$1(e: u64): u64 { - Add<u64>(e, 1) - } -} // end 0x42::Test - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/options.move:7:26 - │ -7 │ option::some(f(option::extract(&mut t))) - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/options.move:22:33 │ 22 │ let x = map_opt::map(t, |e| e + 1); diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda.lambda.exp index bf94c6a9de653..15cec56dd1a58 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/return_in_lambda.lambda.exp @@ -152,66 +152,9 @@ module 0x42::Test { } // end 0x42::Test -// -- Model dump after env processor lambda-lifting: -module 0x42::Test { - private fun adder(x: u64,y: u64): u64 { - Add<u64>(x, y) - } - private fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { - (f)(x, y) - } - public fun main(): u64 { - Test::apply(closure Test::main$lambda$1(), 10, 100) - } - private fun main$lambda$1(x: u64,y: u64): u64 { - return Test::adder(x, y) - } -} // end 0x42::Test - - -// -- Model dump after env processor specification checker: -module 0x42::Test { - private fun adder(x: u64,y: u64): u64 { - Add<u64>(x, y) - } - private fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { - (f)(x, y) - } - public fun main(): u64 { - Test::apply(closure Test::main$lambda$1(), 10, 100) - } - private fun main$lambda$1(x: u64,y: u64): u64 { - return Test::adder(x, y) - } -} // end 0x42::Test - - -// -- Model dump after env processor specification rewriter: -module 0x42::Test { - private fun adder(x: u64,y: u64): u64 { - Add<u64>(x, y) - } - private fun apply(f: |(u64, u64)|u64,x: u64,y: u64): u64 { - (f)(x, y) - } - public fun main(): u64 { - Test::apply(closure Test::main$lambda$1(), 10, 100) - } - private fun main$lambda$1(x: u64,y: u64): u64 { - return Test::adder(x, y) - } -} // end 0x42::Test - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/return_in_lambda.move:4:9 - │ -4 │ f(x, y) - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/return_in_lambda.move:12:15 │ 12 │ apply(|x, y| { diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/same_names.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/same_names.lambda.exp index c473f81866042..5037745a0d988 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/same_names.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/same_names.lambda.exp @@ -361,123 +361,9 @@ module 0x42::c { } // end 0x42::c -// -- Model dump after env processor lambda-lifting: -module 0x42::b { - struct MyOtherList { - len: u64, - } - public fun len(self: &MyOtherList): u64 { - select b::MyOtherList.len<&MyOtherList>(self) - } -} // end 0x42::b -module 0x42::a { - struct MyList { - len: u64, - } - public fun len(self: &MyList): u64 { - select a::MyList.len<&MyList>(self) - } -} // end 0x42::a -module 0x42::c { - use 0x42::a; // resolved as: 0x42::a - use 0x42::b; // resolved as: 0x42::b - private fun foo(f: |(a::MyList, b::MyOtherList)|,x: a::MyList,y: b::MyOtherList) { - (f)(x, y) - } - private fun test(x: a::MyList,y: b::MyOtherList) { - c::foo(closure c::test$lambda$1(), x, y) - } - private fun test$lambda$1(x: a::MyList,y: b::MyOtherList) { - if Eq<u64>(Add<u64>(a::len(Borrow(Immutable)(x)), b::len(Borrow(Immutable)(y))), 1) { - Tuple() - } else { - Abort(1) - } - } -} // end 0x42::c - - -// -- Model dump after env processor specification checker: -module 0x42::b { - struct MyOtherList { - len: u64, - } - public fun len(self: &MyOtherList): u64 { - select b::MyOtherList.len<&MyOtherList>(self) - } -} // end 0x42::b -module 0x42::a { - struct MyList { - len: u64, - } - public fun len(self: &MyList): u64 { - select a::MyList.len<&MyList>(self) - } -} // end 0x42::a -module 0x42::c { - use 0x42::a; // resolved as: 0x42::a - use 0x42::b; // resolved as: 0x42::b - private fun foo(f: |(a::MyList, b::MyOtherList)|,x: a::MyList,y: b::MyOtherList) { - (f)(x, y) - } - private fun test(x: a::MyList,y: b::MyOtherList) { - c::foo(closure c::test$lambda$1(), x, y) - } - private fun test$lambda$1(x: a::MyList,y: b::MyOtherList) { - if Eq<u64>(Add<u64>(a::len(Borrow(Immutable)(x)), b::len(Borrow(Immutable)(y))), 1) { - Tuple() - } else { - Abort(1) - } - } -} // end 0x42::c - - -// -- Model dump after env processor specification rewriter: -module 0x42::b { - struct MyOtherList { - len: u64, - } - public fun len(self: &MyOtherList): u64 { - select b::MyOtherList.len<&MyOtherList>(self) - } -} // end 0x42::b -module 0x42::a { - struct MyList { - len: u64, - } - public fun len(self: &MyList): u64 { - select a::MyList.len<&MyList>(self) - } -} // end 0x42::a -module 0x42::c { - use 0x42::a; // resolved as: 0x42::a - use 0x42::b; // resolved as: 0x42::b - private fun foo(f: |(a::MyList, b::MyOtherList)|,x: a::MyList,y: b::MyOtherList) { - (f)(x, y) - } - private fun test(x: a::MyList,y: b::MyOtherList) { - c::foo(closure c::test$lambda$1(), x, y) - } - private fun test$lambda$1(x: a::MyList,y: b::MyOtherList) { - if Eq<u64>(Add<u64>(a::len(Borrow(Immutable)(x)), b::len(Borrow(Immutable)(y))), 1) { - Tuple() - } else { - Abort(1) - } - } -} // end 0x42::c - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/same_names.move:24:9 - │ -24 │ f(x, y) - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/same_names.move:30:13 │ 30 │ foo(|x, y| { assert!(x.len() + y.len() == 1, 1) }, x, y) diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing.lambda.exp index 813306a5f3a94..6220c5ae1c85e 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing.lambda.exp @@ -250,8 +250,12 @@ module 0x42::Test { Diagnostics: -error: captured variable `_x` cannot be modified inside of a lambda - ┌─ tests/lambda/inline-parity/shadowing.move:12:13 +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/shadowing.move:11:13 │ -12 │ _x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would - │ ^^ +11 │ foo(|y| { + │ ╭─────────────^ +12 │ │ _x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would +13 │ │ // have the value 1. +14 │ │ }); + │ ╰─────────^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed.lambda.exp index 57fbdb400d002..80dc09bd1544b 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed.lambda.exp @@ -250,8 +250,12 @@ module 0x42::Test { Diagnostics: -error: captured variable `x` cannot be modified inside of a lambda - ┌─ tests/lambda/inline-parity/shadowing_renamed.move:12:13 +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/shadowing_renamed.move:11:13 │ -12 │ x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would - │ ^ +11 │ foo(|y| { + │ ╭─────────────^ +12 │ │ x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would +13 │ │ // have the value 1. +14 │ │ }); + │ ╰─────────^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed_param.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed_param.lambda.exp index bf8fa10008821..3b95647c560af 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed_param.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_renamed_param.lambda.exp @@ -561,26 +561,42 @@ module 0x42::Test { Diagnostics: -error: captured variable `x` cannot be modified inside of a lambda - ┌─ tests/lambda/inline-parity/shadowing_renamed_param.move:15:13 +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/shadowing_renamed_param.move:14:13 │ -15 │ x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would - │ ^ +14 │ foo(|y| { + │ ╭─────────────^ +15 │ │ x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would +16 │ │ // have the value 1. +17 │ │ }, 3); + │ ╰─────────^ -error: captured variable `x` cannot be modified inside of a lambda - ┌─ tests/lambda/inline-parity/shadowing_renamed_param.move:21:13 +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/shadowing_renamed_param.move:20:14 │ -21 │ x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would - │ ^ +20 │ foo2(|y| { + │ ╭──────────────^ +21 │ │ x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would +22 │ │ // have the value 1. +23 │ │ }, 5); + │ ╰─────────^ -error: captured variable `x` cannot be modified inside of a lambda - ┌─ tests/lambda/inline-parity/shadowing_renamed_param.move:30:13 +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/shadowing_renamed_param.move:29:13 │ -30 │ x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would - │ ^ +29 │ foo(|y| { + │ ╭─────────────^ +30 │ │ x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would +31 │ │ // have the value 1. +32 │ │ }, 3); + │ ╰─────────^ -error: captured variable `x` cannot be modified inside of a lambda - ┌─ tests/lambda/inline-parity/shadowing_renamed_param.move:36:13 +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/shadowing_renamed_param.move:35:14 │ -36 │ x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would - │ ^ +35 │ foo2(|y| { + │ ╭──────────────^ +36 │ │ x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would +37 │ │ // have the value 1. +38 │ │ }, 5); + │ ╰─────────^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused.lambda.exp index 7c4b85b3b4291..227fec78406e9 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused.lambda.exp @@ -505,14 +505,28 @@ module 0x42::Test { Diagnostics: -error: captured variable `_x` cannot be modified inside of a lambda - ┌─ tests/lambda/inline-parity/shadowing_unused.move:18:13 +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/shadowing_unused.move:11:14 │ -18 │ _x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would - │ ^^ +11 │ quux(|a, b| f(a, b), z); + │ ^^^^^^^^^^^^^^ -error: captured variable `_x` cannot be modified inside of a lambda - ┌─ tests/lambda/inline-parity/shadowing_unused.move:28:13 +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/shadowing_unused.move:17:13 │ -28 │ _x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would - │ ^^ +17 │ foo(|y, _q| { + │ ╭─────────────^ +18 │ │ _x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would +19 │ │ // have the value 1. +20 │ │ }, z); + │ ╰─────────^ + +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/shadowing_unused.move:27:14 + │ +27 │ quux(|y, _q| { + │ ╭──────────────^ +28 │ │ _x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would +29 │ │ // have the value 1. +30 │ │ }, z); + │ ╰─────────^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused_nodecl.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused_nodecl.lambda.exp index ccbae64fbd2f7..e2abb7639d5de 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused_nodecl.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/shadowing_unused_nodecl.lambda.exp @@ -511,14 +511,28 @@ warning: Unused parameter `z`. Consider removing or prefixing with an underscore 6 │ public fun quux(f:|u64, u64|, z: u64) { │ ^ -error: captured variable `_x` cannot be modified inside of a lambda - ┌─ tests/lambda/inline-parity/shadowing_unused_nodecl.move:20:13 +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/shadowing_unused_nodecl.move:13:14 │ -20 │ _x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would - │ ^^ +13 │ quux(|a, b| f(a, b), z); + │ ^^^^^^^^^^^^^^ -error: captured variable `_x` cannot be modified inside of a lambda - ┌─ tests/lambda/inline-parity/shadowing_unused_nodecl.move:30:13 +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/shadowing_unused_nodecl.move:19:13 │ -30 │ _x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would - │ ^^ +19 │ foo(|y, _q| { + │ ╭─────────────^ +20 │ │ _x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would +21 │ │ // have the value 1. +22 │ │ }, z); + │ ╰─────────^ + +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/shadowing_unused_nodecl.move:29:14 + │ +29 │ quux(|y, _q| { + │ ╭──────────────^ +30 │ │ _x = y // We expect this to assign 3 via foo if renaming works correctly. If not it would +31 │ │ // have the value 1. +32 │ │ }, z); + │ ╰─────────^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/simple_map_keys.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/simple_map_keys.lambda.exp index 90288bcbca57e..3085fc6816985 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/simple_map_keys.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/simple_map_keys.lambda.exp @@ -682,8 +682,18 @@ module 0x42::simple_map { Diagnostics: -error: captured variable `result` cannot be modified inside of a lambda - ┌─ tests/lambda/inline-parity/simple_map_keys.move:28:55 +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/simple_map_keys.move:17:28 + │ +17 │ map_ref(&map.data, |e| { + │ ╭────────────────────────────^ +18 │ │ let e: &Element<Key, Value> = e; +19 │ │ e.key +20 │ │ }) + │ ╰─────────^ + +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/inline-parity/simple_map_keys.move:28:25 │ 28 │ for_each_ref(v, |elem| vector::push_back(&mut result, f(elem))); - │ ^^^^^^ + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/spec_inlining.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/spec_inlining.lambda.exp index 82da96e292c71..53b72c72daafa 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/spec_inlining.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/spec_inlining.lambda.exp @@ -427,156 +427,15 @@ module 0x42::Test { } // end 0x42::Test -// -- Model dump after env processor lambda-lifting: -module 0x42::Test { - private fun apply(v: u64,predicate: |u64|bool): bool { - spec { - assert Ge($t0, 0); - } - ; - (predicate)(v) - } - public fun test_apply(x: u64) { - { - let r1: bool = Test::apply(x, closure Test::test_apply$lambda$1()); - spec { - assert r1; - } - ; - if r1 { - Tuple() - } else { - Abort(1) - }; - { - let r2: bool = Test::apply(x, closure Test::test_apply$lambda$2()); - spec { - assert r2; - } - ; - if r2 { - Tuple() - } else { - Abort(2) - }; - Tuple() - } - } - } - private fun test_apply$lambda$1(v: u64): bool { - Ge<u64>(v, 0) - } - private fun test_apply$lambda$2(v: u64): bool { - Neq<u64>(v, 0) - } -} // end 0x42::Test - - -// -- Model dump after env processor specification checker: -module 0x42::Test { - private fun apply(v: u64,predicate: |u64|bool): bool { - spec { - assert Ge($t0, 0); - } - ; - (predicate)(v) - } - public fun test_apply(x: u64) { - { - let r1: bool = Test::apply(x, closure Test::test_apply$lambda$1()); - spec { - assert r1; - } - ; - if r1 { - Tuple() - } else { - Abort(1) - }; - { - let r2: bool = Test::apply(x, closure Test::test_apply$lambda$2()); - spec { - assert r2; - } - ; - if r2 { - Tuple() - } else { - Abort(2) - }; - Tuple() - } - } - } - private fun test_apply$lambda$1(v: u64): bool { - Ge<u64>(v, 0) - } - private fun test_apply$lambda$2(v: u64): bool { - Neq<u64>(v, 0) - } -} // end 0x42::Test - - -// -- Model dump after env processor specification rewriter: -module 0x42::Test { - private fun apply(v: u64,predicate: |u64|bool): bool { - spec { - assert Ge($t0, 0); - } - ; - (predicate)(v) - } - public fun test_apply(x: u64) { - { - let r1: bool = Test::apply(x, closure Test::test_apply$lambda$1()); - spec { - assert r1; - } - ; - if r1 { - Tuple() - } else { - Abort(1) - }; - { - let r2: bool = Test::apply(x, closure Test::test_apply$lambda$2()); - spec { - assert r2; - } - ; - if r2 { - Tuple() - } else { - Abort(2) - }; - Tuple() - } - } - } - private fun test_apply$lambda$1(v: u64): bool { - Ge<u64>(v, 0) - } - private fun test_apply$lambda$2(v: u64): bool { - Neq<u64>(v, 0) - } -} // end 0x42::Test - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/spec_inlining.move:6:9 - │ -6 │ predicate(v) - │ ^^^^^^^^^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/spec_inlining.move:10:27 │ 10 │ let r1 = apply(x, |v| v >= 0); │ ^^^^^^^^^^ -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/spec_inlining.move:16:27 │ 16 │ let r2 = apply(x, |v| v != 0); diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args.lambda.exp index 51316f7cd9c17..13fdcad48d3be 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/subtype_args.lambda.exp @@ -536,10 +536,10 @@ error: Calls to function values other than inline function parameters not yet su ┌─ tests/lambda/inline-parity/subtype_args.move:24:9 │ 24 │ f(&mut 0, &mut 0); - │ ^ + │ ^^^^^^^^^^^^^^^^^ error: Calls to function values other than inline function parameters not yet supported ┌─ tests/lambda/inline-parity/subtype_args.move:25:9 │ 25 │ f(&0, &mut 0); - │ ^ + │ ^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unnecessary_numerical_extreme_comparisons_warn.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unnecessary_numerical_extreme_comparisons_warn.lambda.exp index 2506246844937..57b8fafd070d9 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unnecessary_numerical_extreme_comparisons_warn.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unnecessary_numerical_extreme_comparisons_warn.lambda.exp @@ -1395,405 +1395,9 @@ module 0xc0ffee::no_warn { } // end 0xc0ffee::no_warn -// -- Model dump after env processor lambda-lifting: -module 0xc0ffee::m { - private fun apply(f: |u8|bool,x: u8): bool { - (f)(x) - } - private fun bar() { - Tuple() - } - private fun foo<T>(x: T): T { - x - } - public fun test1(x: u8) { - if Gt<u8>(Add<u8>(x, 1), 255) { - m::bar() - } else { - Tuple() - }; - Tuple() - } - public fun test2(x: &u8,y: &u8) { - if Eq<bool>(Gt<u8>(Add<u8>(Deref(x), Deref(y)), 255), true) { - m::bar() - } else { - Tuple() - }; - Tuple() - } - public fun test3(x: u8) { - if Or(Lt<u8>(x, 0), Gt<u8>(0, x)) { - m::bar() - } else { - Tuple() - }; - if Le<u8>(m::foo<u8>(x), 0) { - m::bar() - } else { - Tuple() - }; - if Ge<u8>(0, m::foo<u8>(x)) { - m::bar() - } else { - Tuple() - }; - if Gt<u8>(m::foo<u8>(x), 0) { - m::bar() - } else { - Tuple() - }; - if Lt<u8>(0, m::foo<u8>(x)) { - m::bar() - } else { - Tuple() - }; - if Ge<u8>(m::foo<u8>(x), 0) { - m::bar() - } else { - Tuple() - }; - if Le<u8>(0, m::foo<u8>(x)) { - m::bar() - } else { - Tuple() - }; - Tuple() - } - public fun test4(a: u8,b: u16,c: u32,d: u64,e: u128,f: u256) { - if Or(Gt<u8>(a, 255), Gt<u256>(f, 255)) { - m::bar() - } else { - Tuple() - }; - if Ge<u16>(b, 65535) { - m::bar() - } else { - Tuple() - }; - if Lt<u32>(4294967295, c) { - m::bar() - } else { - Tuple() - }; - if Le<u64>(18446744073709551615, d) { - m::bar() - } else { - Tuple() - }; - if Lt<u128>(e, 340282366920938463463374607431768211455) { - m::bar() - } else { - Tuple() - }; - if Le<u256>(f, 115792089237316195423570985008687907853269984665640564039457584007913129639935) { - m::bar() - } else { - Tuple() - }; - if Ge<u256>(115792089237316195423570985008687907853269984665640564039457584007913129639935, f) { - m::bar() - } else { - Tuple() - }; - if Gt<u128>(340282366920938463463374607431768211455, e) { - m::bar() - } else { - Tuple() - }; - spec { - assert Le($t0, 255); - } - - } - public fun test5(x: u8): bool { - m::apply(closure m::test5$lambda$1(), x) - } - private fun test5$lambda$1(x: u8): bool { - Gt<u8>(x, 255) - } -} // end 0xc0ffee::m -module 0xc0ffee::no_warn { - public fun test(x: u8) { - if Lt<u8>(x, 0) { - Abort(1) - } else { - Tuple() - }; - Tuple() - } -} // end 0xc0ffee::no_warn - - -// -- Model dump after env processor specification checker: -module 0xc0ffee::m { - private fun apply(f: |u8|bool,x: u8): bool { - (f)(x) - } - private fun bar() { - Tuple() - } - private fun foo<T>(x: T): T { - x - } - public fun test1(x: u8) { - if Gt<u8>(Add<u8>(x, 1), 255) { - m::bar() - } else { - Tuple() - }; - Tuple() - } - public fun test2(x: &u8,y: &u8) { - if Eq<bool>(Gt<u8>(Add<u8>(Deref(x), Deref(y)), 255), true) { - m::bar() - } else { - Tuple() - }; - Tuple() - } - public fun test3(x: u8) { - if Or(Lt<u8>(x, 0), Gt<u8>(0, x)) { - m::bar() - } else { - Tuple() - }; - if Le<u8>(m::foo<u8>(x), 0) { - m::bar() - } else { - Tuple() - }; - if Ge<u8>(0, m::foo<u8>(x)) { - m::bar() - } else { - Tuple() - }; - if Gt<u8>(m::foo<u8>(x), 0) { - m::bar() - } else { - Tuple() - }; - if Lt<u8>(0, m::foo<u8>(x)) { - m::bar() - } else { - Tuple() - }; - if Ge<u8>(m::foo<u8>(x), 0) { - m::bar() - } else { - Tuple() - }; - if Le<u8>(0, m::foo<u8>(x)) { - m::bar() - } else { - Tuple() - }; - Tuple() - } - public fun test4(a: u8,b: u16,c: u32,d: u64,e: u128,f: u256) { - if Or(Gt<u8>(a, 255), Gt<u256>(f, 255)) { - m::bar() - } else { - Tuple() - }; - if Ge<u16>(b, 65535) { - m::bar() - } else { - Tuple() - }; - if Lt<u32>(4294967295, c) { - m::bar() - } else { - Tuple() - }; - if Le<u64>(18446744073709551615, d) { - m::bar() - } else { - Tuple() - }; - if Lt<u128>(e, 340282366920938463463374607431768211455) { - m::bar() - } else { - Tuple() - }; - if Le<u256>(f, 115792089237316195423570985008687907853269984665640564039457584007913129639935) { - m::bar() - } else { - Tuple() - }; - if Ge<u256>(115792089237316195423570985008687907853269984665640564039457584007913129639935, f) { - m::bar() - } else { - Tuple() - }; - if Gt<u128>(340282366920938463463374607431768211455, e) { - m::bar() - } else { - Tuple() - }; - spec { - assert Le($t0, 255); - } - - } - public fun test5(x: u8): bool { - m::apply(closure m::test5$lambda$1(), x) - } - private fun test5$lambda$1(x: u8): bool { - Gt<u8>(x, 255) - } -} // end 0xc0ffee::m -module 0xc0ffee::no_warn { - public fun test(x: u8) { - if Lt<u8>(x, 0) { - Abort(1) - } else { - Tuple() - }; - Tuple() - } -} // end 0xc0ffee::no_warn - - -// -- Model dump after env processor specification rewriter: -module 0xc0ffee::m { - private fun apply(f: |u8|bool,x: u8): bool { - (f)(x) - } - private fun bar() { - Tuple() - } - private fun foo<T>(x: T): T { - x - } - public fun test1(x: u8) { - if Gt<u8>(Add<u8>(x, 1), 255) { - m::bar() - } else { - Tuple() - }; - Tuple() - } - public fun test2(x: &u8,y: &u8) { - if Eq<bool>(Gt<u8>(Add<u8>(Deref(x), Deref(y)), 255), true) { - m::bar() - } else { - Tuple() - }; - Tuple() - } - public fun test3(x: u8) { - if Or(Lt<u8>(x, 0), Gt<u8>(0, x)) { - m::bar() - } else { - Tuple() - }; - if Le<u8>(m::foo<u8>(x), 0) { - m::bar() - } else { - Tuple() - }; - if Ge<u8>(0, m::foo<u8>(x)) { - m::bar() - } else { - Tuple() - }; - if Gt<u8>(m::foo<u8>(x), 0) { - m::bar() - } else { - Tuple() - }; - if Lt<u8>(0, m::foo<u8>(x)) { - m::bar() - } else { - Tuple() - }; - if Ge<u8>(m::foo<u8>(x), 0) { - m::bar() - } else { - Tuple() - }; - if Le<u8>(0, m::foo<u8>(x)) { - m::bar() - } else { - Tuple() - }; - Tuple() - } - public fun test4(a: u8,b: u16,c: u32,d: u64,e: u128,f: u256) { - if Or(Gt<u8>(a, 255), Gt<u256>(f, 255)) { - m::bar() - } else { - Tuple() - }; - if Ge<u16>(b, 65535) { - m::bar() - } else { - Tuple() - }; - if Lt<u32>(4294967295, c) { - m::bar() - } else { - Tuple() - }; - if Le<u64>(18446744073709551615, d) { - m::bar() - } else { - Tuple() - }; - if Lt<u128>(e, 340282366920938463463374607431768211455) { - m::bar() - } else { - Tuple() - }; - if Le<u256>(f, 115792089237316195423570985008687907853269984665640564039457584007913129639935) { - m::bar() - } else { - Tuple() - }; - if Ge<u256>(115792089237316195423570985008687907853269984665640564039457584007913129639935, f) { - m::bar() - } else { - Tuple() - }; - if Gt<u128>(340282366920938463463374607431768211455, e) { - m::bar() - } else { - Tuple() - }; - spec { - assert Le($t0, 255); - } - - } - public fun test5(x: u8): bool { - m::apply(closure m::test5$lambda$1(), x) - } - private fun test5$lambda$1(x: u8): bool { - Gt<u8>(x, 255) - } -} // end 0xc0ffee::m -module 0xc0ffee::no_warn { - public fun test(x: u8) { - if Lt<u8>(x, 0) { - Abort(1) - } else { - Tuple() - }; - Tuple() - } -} // end 0xc0ffee::no_warn - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/unnecessary_numerical_extreme_comparisons_warn.move:50:9 - │ -50 │ f(x) - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/unnecessary_numerical_extreme_comparisons_warn.move:54:15 │ 54 │ apply(|x| x > U8_MAX, x) diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unpack_generic_struct.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unpack_generic_struct.lambda.exp index 2bdecc21d6698..ccb4d76ab98ae 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unpack_generic_struct.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unpack_generic_struct.lambda.exp @@ -504,177 +504,9 @@ module 0x42::m { } // end 0x42::m -// -- Model dump after env processor lambda-lifting: -module 0x42::m { - use std::vector; - struct E<Key> { - key: Key, - } - struct Option<Element> { - vec: vector<Element>, - } - public fun destroy_none<Element>(t: Option<Element>) { - if m::is_none<Element>(Borrow(Immutable)(t)) { - Tuple() - } else { - Abort(262144) - }; - { - let m::Option<Element>{ vec } = t; - vector::destroy_empty<Element>(vec) - } - } - public fun foo<Key>(data: E<Key>,v: &mut Key) { - { - let f: E<Key> = m::h<Key>(data, closure m::foo$lambda$1()); - m::g<Key>(f, closure m::foo$lambda$2(v)); - Tuple() - } - } - public fun g<Key>(x: E<Key>,v: |E<Key>|) { - (v)(x) - } - public fun h<Key>(x: E<Key>,v: |Key|E<Key>): E<Key> { - { - let m::E<Key>{ key } = x; - (v)(key) - } - } - public fun is_none<Element>(t: &Option<Element>): bool { - vector::is_empty<Element>(Borrow(Immutable)(select m::Option.vec<&Option<Element>>(t))) - } - private fun foo$lambda$1<Key>(e: Key): E<Key> { - pack m::E<Key>(e) - } - private fun foo$lambda$2<Key>(v: &mut Key,e: E<Key>) { - { - let (m::E<Key>{ key }, _x: u64): (E<Key>, u64) = Tuple(e, 3); - v = key; - Tuple() - } - } -} // end 0x42::m - - -// -- Model dump after env processor specification checker: -module 0x42::m { - use std::vector; - struct E<Key> { - key: Key, - } - struct Option<Element> { - vec: vector<Element>, - } - public fun destroy_none<Element>(t: Option<Element>) { - if m::is_none<Element>(Borrow(Immutable)(t)) { - Tuple() - } else { - Abort(262144) - }; - { - let m::Option<Element>{ vec } = t; - vector::destroy_empty<Element>(vec) - } - } - public fun foo<Key>(data: E<Key>,v: &mut Key) { - { - let f: E<Key> = m::h<Key>(data, closure m::foo$lambda$1()); - m::g<Key>(f, closure m::foo$lambda$2(v)); - Tuple() - } - } - public fun g<Key>(x: E<Key>,v: |E<Key>|) { - (v)(x) - } - public fun h<Key>(x: E<Key>,v: |Key|E<Key>): E<Key> { - { - let m::E<Key>{ key } = x; - (v)(key) - } - } - public fun is_none<Element>(t: &Option<Element>): bool { - vector::is_empty<Element>(Borrow(Immutable)(select m::Option.vec<&Option<Element>>(t))) - } - private fun foo$lambda$1<Key>(e: Key): E<Key> { - pack m::E<Key>(e) - } - private fun foo$lambda$2<Key>(v: &mut Key,e: E<Key>) { - { - let (m::E<Key>{ key }, _x: u64): (E<Key>, u64) = Tuple(e, 3); - v = key; - Tuple() - } - } -} // end 0x42::m - - -// -- Model dump after env processor specification rewriter: -module 0x42::m { - use std::vector; - struct E<Key> { - key: Key, - } - struct Option<Element> { - vec: vector<Element>, - } - public fun destroy_none<Element>(t: Option<Element>) { - if m::is_none<Element>(Borrow(Immutable)(t)) { - Tuple() - } else { - Abort(262144) - }; - { - let m::Option<Element>{ vec } = t; - vector::destroy_empty<Element>(vec) - } - } - public fun foo<Key>(data: E<Key>,v: &mut Key) { - { - let f: E<Key> = m::h<Key>(data, closure m::foo$lambda$1()); - m::g<Key>(f, closure m::foo$lambda$2(v)); - Tuple() - } - } - public fun g<Key>(x: E<Key>,v: |E<Key>|) { - (v)(x) - } - public fun h<Key>(x: E<Key>,v: |Key|E<Key>): E<Key> { - { - let m::E<Key>{ key } = x; - (v)(key) - } - } - public fun is_none<Element>(t: &Option<Element>): bool { - vector::is_empty<Element>(Borrow(Immutable)(select m::Option.vec<&Option<Element>>(t))) - } - private fun foo$lambda$1<Key>(e: Key): E<Key> { - pack m::E<Key>(e) - } - private fun foo$lambda$2<Key>(v: &mut Key,e: E<Key>) { - { - let (m::E<Key>{ key }, _x: u64): (E<Key>, u64) = Tuple(e, 3); - v = key; - Tuple() - } - } -} // end 0x42::m - - Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/unpack_generic_struct.move:24:9 - │ -24 │ v(key) - │ ^ - -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/unpack_generic_struct.move:28:9 - │ -28 │ v(x) - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/unpack_generic_struct.move:33:25 │ 33 │ let f = h(data, |e| { @@ -683,7 +515,7 @@ error: Function-typed values not yet supported except as parameters to calls to 35 │ │ }); │ ╰─────────^ -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/unpack_generic_struct.move:36:14 │ 36 │ g(f, |e| { diff --git a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unused_lambda_param.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unused_lambda_param.lambda.exp index a720df7124c63..5843e39307da4 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unused_lambda_param.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/inline-parity/unused_lambda_param.lambda.exp @@ -218,102 +218,6 @@ module 0xc0ffee::m { } // end 0xc0ffee::m -// -- Model dump after env processor lambda-lifting: -module 0xc0ffee::m { - private fun test(p: u64,f: |u64|u64): u64 { - (f)(p) - } - private fun unused_lambda() { - m::test(0, closure m::unused_lambda$lambda$1()); - Tuple() - } - private fun unused_lambda_suppressed1() { - m::test(0, closure m::unused_lambda_suppressed1$lambda$1()); - Tuple() - } - private fun unused_lambda_suppressed2() { - m::test(0, closure m::unused_lambda_suppressed2$lambda$1()); - Tuple() - } - private fun unused_lambda$lambda$1(x: u64): u64 { - 1 - } - private fun unused_lambda_suppressed1$lambda$1(_x: u64): u64 { - 1 - } - private fun unused_lambda_suppressed2$lambda$1(param$0: u64): u64 { - { - let _: u64 = param$0; - 1 - } - } -} // end 0xc0ffee::m - - -// -- Model dump after env processor specification checker: -module 0xc0ffee::m { - private fun test(p: u64,f: |u64|u64): u64 { - (f)(p) - } - private fun unused_lambda() { - m::test(0, closure m::unused_lambda$lambda$1()); - Tuple() - } - private fun unused_lambda_suppressed1() { - m::test(0, closure m::unused_lambda_suppressed1$lambda$1()); - Tuple() - } - private fun unused_lambda_suppressed2() { - m::test(0, closure m::unused_lambda_suppressed2$lambda$1()); - Tuple() - } - private fun unused_lambda$lambda$1(x: u64): u64 { - 1 - } - private fun unused_lambda_suppressed1$lambda$1(_x: u64): u64 { - 1 - } - private fun unused_lambda_suppressed2$lambda$1(param$0: u64): u64 { - { - let _: u64 = param$0; - 1 - } - } -} // end 0xc0ffee::m - - -// -- Model dump after env processor specification rewriter: -module 0xc0ffee::m { - private fun test(p: u64,f: |u64|u64): u64 { - (f)(p) - } - private fun unused_lambda() { - m::test(0, closure m::unused_lambda$lambda$1()); - Tuple() - } - private fun unused_lambda_suppressed1() { - m::test(0, closure m::unused_lambda_suppressed1$lambda$1()); - Tuple() - } - private fun unused_lambda_suppressed2() { - m::test(0, closure m::unused_lambda_suppressed2$lambda$1()); - Tuple() - } - private fun unused_lambda$lambda$1(x: u64): u64 { - 1 - } - private fun unused_lambda_suppressed1$lambda$1(_x: u64): u64 { - 1 - } - private fun unused_lambda_suppressed2$lambda$1(param$0: u64): u64 { - { - let _: u64 = param$0; - 1 - } - } -} // end 0xc0ffee::m - - Diagnostics: warning: Unused anonymous function parameter `x`. Consider removing or prefixing with an underscore: `_x` @@ -322,27 +226,19 @@ warning: Unused anonymous function parameter `x`. Consider removing or prefixing 7 │ test(0, |x| 1); │ ^ - -Diagnostics: -error: Calls to function values other than inline function parameters not yet supported - ┌─ tests/lambda/inline-parity/unused_lambda_param.move:3:9 - │ -3 │ f(p) - │ ^ - -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/unused_lambda_param.move:7:17 │ 7 │ test(0, |x| 1); │ ^^^^^ -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/unused_lambda_param.move:11:17 │ 11 │ test(0, |_x| 1); │ ^^^^^^ -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/inline-parity/unused_lambda_param.move:15:17 │ 15 │ test(0, |_| 1); diff --git a/third_party/move/move-compiler-v2/tests/lambda/lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/lambda.exp index 4f17028adb675..7328ae7924537 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/lambda.exp @@ -24,7 +24,7 @@ error: cannot use `()` with an operator which expects a value of type `u64` 56 │ i = i + action(XVector::borrow(v, i)); // expected to have wrong result type │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: cannot return `u64` from a function with result type `|integer|` +error: cannot return `u64` from a function with result type `|integer| with copy+store` ┌─ tests/lambda/lambda.move:61:9 │ 61 │ x(1) // expected to be not a function diff --git a/third_party/move/move-compiler-v2/tests/lambda/lambda.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/lambda.lambda.exp index 4f17028adb675..7328ae7924537 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/lambda.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/lambda.lambda.exp @@ -24,7 +24,7 @@ error: cannot use `()` with an operator which expects a value of type `u64` 56 │ i = i + action(XVector::borrow(v, i)); // expected to have wrong result type │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: cannot return `u64` from a function with result type `|integer|` +error: cannot return `u64` from a function with result type `|integer| with copy+store` ┌─ tests/lambda/lambda.move:61:9 │ 61 │ x(1) // expected to be not a function diff --git a/third_party/move/move-compiler-v2/tests/lambda/lambda3.exp b/third_party/move/move-compiler-v2/tests/lambda/lambda3.exp index b7104b3811ed1..9eb746fa166b1 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/lambda3.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/lambda3.exp @@ -2,7 +2,7 @@ module 0x8675309::M { public fun lambda_not_allowed() { { - let _x: |u64|u64 = |i: u64| Add<u64>(i, 1); + let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1); Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/lambda/lambda3.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/lambda3.lambda.exp index db9ce1b64dc58..cca732666e1ef 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/lambda3.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/lambda3.lambda.exp @@ -2,7 +2,7 @@ module 0x8675309::M { public fun lambda_not_allowed() { { - let _x: |u64|u64 = |i: u64| Add<u64>(i, 1); + let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1); Tuple() } } @@ -13,7 +13,7 @@ module 0x8675309::M { module 0x8675309::M { public fun lambda_not_allowed() { { - let _x: |u64|u64 = |i: u64| Add<u64>(i, 1); + let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1); Tuple() } } @@ -24,7 +24,7 @@ module 0x8675309::M { module 0x8675309::M { public fun lambda_not_allowed() { { - let _x: |u64|u64 = |i: u64| Add<u64>(i, 1); + let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1); Tuple() } } @@ -35,7 +35,7 @@ module 0x8675309::M { module 0x8675309::M { public fun lambda_not_allowed() { { - let _x: |u64|u64 = |i: u64| Add<u64>(i, 1); + let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1); Tuple() } } @@ -46,7 +46,7 @@ module 0x8675309::M { module 0x8675309::M { public fun lambda_not_allowed() { { - let _x: |u64|u64 = |i: u64| Add<u64>(i, 1); + let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1); Tuple() } } @@ -57,7 +57,7 @@ module 0x8675309::M { module 0x8675309::M { public fun lambda_not_allowed() { { - let _x: |u64|u64 = |i: u64| Add<u64>(i, 1); + let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1); Tuple() } } @@ -68,7 +68,7 @@ module 0x8675309::M { module 0x8675309::M { public fun lambda_not_allowed() { { - let _x: |u64|u64 = |i: u64| Add<u64>(i, 1); + let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1); Tuple() } } @@ -79,7 +79,7 @@ module 0x8675309::M { module 0x8675309::M { public fun lambda_not_allowed() { { - let _x: |u64|u64 = |i: u64| Add<u64>(i, 1); + let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1); Tuple() } } @@ -90,7 +90,7 @@ module 0x8675309::M { module 0x8675309::M { public fun lambda_not_allowed() { { - let _x: |u64|u64 = |i: u64| Add<u64>(i, 1); + let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1); Tuple() } } @@ -101,7 +101,7 @@ module 0x8675309::M { module 0x8675309::M { public fun lambda_not_allowed() { { - let _x: |u64|u64 = |i: u64| Add<u64>(i, 1); + let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1); Tuple() } } @@ -112,58 +112,16 @@ module 0x8675309::M { module 0x8675309::M { public fun lambda_not_allowed() { { - let _x: |u64|u64 = |i: u64| Add<u64>(i, 1); + let _x: |u64|u64 with copy+store = |i: u64| Add<u64>(i, 1); Tuple() } } } // end 0x8675309::M -// -- Model dump after env processor lambda-lifting: -module 0x8675309::M { - public fun lambda_not_allowed() { - { - let _x: |u64|u64 = closure M::lambda_not_allowed$lambda$1(); - Tuple() - } - } - private fun lambda_not_allowed$lambda$1(i: u64): u64 { - Add<u64>(i, 1) - } -} // end 0x8675309::M - - -// -- Model dump after env processor specification checker: -module 0x8675309::M { - public fun lambda_not_allowed() { - { - let _x: |u64|u64 = closure M::lambda_not_allowed$lambda$1(); - Tuple() - } - } - private fun lambda_not_allowed$lambda$1(i: u64): u64 { - Add<u64>(i, 1) - } -} // end 0x8675309::M - - -// -- Model dump after env processor specification rewriter: -module 0x8675309::M { - public fun lambda_not_allowed() { - { - let _x: |u64|u64 = closure M::lambda_not_allowed$lambda$1(); - Tuple() - } - } - private fun lambda_not_allowed$lambda$1(i: u64): u64 { - Add<u64>(i, 1) - } -} // end 0x8675309::M - - Diagnostics: -error: Function-typed values not yet supported except as parameters to calls to inline functions +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. ┌─ tests/lambda/lambda3.move:77:18 │ 77 │ let _x = |i| i + 1; // expected lambda not allowed diff --git a/third_party/move/move-compiler-v2/tests/lambda/non_lambda_arg.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/non_lambda_arg.lambda.exp index 0a35235798063..8949035e6a9d3 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/non_lambda_arg.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/non_lambda_arg.lambda.exp @@ -404,13 +404,3 @@ error: local `a_less_b` of type `|(T, T)|bool` does not have the `copy` ability │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ copy needed here because value is still in use 13 │ incorrect_sort_recursive(arr, pi + 1, high, a_less_b); │ ----------------------------------------------------- used here - -error: local `a_less_b` of type `|(T, T)|bool` does not have the `drop` ability - ┌─ tests/lambda/non_lambda_arg.move:10:9 - │ -10 │ ╭ if (low < high) { -11 │ │ let pi = low + high / 2; -12 │ │ incorrect_sort_recursive(arr, low, pi - 1, a_less_b); -13 │ │ incorrect_sort_recursive(arr, pi + 1, high, a_less_b); -14 │ │ }; - │ ╰─────────^ implicitly dropped here since it is no longer used diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/doable_func.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/doable_func.exp new file mode 100644 index 0000000000000..bee6d7e4e76c2 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/doable_func.exp @@ -0,0 +1,127 @@ + +Diagnostics: +error: unsupported language construct + ┌─ tests/lambda/storable/doable_func.move:43:17 + │ +43 │ move |x| mod3::multiply(4, x) + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/doable_func.move:46:17 + │ +46 │ move |y| alt_multiply(x, y) + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/doable_func.move:49:17 + │ +49 │ move |y| mod3::multiply(y, x) + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/doable_func.move:51:17 + │ +51 │ move |x| multiply3(x, 3, 2) + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/doable_func.move:53:17 + │ +53 │ move |x| mod3::multiply(x, 7) + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/doable_func.move:55:17 + │ +55 │ move |x| multiply3(4, x, 2) + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/doable_func.move:57:17 + │ +57 │ move |x| multiply3(3, 3, x) + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/doable_func.move:61:17 + │ +61 │ move |z| multiply3(x, y, z) + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/doable_func.move:64:17 + │ +64 │ move |x| alt_multiply(x, z) with copy + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/doable_func.move:64:45 + │ +64 │ move |x| alt_multiply(x, z) with copy + │ ^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions + +error: unsupported language construct + ┌─ tests/lambda/storable/doable_func.move:66:25 + │ +66 │ let g = move |x, y| mod3::multiply(x, y) with copy+drop; + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/doable_func.move:66:58 + │ +66 │ let g = move |x, y| mod3::multiply(x, y) with copy+drop; + │ ^^^^^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions + +error: unsupported language construct + ┌─ tests/lambda/storable/doable_func.move:67:17 + │ +67 │ move |x| g(x, 11) + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/doable_func.move:69:25 + │ +69 │ let h = move |x| mod3::multiply(x, 12) with copy; + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/doable_func.move:69:56 + │ +69 │ let h = move |x| mod3::multiply(x, 12) with copy; + │ ^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions + +error: unsupported language construct + ┌─ tests/lambda/storable/doable_func.move:70:17 + │ +70 │ move |x| { h(x) } with copy + drop + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/doable_func.move:70:35 + │ +70 │ move |x| { h(x) } with copy + drop + │ ^^^^^^^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions + +error: unsupported language construct + ┌─ tests/lambda/storable/doable_func.move:72:25 + │ +72 │ let i = move |x| multiply3(2, x, 2); + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/doable_func.move:73:17 + │ +73 │ move |z| i(z) + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/doable_func.move:75:25 + │ +75 │ let i = move |x, y| { let q = y - 1; 0x42::mod3::multiply(x, q + 1) }; + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/doable_func.move:76:17 + │ +76 │ move |x| i(x, 15) + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/doable_func.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/doable_func.lambda.exp new file mode 100644 index 0000000000000..e39fd4deaeb18 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/doable_func.lambda.exp @@ -0,0 +1,2465 @@ +// -- Model dump before env processor pipeline: +module 0x42::mod4 { + public fun alt_multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod4 +module 0x42::mod3 { + public fun multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod3 +module 0x42::mod2 { + friend fun double(x: u64): u64 { + Mul<u64>(x, 2) + } +} // end 0x42::mod2 +module 0x42::mod1 { + friend fun triple(x: u64): u64 { + Mul<u64>(x, 3) + } +} // end 0x42::mod1 +module 0x42::test { + use 0x42::mod1; // resolved as: 0x42::mod1 + use 0x42::mod2; // resolved as: 0x42::mod2 + use 0x42::mod3; // resolved as: 0x42::mod3 + use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4 + private fun add_mul(x: u64,y: u64,z: u64): u64 { + Mul<u64>(z, Add<u64>(x, y)) + } + private fun choose_function1(key: u64,x: u64): u64 { + { + let f: |u64|u64 with copy = if Eq<u64>(key, 0) { + mod2::double + } else { + if Eq<u64>(key, 1) { + mod1::triple + } else { + if Eq<u64>(key, 2) { + move|x: u64| mod3::multiply(4, x) + } else { + if Eq<u64>(key, 3) { + { + let x: u64 = 5; + move|y: u64| mod4::alt_multiply(x, y) + } + } else { + if Eq<u64>(key, 4) { + { + let x: u64 = 6; + move|y: u64| mod3::multiply(y, x) + } + } else { + if Eq<u64>(key, 5) { + move|x: u64| test::multiply3(x, 3, 2) + } else { + if Eq<u64>(key, 6) { + move|x: u64| mod3::multiply(x, 7) + } else { + if Eq<u64>(key, 7) { + move|x: u64| test::multiply3(4, x, 2) + } else { + if Eq<u64>(key, 8) { + move|x: u64| test::multiply3(3, 3, x) + } else { + if Eq<u64>(key, 9) { + { + let x: u64 = 2; + { + let y: u64 = 5; + move|z: u64| test::multiply3(x, y, z) + } + } + } else { + if Eq<u64>(key, 10) { + { + let z: u64 = 11; + move|x: u64| mod4::alt_multiply(x, z) with copy, drop + } + } else { + if Eq<u64>(key, 11) { + { + let g: |(u64, u64)|u64 with copy+store = move|(x: u64, y: u64): (u64, u64)| mod3::multiply(x, y) with copy, drop; + move|x: u64| (g)(x, 11) + } + } else { + if Eq<u64>(key, 12) { + { + let h: |u64|u64 with copy+store = move|x: u64| mod3::multiply(x, 12) with copy, drop; + move|x: u64| (h)(x) with copy, drop + } + } else { + if Eq<u64>(key, 14) { + { + let i: |u64|u64 with copy+store = move|x: u64| test::multiply3(2, x, 2); + move|z: u64| (i)(z) + } + } else { + { + let i: |(u64, u64)|u64 with copy+store = move|(x: u64, y: u64): (u64, u64)| { + let q: u64 = Sub<u64>(y, 1); + mod3::multiply(x, Add<u64>(q, 1)) + }; + move|x: u64| (i)(x, 15) + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }; + (f)(x) + } + } + private fun multiply3(x: u64,y: u64,z: u64): u64 { + Mul<u64>(Mul<u64>(x, y), z) + } + public fun test_functions() { + { + let x: u64 = 3; + { + let i: u64 = 0; + { + let __update_iter_flag: bool = false; + { + let __upper_bound_value: u64 = 15; + loop { + if true { + if __update_iter_flag { + i: u64 = Add<u64>(i, 1) + } else { + __update_iter_flag: bool = true + }; + if Lt<u64>(i, __upper_bound_value) { + { + let y: u64 = test::choose_function1(i, 3); + if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), x)) { + Tuple() + } else { + Abort(i) + }; + Tuple() + } + } else { + break + }; + Tuple() + } else { + break + } + }; + Tuple() + } + } + } + } + } +} // end 0x42::test + + +// -- Model dump after env processor unused checks: +module 0x42::mod4 { + public fun alt_multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod4 +module 0x42::mod3 { + public fun multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod3 +module 0x42::mod2 { + friend fun double(x: u64): u64 { + Mul<u64>(x, 2) + } +} // end 0x42::mod2 +module 0x42::mod1 { + friend fun triple(x: u64): u64 { + Mul<u64>(x, 3) + } +} // end 0x42::mod1 +module 0x42::test { + use 0x42::mod1; // resolved as: 0x42::mod1 + use 0x42::mod2; // resolved as: 0x42::mod2 + use 0x42::mod3; // resolved as: 0x42::mod3 + use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4 + private fun add_mul(x: u64,y: u64,z: u64): u64 { + Mul<u64>(z, Add<u64>(x, y)) + } + private fun choose_function1(key: u64,x: u64): u64 { + { + let f: |u64|u64 with copy = if Eq<u64>(key, 0) { + mod2::double + } else { + if Eq<u64>(key, 1) { + mod1::triple + } else { + if Eq<u64>(key, 2) { + move|x: u64| mod3::multiply(4, x) + } else { + if Eq<u64>(key, 3) { + { + let x: u64 = 5; + move|y: u64| mod4::alt_multiply(x, y) + } + } else { + if Eq<u64>(key, 4) { + { + let x: u64 = 6; + move|y: u64| mod3::multiply(y, x) + } + } else { + if Eq<u64>(key, 5) { + move|x: u64| test::multiply3(x, 3, 2) + } else { + if Eq<u64>(key, 6) { + move|x: u64| mod3::multiply(x, 7) + } else { + if Eq<u64>(key, 7) { + move|x: u64| test::multiply3(4, x, 2) + } else { + if Eq<u64>(key, 8) { + move|x: u64| test::multiply3(3, 3, x) + } else { + if Eq<u64>(key, 9) { + { + let x: u64 = 2; + { + let y: u64 = 5; + move|z: u64| test::multiply3(x, y, z) + } + } + } else { + if Eq<u64>(key, 10) { + { + let z: u64 = 11; + move|x: u64| mod4::alt_multiply(x, z) with copy, drop + } + } else { + if Eq<u64>(key, 11) { + { + let g: |(u64, u64)|u64 with copy+store = move|(x: u64, y: u64): (u64, u64)| mod3::multiply(x, y) with copy, drop; + move|x: u64| (g)(x, 11) + } + } else { + if Eq<u64>(key, 12) { + { + let h: |u64|u64 with copy+store = move|x: u64| mod3::multiply(x, 12) with copy, drop; + move|x: u64| (h)(x) with copy, drop + } + } else { + if Eq<u64>(key, 14) { + { + let i: |u64|u64 with copy+store = move|x: u64| test::multiply3(2, x, 2); + move|z: u64| (i)(z) + } + } else { + { + let i: |(u64, u64)|u64 with copy+store = move|(x: u64, y: u64): (u64, u64)| { + let q: u64 = Sub<u64>(y, 1); + mod3::multiply(x, Add<u64>(q, 1)) + }; + move|x: u64| (i)(x, 15) + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }; + (f)(x) + } + } + private fun multiply3(x: u64,y: u64,z: u64): u64 { + Mul<u64>(Mul<u64>(x, y), z) + } + public fun test_functions() { + { + let x: u64 = 3; + { + let i: u64 = 0; + { + let __update_iter_flag: bool = false; + { + let __upper_bound_value: u64 = 15; + loop { + if true { + if __update_iter_flag { + i: u64 = Add<u64>(i, 1) + } else { + __update_iter_flag: bool = true + }; + if Lt<u64>(i, __upper_bound_value) { + { + let y: u64 = test::choose_function1(i, 3); + if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), x)) { + Tuple() + } else { + Abort(i) + }; + Tuple() + } + } else { + break + }; + Tuple() + } else { + break + } + }; + Tuple() + } + } + } + } + } +} // end 0x42::test + + +// -- Model dump after env processor type parameter check: +module 0x42::mod4 { + public fun alt_multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod4 +module 0x42::mod3 { + public fun multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod3 +module 0x42::mod2 { + friend fun double(x: u64): u64 { + Mul<u64>(x, 2) + } +} // end 0x42::mod2 +module 0x42::mod1 { + friend fun triple(x: u64): u64 { + Mul<u64>(x, 3) + } +} // end 0x42::mod1 +module 0x42::test { + use 0x42::mod1; // resolved as: 0x42::mod1 + use 0x42::mod2; // resolved as: 0x42::mod2 + use 0x42::mod3; // resolved as: 0x42::mod3 + use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4 + private fun add_mul(x: u64,y: u64,z: u64): u64 { + Mul<u64>(z, Add<u64>(x, y)) + } + private fun choose_function1(key: u64,x: u64): u64 { + { + let f: |u64|u64 with copy = if Eq<u64>(key, 0) { + mod2::double + } else { + if Eq<u64>(key, 1) { + mod1::triple + } else { + if Eq<u64>(key, 2) { + move|x: u64| mod3::multiply(4, x) + } else { + if Eq<u64>(key, 3) { + { + let x: u64 = 5; + move|y: u64| mod4::alt_multiply(x, y) + } + } else { + if Eq<u64>(key, 4) { + { + let x: u64 = 6; + move|y: u64| mod3::multiply(y, x) + } + } else { + if Eq<u64>(key, 5) { + move|x: u64| test::multiply3(x, 3, 2) + } else { + if Eq<u64>(key, 6) { + move|x: u64| mod3::multiply(x, 7) + } else { + if Eq<u64>(key, 7) { + move|x: u64| test::multiply3(4, x, 2) + } else { + if Eq<u64>(key, 8) { + move|x: u64| test::multiply3(3, 3, x) + } else { + if Eq<u64>(key, 9) { + { + let x: u64 = 2; + { + let y: u64 = 5; + move|z: u64| test::multiply3(x, y, z) + } + } + } else { + if Eq<u64>(key, 10) { + { + let z: u64 = 11; + move|x: u64| mod4::alt_multiply(x, z) with copy, drop + } + } else { + if Eq<u64>(key, 11) { + { + let g: |(u64, u64)|u64 with copy+store = move|(x: u64, y: u64): (u64, u64)| mod3::multiply(x, y) with copy, drop; + move|x: u64| (g)(x, 11) + } + } else { + if Eq<u64>(key, 12) { + { + let h: |u64|u64 with copy+store = move|x: u64| mod3::multiply(x, 12) with copy, drop; + move|x: u64| (h)(x) with copy, drop + } + } else { + if Eq<u64>(key, 14) { + { + let i: |u64|u64 with copy+store = move|x: u64| test::multiply3(2, x, 2); + move|z: u64| (i)(z) + } + } else { + { + let i: |(u64, u64)|u64 with copy+store = move|(x: u64, y: u64): (u64, u64)| { + let q: u64 = Sub<u64>(y, 1); + mod3::multiply(x, Add<u64>(q, 1)) + }; + move|x: u64| (i)(x, 15) + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }; + (f)(x) + } + } + private fun multiply3(x: u64,y: u64,z: u64): u64 { + Mul<u64>(Mul<u64>(x, y), z) + } + public fun test_functions() { + { + let x: u64 = 3; + { + let i: u64 = 0; + { + let __update_iter_flag: bool = false; + { + let __upper_bound_value: u64 = 15; + loop { + if true { + if __update_iter_flag { + i: u64 = Add<u64>(i, 1) + } else { + __update_iter_flag: bool = true + }; + if Lt<u64>(i, __upper_bound_value) { + { + let y: u64 = test::choose_function1(i, 3); + if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), x)) { + Tuple() + } else { + Abort(i) + }; + Tuple() + } + } else { + break + }; + Tuple() + } else { + break + } + }; + Tuple() + } + } + } + } + } +} // end 0x42::test + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::mod4 { + public fun alt_multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod4 +module 0x42::mod3 { + public fun multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod3 +module 0x42::mod2 { + friend fun double(x: u64): u64 { + Mul<u64>(x, 2) + } +} // end 0x42::mod2 +module 0x42::mod1 { + friend fun triple(x: u64): u64 { + Mul<u64>(x, 3) + } +} // end 0x42::mod1 +module 0x42::test { + use 0x42::mod1; // resolved as: 0x42::mod1 + use 0x42::mod2; // resolved as: 0x42::mod2 + use 0x42::mod3; // resolved as: 0x42::mod3 + use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4 + private fun add_mul(x: u64,y: u64,z: u64): u64 { + Mul<u64>(z, Add<u64>(x, y)) + } + private fun choose_function1(key: u64,x: u64): u64 { + { + let f: |u64|u64 with copy = if Eq<u64>(key, 0) { + mod2::double + } else { + if Eq<u64>(key, 1) { + mod1::triple + } else { + if Eq<u64>(key, 2) { + move|x: u64| mod3::multiply(4, x) + } else { + if Eq<u64>(key, 3) { + { + let x: u64 = 5; + move|y: u64| mod4::alt_multiply(x, y) + } + } else { + if Eq<u64>(key, 4) { + { + let x: u64 = 6; + move|y: u64| mod3::multiply(y, x) + } + } else { + if Eq<u64>(key, 5) { + move|x: u64| test::multiply3(x, 3, 2) + } else { + if Eq<u64>(key, 6) { + move|x: u64| mod3::multiply(x, 7) + } else { + if Eq<u64>(key, 7) { + move|x: u64| test::multiply3(4, x, 2) + } else { + if Eq<u64>(key, 8) { + move|x: u64| test::multiply3(3, 3, x) + } else { + if Eq<u64>(key, 9) { + { + let x: u64 = 2; + { + let y: u64 = 5; + move|z: u64| test::multiply3(x, y, z) + } + } + } else { + if Eq<u64>(key, 10) { + { + let z: u64 = 11; + move|x: u64| mod4::alt_multiply(x, z) with copy, drop + } + } else { + if Eq<u64>(key, 11) { + { + let g: |(u64, u64)|u64 with copy+store = move|(x: u64, y: u64): (u64, u64)| mod3::multiply(x, y) with copy, drop; + move|x: u64| (g)(x, 11) + } + } else { + if Eq<u64>(key, 12) { + { + let h: |u64|u64 with copy+store = move|x: u64| mod3::multiply(x, 12) with copy, drop; + move|x: u64| (h)(x) with copy, drop + } + } else { + if Eq<u64>(key, 14) { + { + let i: |u64|u64 with copy+store = move|x: u64| test::multiply3(2, x, 2); + move|z: u64| (i)(z) + } + } else { + { + let i: |(u64, u64)|u64 with copy+store = move|(x: u64, y: u64): (u64, u64)| { + let q: u64 = Sub<u64>(y, 1); + mod3::multiply(x, Add<u64>(q, 1)) + }; + move|x: u64| (i)(x, 15) + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }; + (f)(x) + } + } + private fun multiply3(x: u64,y: u64,z: u64): u64 { + Mul<u64>(Mul<u64>(x, y), z) + } + public fun test_functions() { + { + let x: u64 = 3; + { + let i: u64 = 0; + { + let __update_iter_flag: bool = false; + { + let __upper_bound_value: u64 = 15; + loop { + if true { + if __update_iter_flag { + i: u64 = Add<u64>(i, 1) + } else { + __update_iter_flag: bool = true + }; + if Lt<u64>(i, __upper_bound_value) { + { + let y: u64 = test::choose_function1(i, 3); + if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), x)) { + Tuple() + } else { + Abort(i) + }; + Tuple() + } + } else { + break + }; + Tuple() + } else { + break + } + }; + Tuple() + } + } + } + } + } +} // end 0x42::test + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::mod4 { + public fun alt_multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod4 +module 0x42::mod3 { + public fun multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod3 +module 0x42::mod2 { + friend fun double(x: u64): u64 { + Mul<u64>(x, 2) + } +} // end 0x42::mod2 +module 0x42::mod1 { + friend fun triple(x: u64): u64 { + Mul<u64>(x, 3) + } +} // end 0x42::mod1 +module 0x42::test { + use 0x42::mod1; // resolved as: 0x42::mod1 + use 0x42::mod2; // resolved as: 0x42::mod2 + use 0x42::mod3; // resolved as: 0x42::mod3 + use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4 + private fun add_mul(x: u64,y: u64,z: u64): u64 { + Mul<u64>(z, Add<u64>(x, y)) + } + private fun choose_function1(key: u64,x: u64): u64 { + { + let f: |u64|u64 with copy = if Eq<u64>(key, 0) { + mod2::double + } else { + if Eq<u64>(key, 1) { + mod1::triple + } else { + if Eq<u64>(key, 2) { + move|x: u64| mod3::multiply(4, x) + } else { + if Eq<u64>(key, 3) { + { + let x: u64 = 5; + move|y: u64| mod4::alt_multiply(x, y) + } + } else { + if Eq<u64>(key, 4) { + { + let x: u64 = 6; + move|y: u64| mod3::multiply(y, x) + } + } else { + if Eq<u64>(key, 5) { + move|x: u64| test::multiply3(x, 3, 2) + } else { + if Eq<u64>(key, 6) { + move|x: u64| mod3::multiply(x, 7) + } else { + if Eq<u64>(key, 7) { + move|x: u64| test::multiply3(4, x, 2) + } else { + if Eq<u64>(key, 8) { + move|x: u64| test::multiply3(3, 3, x) + } else { + if Eq<u64>(key, 9) { + { + let x: u64 = 2; + { + let y: u64 = 5; + move|z: u64| test::multiply3(x, y, z) + } + } + } else { + if Eq<u64>(key, 10) { + { + let z: u64 = 11; + move|x: u64| mod4::alt_multiply(x, z) with copy, drop + } + } else { + if Eq<u64>(key, 11) { + { + let g: |(u64, u64)|u64 with copy+store = move|(x: u64, y: u64): (u64, u64)| mod3::multiply(x, y) with copy, drop; + move|x: u64| (g)(x, 11) + } + } else { + if Eq<u64>(key, 12) { + { + let h: |u64|u64 with copy+store = move|x: u64| mod3::multiply(x, 12) with copy, drop; + move|x: u64| (h)(x) with copy, drop + } + } else { + if Eq<u64>(key, 14) { + { + let i: |u64|u64 with copy+store = move|x: u64| test::multiply3(2, x, 2); + move|z: u64| (i)(z) + } + } else { + { + let i: |(u64, u64)|u64 with copy+store = move|(x: u64, y: u64): (u64, u64)| { + let q: u64 = Sub<u64>(y, 1); + mod3::multiply(x, Add<u64>(q, 1)) + }; + move|x: u64| (i)(x, 15) + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }; + (f)(x) + } + } + private fun multiply3(x: u64,y: u64,z: u64): u64 { + Mul<u64>(Mul<u64>(x, y), z) + } + public fun test_functions() { + { + let x: u64 = 3; + { + let i: u64 = 0; + { + let __update_iter_flag: bool = false; + { + let __upper_bound_value: u64 = 15; + loop { + if true { + if __update_iter_flag { + i: u64 = Add<u64>(i, 1) + } else { + __update_iter_flag: bool = true + }; + if Lt<u64>(i, __upper_bound_value) { + { + let y: u64 = test::choose_function1(i, 3); + if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), x)) { + Tuple() + } else { + Abort(i) + }; + Tuple() + } + } else { + break + }; + Tuple() + } else { + break + } + }; + Tuple() + } + } + } + } + } +} // end 0x42::test + + +// -- Model dump after env processor unused struct params check: +module 0x42::mod4 { + public fun alt_multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod4 +module 0x42::mod3 { + public fun multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod3 +module 0x42::mod2 { + friend fun double(x: u64): u64 { + Mul<u64>(x, 2) + } +} // end 0x42::mod2 +module 0x42::mod1 { + friend fun triple(x: u64): u64 { + Mul<u64>(x, 3) + } +} // end 0x42::mod1 +module 0x42::test { + use 0x42::mod1; // resolved as: 0x42::mod1 + use 0x42::mod2; // resolved as: 0x42::mod2 + use 0x42::mod3; // resolved as: 0x42::mod3 + use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4 + private fun add_mul(x: u64,y: u64,z: u64): u64 { + Mul<u64>(z, Add<u64>(x, y)) + } + private fun choose_function1(key: u64,x: u64): u64 { + { + let f: |u64|u64 with copy = if Eq<u64>(key, 0) { + mod2::double + } else { + if Eq<u64>(key, 1) { + mod1::triple + } else { + if Eq<u64>(key, 2) { + move|x: u64| mod3::multiply(4, x) + } else { + if Eq<u64>(key, 3) { + { + let x: u64 = 5; + move|y: u64| mod4::alt_multiply(x, y) + } + } else { + if Eq<u64>(key, 4) { + { + let x: u64 = 6; + move|y: u64| mod3::multiply(y, x) + } + } else { + if Eq<u64>(key, 5) { + move|x: u64| test::multiply3(x, 3, 2) + } else { + if Eq<u64>(key, 6) { + move|x: u64| mod3::multiply(x, 7) + } else { + if Eq<u64>(key, 7) { + move|x: u64| test::multiply3(4, x, 2) + } else { + if Eq<u64>(key, 8) { + move|x: u64| test::multiply3(3, 3, x) + } else { + if Eq<u64>(key, 9) { + { + let x: u64 = 2; + { + let y: u64 = 5; + move|z: u64| test::multiply3(x, y, z) + } + } + } else { + if Eq<u64>(key, 10) { + { + let z: u64 = 11; + move|x: u64| mod4::alt_multiply(x, z) with copy, drop + } + } else { + if Eq<u64>(key, 11) { + { + let g: |(u64, u64)|u64 with copy+store = move|(x: u64, y: u64): (u64, u64)| mod3::multiply(x, y) with copy, drop; + move|x: u64| (g)(x, 11) + } + } else { + if Eq<u64>(key, 12) { + { + let h: |u64|u64 with copy+store = move|x: u64| mod3::multiply(x, 12) with copy, drop; + move|x: u64| (h)(x) with copy, drop + } + } else { + if Eq<u64>(key, 14) { + { + let i: |u64|u64 with copy+store = move|x: u64| test::multiply3(2, x, 2); + move|z: u64| (i)(z) + } + } else { + { + let i: |(u64, u64)|u64 with copy+store = move|(x: u64, y: u64): (u64, u64)| { + let q: u64 = Sub<u64>(y, 1); + mod3::multiply(x, Add<u64>(q, 1)) + }; + move|x: u64| (i)(x, 15) + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }; + (f)(x) + } + } + private fun multiply3(x: u64,y: u64,z: u64): u64 { + Mul<u64>(Mul<u64>(x, y), z) + } + public fun test_functions() { + { + let x: u64 = 3; + { + let i: u64 = 0; + { + let __update_iter_flag: bool = false; + { + let __upper_bound_value: u64 = 15; + loop { + if true { + if __update_iter_flag { + i: u64 = Add<u64>(i, 1) + } else { + __update_iter_flag: bool = true + }; + if Lt<u64>(i, __upper_bound_value) { + { + let y: u64 = test::choose_function1(i, 3); + if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), x)) { + Tuple() + } else { + Abort(i) + }; + Tuple() + } + } else { + break + }; + Tuple() + } else { + break + } + }; + Tuple() + } + } + } + } + } +} // end 0x42::test + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::mod4 { + public fun alt_multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod4 +module 0x42::mod3 { + public fun multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod3 +module 0x42::mod2 { + friend fun double(x: u64): u64 { + Mul<u64>(x, 2) + } +} // end 0x42::mod2 +module 0x42::mod1 { + friend fun triple(x: u64): u64 { + Mul<u64>(x, 3) + } +} // end 0x42::mod1 +module 0x42::test { + use 0x42::mod1; // resolved as: 0x42::mod1 + use 0x42::mod2; // resolved as: 0x42::mod2 + use 0x42::mod3; // resolved as: 0x42::mod3 + use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4 + private fun add_mul(x: u64,y: u64,z: u64): u64 { + Mul<u64>(z, Add<u64>(x, y)) + } + private fun choose_function1(key: u64,x: u64): u64 { + { + let f: |u64|u64 with copy = if Eq<u64>(key, 0) { + mod2::double + } else { + if Eq<u64>(key, 1) { + mod1::triple + } else { + if Eq<u64>(key, 2) { + move|x: u64| mod3::multiply(4, x) + } else { + if Eq<u64>(key, 3) { + { + let x: u64 = 5; + move|y: u64| mod4::alt_multiply(x, y) + } + } else { + if Eq<u64>(key, 4) { + { + let x: u64 = 6; + move|y: u64| mod3::multiply(y, x) + } + } else { + if Eq<u64>(key, 5) { + move|x: u64| test::multiply3(x, 3, 2) + } else { + if Eq<u64>(key, 6) { + move|x: u64| mod3::multiply(x, 7) + } else { + if Eq<u64>(key, 7) { + move|x: u64| test::multiply3(4, x, 2) + } else { + if Eq<u64>(key, 8) { + move|x: u64| test::multiply3(3, 3, x) + } else { + if Eq<u64>(key, 9) { + { + let x: u64 = 2; + { + let y: u64 = 5; + move|z: u64| test::multiply3(x, y, z) + } + } + } else { + if Eq<u64>(key, 10) { + { + let z: u64 = 11; + move|x: u64| mod4::alt_multiply(x, z) with copy, drop + } + } else { + if Eq<u64>(key, 11) { + { + let g: |(u64, u64)|u64 with copy+store = move|(x: u64, y: u64): (u64, u64)| mod3::multiply(x, y) with copy, drop; + move|x: u64| (g)(x, 11) + } + } else { + if Eq<u64>(key, 12) { + { + let h: |u64|u64 with copy+store = move|x: u64| mod3::multiply(x, 12) with copy, drop; + move|x: u64| (h)(x) with copy, drop + } + } else { + if Eq<u64>(key, 14) { + { + let i: |u64|u64 with copy+store = move|x: u64| test::multiply3(2, x, 2); + move|z: u64| (i)(z) + } + } else { + { + let i: |(u64, u64)|u64 with copy+store = move|(x: u64, y: u64): (u64, u64)| { + let q: u64 = Sub<u64>(y, 1); + mod3::multiply(x, Add<u64>(q, 1)) + }; + move|x: u64| (i)(x, 15) + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }; + (f)(x) + } + } + private fun multiply3(x: u64,y: u64,z: u64): u64 { + Mul<u64>(Mul<u64>(x, y), z) + } + public fun test_functions() { + { + let x: u64 = 3; + { + let i: u64 = 0; + { + let __update_iter_flag: bool = false; + { + let __upper_bound_value: u64 = 15; + loop { + if true { + if __update_iter_flag { + i: u64 = Add<u64>(i, 1) + } else { + __update_iter_flag: bool = true + }; + if Lt<u64>(i, __upper_bound_value) { + { + let y: u64 = test::choose_function1(i, 3); + if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), x)) { + Tuple() + } else { + Abort(i) + }; + Tuple() + } + } else { + break + }; + Tuple() + } else { + break + } + }; + Tuple() + } + } + } + } + } +} // end 0x42::test + + +// -- Model dump after env processor inlining: +module 0x42::mod4 { + public fun alt_multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod4 +module 0x42::mod3 { + public fun multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod3 +module 0x42::mod2 { + friend fun double(x: u64): u64 { + Mul<u64>(x, 2) + } +} // end 0x42::mod2 +module 0x42::mod1 { + friend fun triple(x: u64): u64 { + Mul<u64>(x, 3) + } +} // end 0x42::mod1 +module 0x42::test { + use 0x42::mod1; // resolved as: 0x42::mod1 + use 0x42::mod2; // resolved as: 0x42::mod2 + use 0x42::mod3; // resolved as: 0x42::mod3 + use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4 + private fun add_mul(x: u64,y: u64,z: u64): u64 { + Mul<u64>(z, Add<u64>(x, y)) + } + private fun choose_function1(key: u64,x: u64): u64 { + { + let f: |u64|u64 with copy = if Eq<u64>(key, 0) { + mod2::double + } else { + if Eq<u64>(key, 1) { + mod1::triple + } else { + if Eq<u64>(key, 2) { + move|x: u64| mod3::multiply(4, x) + } else { + if Eq<u64>(key, 3) { + { + let x: u64 = 5; + move|y: u64| mod4::alt_multiply(x, y) + } + } else { + if Eq<u64>(key, 4) { + { + let x: u64 = 6; + move|y: u64| mod3::multiply(y, x) + } + } else { + if Eq<u64>(key, 5) { + move|x: u64| test::multiply3(x, 3, 2) + } else { + if Eq<u64>(key, 6) { + move|x: u64| mod3::multiply(x, 7) + } else { + if Eq<u64>(key, 7) { + move|x: u64| test::multiply3(4, x, 2) + } else { + if Eq<u64>(key, 8) { + move|x: u64| test::multiply3(3, 3, x) + } else { + if Eq<u64>(key, 9) { + { + let x: u64 = 2; + { + let y: u64 = 5; + move|z: u64| test::multiply3(x, y, z) + } + } + } else { + if Eq<u64>(key, 10) { + { + let z: u64 = 11; + move|x: u64| mod4::alt_multiply(x, z) with copy, drop + } + } else { + if Eq<u64>(key, 11) { + { + let g: |(u64, u64)|u64 with copy+store = move|(x: u64, y: u64): (u64, u64)| mod3::multiply(x, y) with copy, drop; + move|x: u64| (g)(x, 11) + } + } else { + if Eq<u64>(key, 12) { + { + let h: |u64|u64 with copy+store = move|x: u64| mod3::multiply(x, 12) with copy, drop; + move|x: u64| (h)(x) with copy, drop + } + } else { + if Eq<u64>(key, 14) { + { + let i: |u64|u64 with copy+store = move|x: u64| test::multiply3(2, x, 2); + move|z: u64| (i)(z) + } + } else { + { + let i: |(u64, u64)|u64 with copy+store = move|(x: u64, y: u64): (u64, u64)| { + let q: u64 = Sub<u64>(y, 1); + mod3::multiply(x, Add<u64>(q, 1)) + }; + move|x: u64| (i)(x, 15) + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }; + (f)(x) + } + } + private fun multiply3(x: u64,y: u64,z: u64): u64 { + Mul<u64>(Mul<u64>(x, y), z) + } + public fun test_functions() { + { + let x: u64 = 3; + { + let i: u64 = 0; + { + let __update_iter_flag: bool = false; + { + let __upper_bound_value: u64 = 15; + loop { + if true { + if __update_iter_flag { + i: u64 = Add<u64>(i, 1) + } else { + __update_iter_flag: bool = true + }; + if Lt<u64>(i, __upper_bound_value) { + { + let y: u64 = test::choose_function1(i, 3); + if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), x)) { + Tuple() + } else { + Abort(i) + }; + Tuple() + } + } else { + break + }; + Tuple() + } else { + break + } + }; + Tuple() + } + } + } + } + } +} // end 0x42::test + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::mod4 { + public fun alt_multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod4 +module 0x42::mod3 { + public fun multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod3 +module 0x42::mod2 { + friend fun double(x: u64): u64 { + Mul<u64>(x, 2) + } +} // end 0x42::mod2 +module 0x42::mod1 { + friend fun triple(x: u64): u64 { + Mul<u64>(x, 3) + } +} // end 0x42::mod1 +module 0x42::test { + use 0x42::mod1; // resolved as: 0x42::mod1 + use 0x42::mod2; // resolved as: 0x42::mod2 + use 0x42::mod3; // resolved as: 0x42::mod3 + use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4 + private fun add_mul(x: u64,y: u64,z: u64): u64 { + Mul<u64>(z, Add<u64>(x, y)) + } + private fun choose_function1(key: u64,x: u64): u64 { + { + let f: |u64|u64 with copy = if Eq<u64>(key, 0) { + mod2::double + } else { + if Eq<u64>(key, 1) { + mod1::triple + } else { + if Eq<u64>(key, 2) { + move|x: u64| mod3::multiply(4, x) + } else { + if Eq<u64>(key, 3) { + { + let x: u64 = 5; + move|y: u64| mod4::alt_multiply(x, y) + } + } else { + if Eq<u64>(key, 4) { + { + let x: u64 = 6; + move|y: u64| mod3::multiply(y, x) + } + } else { + if Eq<u64>(key, 5) { + move|x: u64| test::multiply3(x, 3, 2) + } else { + if Eq<u64>(key, 6) { + move|x: u64| mod3::multiply(x, 7) + } else { + if Eq<u64>(key, 7) { + move|x: u64| test::multiply3(4, x, 2) + } else { + if Eq<u64>(key, 8) { + move|x: u64| test::multiply3(3, 3, x) + } else { + if Eq<u64>(key, 9) { + { + let x: u64 = 2; + { + let y: u64 = 5; + move|z: u64| test::multiply3(x, y, z) + } + } + } else { + if Eq<u64>(key, 10) { + { + let z: u64 = 11; + move|x: u64| mod4::alt_multiply(x, z) with copy, drop + } + } else { + if Eq<u64>(key, 11) { + { + let g: |(u64, u64)|u64 with copy+store = move|(x: u64, y: u64): (u64, u64)| mod3::multiply(x, y) with copy, drop; + move|x: u64| (g)(x, 11) + } + } else { + if Eq<u64>(key, 12) { + { + let h: |u64|u64 with copy+store = move|x: u64| mod3::multiply(x, 12) with copy, drop; + move|x: u64| (h)(x) with copy, drop + } + } else { + if Eq<u64>(key, 14) { + { + let i: |u64|u64 with copy+store = move|x: u64| test::multiply3(2, x, 2); + move|z: u64| (i)(z) + } + } else { + { + let i: |(u64, u64)|u64 with copy+store = move|(x: u64, y: u64): (u64, u64)| { + let q: u64 = Sub<u64>(y, 1); + mod3::multiply(x, Add<u64>(q, 1)) + }; + move|x: u64| (i)(x, 15) + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }; + (f)(x) + } + } + private fun multiply3(x: u64,y: u64,z: u64): u64 { + Mul<u64>(Mul<u64>(x, y), z) + } + public fun test_functions() { + { + let x: u64 = 3; + { + let i: u64 = 0; + { + let __update_iter_flag: bool = false; + { + let __upper_bound_value: u64 = 15; + loop { + if true { + if __update_iter_flag { + i: u64 = Add<u64>(i, 1) + } else { + __update_iter_flag: bool = true + }; + if Lt<u64>(i, __upper_bound_value) { + { + let y: u64 = test::choose_function1(i, 3); + if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), x)) { + Tuple() + } else { + Abort(i) + }; + Tuple() + } + } else { + break + }; + Tuple() + } else { + break + } + }; + Tuple() + } + } + } + } + } +} // end 0x42::test + + +// -- Model dump after env processor acquires check: +module 0x42::mod4 { + public fun alt_multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod4 +module 0x42::mod3 { + public fun multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod3 +module 0x42::mod2 { + friend fun double(x: u64): u64 { + Mul<u64>(x, 2) + } +} // end 0x42::mod2 +module 0x42::mod1 { + friend fun triple(x: u64): u64 { + Mul<u64>(x, 3) + } +} // end 0x42::mod1 +module 0x42::test { + use 0x42::mod1; // resolved as: 0x42::mod1 + use 0x42::mod2; // resolved as: 0x42::mod2 + use 0x42::mod3; // resolved as: 0x42::mod3 + use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4 + private fun add_mul(x: u64,y: u64,z: u64): u64 { + Mul<u64>(z, Add<u64>(x, y)) + } + private fun choose_function1(key: u64,x: u64): u64 { + { + let f: |u64|u64 with copy = if Eq<u64>(key, 0) { + mod2::double + } else { + if Eq<u64>(key, 1) { + mod1::triple + } else { + if Eq<u64>(key, 2) { + move|x: u64| mod3::multiply(4, x) + } else { + if Eq<u64>(key, 3) { + { + let x: u64 = 5; + move|y: u64| mod4::alt_multiply(x, y) + } + } else { + if Eq<u64>(key, 4) { + { + let x: u64 = 6; + move|y: u64| mod3::multiply(y, x) + } + } else { + if Eq<u64>(key, 5) { + move|x: u64| test::multiply3(x, 3, 2) + } else { + if Eq<u64>(key, 6) { + move|x: u64| mod3::multiply(x, 7) + } else { + if Eq<u64>(key, 7) { + move|x: u64| test::multiply3(4, x, 2) + } else { + if Eq<u64>(key, 8) { + move|x: u64| test::multiply3(3, 3, x) + } else { + if Eq<u64>(key, 9) { + { + let x: u64 = 2; + { + let y: u64 = 5; + move|z: u64| test::multiply3(x, y, z) + } + } + } else { + if Eq<u64>(key, 10) { + { + let z: u64 = 11; + move|x: u64| mod4::alt_multiply(x, z) with copy, drop + } + } else { + if Eq<u64>(key, 11) { + { + let g: |(u64, u64)|u64 with copy+store = move|(x: u64, y: u64): (u64, u64)| mod3::multiply(x, y) with copy, drop; + move|x: u64| (g)(x, 11) + } + } else { + if Eq<u64>(key, 12) { + { + let h: |u64|u64 with copy+store = move|x: u64| mod3::multiply(x, 12) with copy, drop; + move|x: u64| (h)(x) with copy, drop + } + } else { + if Eq<u64>(key, 14) { + { + let i: |u64|u64 with copy+store = move|x: u64| test::multiply3(2, x, 2); + move|z: u64| (i)(z) + } + } else { + { + let i: |(u64, u64)|u64 with copy+store = move|(x: u64, y: u64): (u64, u64)| { + let q: u64 = Sub<u64>(y, 1); + mod3::multiply(x, Add<u64>(q, 1)) + }; + move|x: u64| (i)(x, 15) + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }; + (f)(x) + } + } + private fun multiply3(x: u64,y: u64,z: u64): u64 { + Mul<u64>(Mul<u64>(x, y), z) + } + public fun test_functions() { + { + let x: u64 = 3; + { + let i: u64 = 0; + { + let __update_iter_flag: bool = false; + { + let __upper_bound_value: u64 = 15; + loop { + if true { + if __update_iter_flag { + i: u64 = Add<u64>(i, 1) + } else { + __update_iter_flag: bool = true + }; + if Lt<u64>(i, __upper_bound_value) { + { + let y: u64 = test::choose_function1(i, 3); + if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), x)) { + Tuple() + } else { + Abort(i) + }; + Tuple() + } + } else { + break + }; + Tuple() + } else { + break + } + }; + Tuple() + } + } + } + } + } +} // end 0x42::test + + +// -- Model dump after env processor simplifier: +module 0x42::mod4 { + public fun alt_multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod4 +module 0x42::mod3 { + public fun multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod3 +module 0x42::mod2 { + friend fun double(x: u64): u64 { + Mul<u64>(x, 2) + } +} // end 0x42::mod2 +module 0x42::mod1 { + friend fun triple(x: u64): u64 { + Mul<u64>(x, 3) + } +} // end 0x42::mod1 +module 0x42::test { + use 0x42::mod1; // resolved as: 0x42::mod1 + use 0x42::mod2; // resolved as: 0x42::mod2 + use 0x42::mod3; // resolved as: 0x42::mod3 + use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4 + private fun add_mul(x: u64,y: u64,z: u64): u64 { + Mul<u64>(z, Add<u64>(x, y)) + } + private fun choose_function1(key: u64,x: u64): u64 { + { + let f: |u64|u64 with copy = if Eq<u64>(key, 0) { + mod2::double + } else { + if Eq<u64>(key, 1) { + mod1::triple + } else { + if Eq<u64>(key, 2) { + move|x: u64| mod3::multiply(4, x) + } else { + if Eq<u64>(key, 3) { + move|y: u64| mod4::alt_multiply(5, y) + } else { + if Eq<u64>(key, 4) { + move|y: u64| mod3::multiply(y, 6) + } else { + if Eq<u64>(key, 5) { + move|x: u64| test::multiply3(x, 3, 2) + } else { + if Eq<u64>(key, 6) { + move|x: u64| mod3::multiply(x, 7) + } else { + if Eq<u64>(key, 7) { + move|x: u64| test::multiply3(4, x, 2) + } else { + if Eq<u64>(key, 8) { + move|x: u64| test::multiply3(3, 3, x) + } else { + if Eq<u64>(key, 9) { + move|z: u64| test::multiply3(2, 5, z) + } else { + if Eq<u64>(key, 10) { + move|x: u64| mod4::alt_multiply(x, 11) with copy, drop + } else { + if Eq<u64>(key, 11) { + { + let g: |(u64, u64)|u64 with copy+store = move|(x: u64, y: u64): (u64, u64)| mod3::multiply(x, y) with copy, drop; + move|x: u64| (g)(x, 11) + } + } else { + if Eq<u64>(key, 12) { + { + let h: |u64|u64 with copy+store = move|x: u64| mod3::multiply(x, 12) with copy, drop; + move|x: u64| (h)(x) with copy, drop + } + } else { + if Eq<u64>(key, 14) { + { + let i: |u64|u64 with copy+store = move|x: u64| test::multiply3(2, x, 2); + move|z: u64| (i)(z) + } + } else { + { + let i: |(u64, u64)|u64 with copy+store = move|(x: u64, y: u64): (u64, u64)| { + let q: u64 = Sub<u64>(y, 1); + mod3::multiply(x, Add<u64>(q, 1)) + }; + move|x: u64| (i)(x, 15) + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }; + (f)(x) + } + } + private fun multiply3(x: u64,y: u64,z: u64): u64 { + Mul<u64>(Mul<u64>(x, y), z) + } + public fun test_functions() { + { + let i: u64 = 0; + { + let __update_iter_flag: bool = false; + loop { + if true { + if __update_iter_flag { + i: u64 = Add<u64>(i, 1) + } else { + __update_iter_flag: bool = true + }; + if Lt<u64>(i, 15) { + { + let y: u64 = test::choose_function1(i, 3); + if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), 3)) { + Tuple() + } else { + Abort(i) + }; + Tuple() + } + } else { + break + }; + Tuple() + } else { + break + } + }; + Tuple() + } + } + } +} // end 0x42::test + + +// -- Model dump after env processor lambda-lifting: +module 0x42::mod4 { + public fun alt_multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod4 +module 0x42::mod3 { + public fun multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod3 +module 0x42::mod2 { + friend fun double(x: u64): u64 { + Mul<u64>(x, 2) + } +} // end 0x42::mod2 +module 0x42::mod1 { + friend fun triple(x: u64): u64 { + Mul<u64>(x, 3) + } +} // end 0x42::mod1 +module 0x42::test { + use 0x42::mod1; // resolved as: 0x42::mod1 + use 0x42::mod2; // resolved as: 0x42::mod2 + use 0x42::mod3; // resolved as: 0x42::mod3 + use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4 + private fun add_mul(x: u64,y: u64,z: u64): u64 { + Mul<u64>(z, Add<u64>(x, y)) + } + private fun choose_function1(key: u64,x: u64): u64 { + { + let f: |u64|u64 with copy = if Eq<u64>(key, 0) { + mod2::double + } else { + if Eq<u64>(key, 1) { + mod1::triple + } else { + if Eq<u64>(key, 2) { + earlybind(mod3::multiply, 4) + } else { + if Eq<u64>(key, 3) { + earlybind(mod4::alt_multiply, 5) + } else { + if Eq<u64>(key, 4) { + test::choose_function1$lambda$1 + } else { + if Eq<u64>(key, 5) { + test::choose_function1$lambda$2 + } else { + if Eq<u64>(key, 6) { + test::choose_function1$lambda$3 + } else { + if Eq<u64>(key, 7) { + test::choose_function1$lambda$4 + } else { + if Eq<u64>(key, 8) { + earlybind(test::multiply3, 3, 3) + } else { + if Eq<u64>(key, 9) { + earlybind(test::multiply3, 2, 5) + } else { + if Eq<u64>(key, 10) { + test::choose_function1$lambda$5 + } else { + if Eq<u64>(key, 11) { + { + let g: |(u64, u64)|u64 with copy+store = mod3::multiply; + earlybind(test::choose_function1$lambda$6, g) + } + } else { + if Eq<u64>(key, 12) { + { + let h: |u64|u64 with copy+store = test::choose_function1$lambda$7; + h + } + } else { + if Eq<u64>(key, 14) { + { + let i: |u64|u64 with copy+store = test::choose_function1$lambda$8; + i + } + } else { + { + let i: |(u64, u64)|u64 with copy+store = test::choose_function1$lambda$9; + earlybind(test::choose_function1$lambda$10, i) + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }; + (f)(x) + } + } + private fun multiply3(x: u64,y: u64,z: u64): u64 { + Mul<u64>(Mul<u64>(x, y), z) + } + public fun test_functions() { + { + let i: u64 = 0; + { + let __update_iter_flag: bool = false; + loop { + if true { + if __update_iter_flag { + i: u64 = Add<u64>(i, 1) + } else { + __update_iter_flag: bool = true + }; + if Lt<u64>(i, 15) { + { + let y: u64 = test::choose_function1(i, 3); + if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), 3)) { + Tuple() + } else { + Abort(i) + }; + Tuple() + } + } else { + break + }; + Tuple() + } else { + break + } + }; + Tuple() + } + } + } + private fun choose_function1$lambda$1(y: u64): u64 { + mod3::multiply(y, 6) + } + private fun choose_function1$lambda$2(x: u64): u64 { + test::multiply3(x, 3, 2) + } + private fun choose_function1$lambda$3(x: u64): u64 { + mod3::multiply(x, 7) + } + private fun choose_function1$lambda$4(x: u64): u64 { + test::multiply3(4, x, 2) + } + private fun choose_function1$lambda$5(x: u64): u64 { + mod4::alt_multiply(x, 11) + } + private fun choose_function1$lambda$6(g: |(u64, u64)|u64 with copy+store,x: u64): u64 { + (g)(x, 11) + } + private fun choose_function1$lambda$7(x: u64): u64 { + mod3::multiply(x, 12) + } + private fun choose_function1$lambda$8(x: u64): u64 { + test::multiply3(2, x, 2) + } + private fun choose_function1$lambda$9(x: u64,y: u64): u64 { + { + let q: u64 = Sub<u64>(y, 1); + mod3::multiply(x, Add<u64>(q, 1)) + } + } + private fun choose_function1$lambda$10(i: |(u64, u64)|u64 with copy+store,x: u64): u64 { + (i)(x, 15) + } +} // end 0x42::test + + +// -- Model dump after env processor specification checker: +module 0x42::mod4 { + public fun alt_multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod4 +module 0x42::mod3 { + public fun multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod3 +module 0x42::mod2 { + friend fun double(x: u64): u64 { + Mul<u64>(x, 2) + } +} // end 0x42::mod2 +module 0x42::mod1 { + friend fun triple(x: u64): u64 { + Mul<u64>(x, 3) + } +} // end 0x42::mod1 +module 0x42::test { + use 0x42::mod1; // resolved as: 0x42::mod1 + use 0x42::mod2; // resolved as: 0x42::mod2 + use 0x42::mod3; // resolved as: 0x42::mod3 + use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4 + private fun add_mul(x: u64,y: u64,z: u64): u64 { + Mul<u64>(z, Add<u64>(x, y)) + } + private fun choose_function1(key: u64,x: u64): u64 { + { + let f: |u64|u64 with copy = if Eq<u64>(key, 0) { + mod2::double + } else { + if Eq<u64>(key, 1) { + mod1::triple + } else { + if Eq<u64>(key, 2) { + earlybind(mod3::multiply, 4) + } else { + if Eq<u64>(key, 3) { + earlybind(mod4::alt_multiply, 5) + } else { + if Eq<u64>(key, 4) { + test::choose_function1$lambda$1 + } else { + if Eq<u64>(key, 5) { + test::choose_function1$lambda$2 + } else { + if Eq<u64>(key, 6) { + test::choose_function1$lambda$3 + } else { + if Eq<u64>(key, 7) { + test::choose_function1$lambda$4 + } else { + if Eq<u64>(key, 8) { + earlybind(test::multiply3, 3, 3) + } else { + if Eq<u64>(key, 9) { + earlybind(test::multiply3, 2, 5) + } else { + if Eq<u64>(key, 10) { + test::choose_function1$lambda$5 + } else { + if Eq<u64>(key, 11) { + { + let g: |(u64, u64)|u64 with copy+store = mod3::multiply; + earlybind(test::choose_function1$lambda$6, g) + } + } else { + if Eq<u64>(key, 12) { + { + let h: |u64|u64 with copy+store = test::choose_function1$lambda$7; + h + } + } else { + if Eq<u64>(key, 14) { + { + let i: |u64|u64 with copy+store = test::choose_function1$lambda$8; + i + } + } else { + { + let i: |(u64, u64)|u64 with copy+store = test::choose_function1$lambda$9; + earlybind(test::choose_function1$lambda$10, i) + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }; + (f)(x) + } + } + private fun multiply3(x: u64,y: u64,z: u64): u64 { + Mul<u64>(Mul<u64>(x, y), z) + } + public fun test_functions() { + { + let i: u64 = 0; + { + let __update_iter_flag: bool = false; + loop { + if true { + if __update_iter_flag { + i: u64 = Add<u64>(i, 1) + } else { + __update_iter_flag: bool = true + }; + if Lt<u64>(i, 15) { + { + let y: u64 = test::choose_function1(i, 3); + if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), 3)) { + Tuple() + } else { + Abort(i) + }; + Tuple() + } + } else { + break + }; + Tuple() + } else { + break + } + }; + Tuple() + } + } + } + private fun choose_function1$lambda$1(y: u64): u64 { + mod3::multiply(y, 6) + } + private fun choose_function1$lambda$2(x: u64): u64 { + test::multiply3(x, 3, 2) + } + private fun choose_function1$lambda$3(x: u64): u64 { + mod3::multiply(x, 7) + } + private fun choose_function1$lambda$4(x: u64): u64 { + test::multiply3(4, x, 2) + } + private fun choose_function1$lambda$5(x: u64): u64 { + mod4::alt_multiply(x, 11) + } + private fun choose_function1$lambda$6(g: |(u64, u64)|u64 with copy+store,x: u64): u64 { + (g)(x, 11) + } + private fun choose_function1$lambda$7(x: u64): u64 { + mod3::multiply(x, 12) + } + private fun choose_function1$lambda$8(x: u64): u64 { + test::multiply3(2, x, 2) + } + private fun choose_function1$lambda$9(x: u64,y: u64): u64 { + { + let q: u64 = Sub<u64>(y, 1); + mod3::multiply(x, Add<u64>(q, 1)) + } + } + private fun choose_function1$lambda$10(i: |(u64, u64)|u64 with copy+store,x: u64): u64 { + (i)(x, 15) + } +} // end 0x42::test + + +// -- Model dump after env processor specification rewriter: +module 0x42::mod4 { + public fun alt_multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod4 +module 0x42::mod3 { + public fun multiply(x: u64,y: u64): u64 { + Mul<u64>(x, y) + } +} // end 0x42::mod3 +module 0x42::mod2 { + friend fun double(x: u64): u64 { + Mul<u64>(x, 2) + } +} // end 0x42::mod2 +module 0x42::mod1 { + friend fun triple(x: u64): u64 { + Mul<u64>(x, 3) + } +} // end 0x42::mod1 +module 0x42::test { + use 0x42::mod1; // resolved as: 0x42::mod1 + use 0x42::mod2; // resolved as: 0x42::mod2 + use 0x42::mod3; // resolved as: 0x42::mod3 + use 0x42::mod4::{alt_multiply}; // resolved as: 0x42::mod4 + private fun add_mul(x: u64,y: u64,z: u64): u64 { + Mul<u64>(z, Add<u64>(x, y)) + } + private fun choose_function1(key: u64,x: u64): u64 { + { + let f: |u64|u64 with copy = if Eq<u64>(key, 0) { + mod2::double + } else { + if Eq<u64>(key, 1) { + mod1::triple + } else { + if Eq<u64>(key, 2) { + earlybind(mod3::multiply, 4) + } else { + if Eq<u64>(key, 3) { + earlybind(mod4::alt_multiply, 5) + } else { + if Eq<u64>(key, 4) { + test::choose_function1$lambda$1 + } else { + if Eq<u64>(key, 5) { + test::choose_function1$lambda$2 + } else { + if Eq<u64>(key, 6) { + test::choose_function1$lambda$3 + } else { + if Eq<u64>(key, 7) { + test::choose_function1$lambda$4 + } else { + if Eq<u64>(key, 8) { + earlybind(test::multiply3, 3, 3) + } else { + if Eq<u64>(key, 9) { + earlybind(test::multiply3, 2, 5) + } else { + if Eq<u64>(key, 10) { + test::choose_function1$lambda$5 + } else { + if Eq<u64>(key, 11) { + { + let g: |(u64, u64)|u64 with copy+store = mod3::multiply; + earlybind(test::choose_function1$lambda$6, g) + } + } else { + if Eq<u64>(key, 12) { + { + let h: |u64|u64 with copy+store = test::choose_function1$lambda$7; + h + } + } else { + if Eq<u64>(key, 14) { + { + let i: |u64|u64 with copy+store = test::choose_function1$lambda$8; + i + } + } else { + { + let i: |(u64, u64)|u64 with copy+store = test::choose_function1$lambda$9; + earlybind(test::choose_function1$lambda$10, i) + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }; + (f)(x) + } + } + private fun multiply3(x: u64,y: u64,z: u64): u64 { + Mul<u64>(Mul<u64>(x, y), z) + } + public fun test_functions() { + { + let i: u64 = 0; + { + let __update_iter_flag: bool = false; + loop { + if true { + if __update_iter_flag { + i: u64 = Add<u64>(i, 1) + } else { + __update_iter_flag: bool = true + }; + if Lt<u64>(i, 15) { + { + let y: u64 = test::choose_function1(i, 3); + if Eq<u64>(y, Mul<u64>(Add<u64>(i, 2), 3)) { + Tuple() + } else { + Abort(i) + }; + Tuple() + } + } else { + break + }; + Tuple() + } else { + break + } + }; + Tuple() + } + } + } + private fun choose_function1$lambda$1(y: u64): u64 { + mod3::multiply(y, 6) + } + private fun choose_function1$lambda$2(x: u64): u64 { + test::multiply3(x, 3, 2) + } + private fun choose_function1$lambda$3(x: u64): u64 { + mod3::multiply(x, 7) + } + private fun choose_function1$lambda$4(x: u64): u64 { + test::multiply3(4, x, 2) + } + private fun choose_function1$lambda$5(x: u64): u64 { + mod4::alt_multiply(x, 11) + } + private fun choose_function1$lambda$6(g: |(u64, u64)|u64 with copy+store,x: u64): u64 { + (g)(x, 11) + } + private fun choose_function1$lambda$7(x: u64): u64 { + mod3::multiply(x, 12) + } + private fun choose_function1$lambda$8(x: u64): u64 { + test::multiply3(2, x, 2) + } + private fun choose_function1$lambda$9(x: u64,y: u64): u64 { + { + let q: u64 = Sub<u64>(y, 1); + mod3::multiply(x, Add<u64>(q, 1)) + } + } + private fun choose_function1$lambda$10(i: |(u64, u64)|u64 with copy+store,x: u64): u64 { + (i)(x, 15) + } +} // end 0x42::test + + + +Diagnostics: +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/storable/doable_func.move:39:17 + │ +39 │ mod2::double + │ ^^^^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/storable/doable_func.move:41:17 + │ +41 │ mod1::triple + │ ^^^^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/storable/doable_func.move:43:17 + │ +43 │ move |x| mod3::multiply(4, x) + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/storable/doable_func.move:46:17 + │ +46 │ move |y| alt_multiply(x, y) + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/storable/doable_func.move:49:17 + │ +49 │ move |y| mod3::multiply(y, x) + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/storable/doable_func.move:51:17 + │ +51 │ move |x| multiply3(x, 3, 2) + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/storable/doable_func.move:53:17 + │ +53 │ move |x| mod3::multiply(x, 7) + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/storable/doable_func.move:55:17 + │ +55 │ move |x| multiply3(4, x, 2) + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/storable/doable_func.move:57:17 + │ +57 │ move |x| multiply3(3, 3, x) + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/storable/doable_func.move:61:17 + │ +61 │ move |z| multiply3(x, y, z) + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/storable/doable_func.move:64:17 + │ +64 │ move |x| alt_multiply(x, z) with copy + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/storable/doable_func.move:66:37 + │ +66 │ let g = move |x, y| mod3::multiply(x, y) with copy+drop; + │ ^^^^^^^^^^^^^^^^^^^^ + +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/storable/doable_func.move:67:26 + │ +67 │ move |x| g(x, 11) + │ ^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/storable/doable_func.move:67:17 + │ +67 │ move |x| g(x, 11) + │ ^^^^^^^^^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/storable/doable_func.move:69:25 + │ +69 │ let h = move |x| mod3::multiply(x, 12) with copy; + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/storable/doable_func.move:72:25 + │ +72 │ let i = move |x| multiply3(2, x, 2); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/storable/doable_func.move:75:25 + │ +75 │ let i = move |x, y| { let q = y - 1; 0x42::mod3::multiply(x, q + 1) }; + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/storable/doable_func.move:76:26 + │ +76 │ move |x| i(x, 15) + │ ^^^^^^^^ + +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/storable/doable_func.move:76:17 + │ +76 │ move |x| i(x, 15) + │ ^^^^^^^^^^^^^^^^^ + +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/lambda/storable/doable_func.move:78:9 + │ +78 │ f(x) + │ ^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/doable_func.move b/third_party/move/move-compiler-v2/tests/lambda/storable/doable_func.move new file mode 100644 index 0000000000000..e53e9c9d3dc45 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/doable_func.move @@ -0,0 +1,93 @@ +module 0x42::mod1 { + package fun triple(x: u64) : u64 { + x * 3 + } +} + +module 0x42::mod2 { + friend 0x42::test; + friend fun double(x: u64): u64 { + x * 2 + } +} + +module 0x42::mod3 { + public fun multiply(x: u64, y: u64): u64 { + x * y + } +} + +module 0x42::mod4 { + public fun alt_multiply(x: u64, y: u64): u64 { + x * y + } +} + +module 0x42::test { + use 0x42::mod1; + use 0x42::mod2; + use 0x42::mod3; + use 0x42::mod4::alt_multiply; + fun multiply3(x: u64, y: u64, z: u64): u64 { + x * y * z + } + + // compute ((key + 2) * x) in different ways + fun choose_function1(key: u64, x: u64): u64 { + let f = + if (key == 0) { + mod2::double + } else if (key == 1) { + mod1::triple + } else if (key == 2) { + move |x| mod3::multiply(4, x) + } else if (key == 3) { + let x = 5; + move |y| alt_multiply(x, y) + } else if (key == 4) { + let x = 6; + move |y| mod3::multiply(y, x) + } else if (key == 5) { + move |x| multiply3(x, 3, 2) + } else if (key == 6) { + move |x| mod3::multiply(x, 7) + } else if (key == 7) { + move |x| multiply3(4, x, 2) + } else if (key == 8) { + move |x| multiply3(3, 3, x) + } else if (key == 9) { + let x = 2; + let y = 5; + move |z| multiply3(x, y, z) + } else if (key == 10) { + let z = 11; + move |x| alt_multiply(x, z) with copy + } else if (key == 11) { + let g = move |x, y| mod3::multiply(x, y) with copy+drop; + move |x| g(x, 11) + } else if (key == 12) { + let h = move |x| mod3::multiply(x, 12) with copy; + move |x| { h(x) } with copy + drop + } else if (key == 14) { + let i = move |x| multiply3(2, x, 2); + move |z| i(z) + } else { + let i = move |x, y| { let q = y - 1; 0x42::mod3::multiply(x, q + 1) }; + move |x| i(x, 15) + }; + f(x) + } + + fun add_mul(x: u64, y: u64, z: u64): u64 { + z * (x + y) + } + + public fun test_functions() { + let x = 3; + + for (i in 0..15) { + let y = choose_function1(i, 3); + assert!(y == (i + 2) * x, i); + } + } +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/parse_errors.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/parse_errors.exp new file mode 100644 index 0000000000000..a10657000e3ac --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/parse_errors.exp @@ -0,0 +1,10 @@ + +Diagnostics: +error: unexpected token + ┌─ tests/lambda/storable/parse_errors.move:10:15 + │ +10 │ x.y[3](27) + │ ^ + │ │ + │ Unexpected '(' + │ Expected ';' diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/parse_errors.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/parse_errors.lambda.exp new file mode 100644 index 0000000000000..a10657000e3ac --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/parse_errors.lambda.exp @@ -0,0 +1,10 @@ + +Diagnostics: +error: unexpected token + ┌─ tests/lambda/storable/parse_errors.move:10:15 + │ +10 │ x.y[3](27) + │ ^ + │ │ + │ Unexpected '(' + │ Expected ';' diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/parse_errors.move b/third_party/move/move-compiler-v2/tests/lambda/storable/parse_errors.move new file mode 100644 index 0000000000000..2c39942fb7a24 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/parse_errors.move @@ -0,0 +1,107 @@ +module 0x42::mod1 { + package fun triple(x: u64) : u64 { + x * 3 + } +} + +module 0x42::mod2 { + friend 0x42::test; + friend fun double(x: u64): u64 { + x.y[3](27) + } +} + +module 0x42::mod3 { + public fun multiply(x: u64, y: u64): u64 { + x * y + } +} + +module 0x42::mod4 { + public fun alt_multiply(x: u64, y: u64): u64 { + x * y + } +} + +module 0x42::mod5 { + struct S { + f: u64, + y: |u64|u64 with copy, + } + fun f(s: S): S { + let x = s.y(3); + let z = S { f: 4, y: s.y }; + z + } +} + + +module 0x42::test { + use 0x42::mod1; + use 0x42::mod2; + use 0x42::mod3; + use 0x42::mod4::alt_multiply; + fun multiply3(x: u64, y: u64, z: u64): u64 { + x * y * z + } + + // compute ((key + 2) * x) in different ways + fun choose_function1(key: u64, x: u64): u64 { + let f = + if (key == 0) { + mod2::double + } else if (key == 1) { + mod1::triple + } else if (key == 2) { + move |x| mod3::multiply(4, x) + } else if (key == 3) { + let x = 5; + move |y| alt_multiply(x, y) + } else if (key == 4) { + let x = 6; + move |y| mod3::multiply(y, x) + } else if (key == 5) { + move |x| multiply3(x, 3, 2) + } else if (key == 6) { + move |x| mod3::multiply(x, 7) + } else if (key == 7) { + move |x| multiply3(4, x, 2) + } else if (key == 8) { + move |x| multiply3(3, 3, x) + } else if (key == 9) { + let x = 2; + let y = 5; + move |z| multiply3(x, y, z) + } else if (key == 10) { + let z = 11; + move |x| alt_multiply(x, z) with copy + } else if (key == 11) { + let g = move |x, y| mod3::multiply(x, y) has copy+drop; + move |x| g(x, 11) + } else if (key == 12) { + let h = move |x| mod3::multiply(x, 12) with copy; + move |x| { h(x) } with copy + drop + } else if (key == 14) { + let i = move |x| multiply3(2, x, 2); + move |z| i(z) + } else { + let i = move |x, y| { let q = y - 1; 0x42::mod3::multiply(x, q + 1) }; + move |x| i(x, 15) + }; + f(x) + } + + fun add_mul(x: u64, y: u64, z: u64): u64 { + z * (x + y) + } + + public fun test_functions() { + // let sum = vector[]; + let x = 3; + + for (i in 0..15) { + let y = choose_function1(i, 3); + assert!(y == (i + 2) * x, i); + } + } +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/registry.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/registry.exp deleted file mode 100644 index a196cfcde9c4c..0000000000000 --- a/third_party/move/move-compiler-v2/tests/lambda/storable/registry.exp +++ /dev/null @@ -1,9 +0,0 @@ - -Diagnostics: -error: unexpected token - ┌─ tests/lambda/storable/registry.move:7:22 - │ -6 │ struct Function { - │ - To match this '{' -7 │ f: |u64| u64 has store, - │ ^ Expected '}' diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/registry.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/registry.lambda.exp deleted file mode 100644 index a196cfcde9c4c..0000000000000 --- a/third_party/move/move-compiler-v2/tests/lambda/storable/registry.lambda.exp +++ /dev/null @@ -1,9 +0,0 @@ - -Diagnostics: -error: unexpected token - ┌─ tests/lambda/storable/registry.move:7:22 - │ -6 │ struct Function { - │ - To match this '{' -7 │ f: |u64| u64 has store, - │ ^ Expected '}' diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/registry.move b/third_party/move/move-compiler-v2/tests/lambda/storable/registry.move deleted file mode 100644 index a6fd8bfab655c..0000000000000 --- a/third_party/move/move-compiler-v2/tests/lambda/storable/registry.move +++ /dev/null @@ -1,109 +0,0 @@ -module 0x42::test { - struct Registry { - functions: vector<Function> - } - - struct Function { - f: |u64| u64 has store, - key: u64 - } - - enum Option<T> { - None(), - Some(T) - }; - - fun get_function(v: &vector<Function>, k: u64): Option<Function> { - mut x = Option<Function>::None; - for_each_ref(v, |f: &Function| { - if f.key == k { - x = f.f - } - }); - x - } - - fun replace_or_add_function(v: &mut vector<Function>, k: u64, f: |u64| u64 has store): Option<Function> { - mut done = false; - for_each_mut(v, |f: &mut Function| { - if f.key == k { - f.f = f; - done = true; - } - }); - if !done { - let new_record = Function { f: f, key: k }; - v.append(new_record); - } - } - - fun register(owner: &signer, f: |u64| u64 has store, k: u64) acquires Registry { - let addr = owner.address; - if !exists<Registry>(addr) { - let new_registry = Registry { - functions: vector[] - }; - move_to<Registry>(owner, registry); - } - let registry = borrow_global_mut<Registry>(addr); - replace_or_add_function(&mut registry.functions, k, f); - } - - fun invoke(addr: address, k: u64, x: u64): Option<u64> acquires Registry { - if !exists<Registry>(addr) { - return Option<u64>::None - } - let registry = borrow_global<Registry>(addr); - match get_function(registry.functions, k) { - Some(func) => { - let Function { f: f, key: key } = &func; - Some(f(x)) - }, - _ => { - Option<u64>::None - } - } - } - - fun double(x: u64):u64 { - x * 2 - } - - fun triple(x: u64):u64 { - x * 3 - } - - public fun multiply(x: u64, y: u64): u64 { - x * y - } - - fun multiply_by_x(x: u64): |u64|u64 has store { - curry(&multiply, x) - } - - - #[test(a = @0x42)] - test_registry1(a; signer) { - register(a, &double, 2); - register(a, &negate, 3); - register(a, multiply_by_x(4), 4); - register(a, multiply_by_x(5), 5); - - match invoke(a, 2, 10) { - Some(x) => { assert!(x == 20); } - _ => assert!(false); - } - match invoke(a, 3, 11) { - Some(x) => { assert!(x == 33); } - _ => assert!(false); - } - match invoke(a, 4, 2) { - Some(x) => { assert!(x == 8); } - _ => assert!(false); - } - match invoke(a, 5, 3) { - Some(x) => { assert!(x == 15); } - _ => assert!(false); - } - } -} diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/registry_errors.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/registry_errors.exp new file mode 100644 index 0000000000000..7c9e57dffddbf --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/registry_errors.exp @@ -0,0 +1,37 @@ + +Diagnostics: +error: unsupported language construct + ┌─ tests/lambda/storable/registry_errors.move:9:22 + │ +9 │ f: |u64| u64 with store, + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types + +error: unsupported language construct + ┌─ tests/lambda/storable/registry_errors.move:28:80 + │ +28 │ fun replace_or_add_function(v: &mut vector<Function>, k: u64, f: |u64| u64 with store): Option<Function> { + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types + +error: unsupported language construct + ┌─ tests/lambda/storable/registry_errors.move:42:47 + │ +42 │ fun register(owner: &signer, f: |u64| u64 with store, k: u64) acquires Registry { + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types + +error: unsupported language construct + ┌─ tests/lambda/storable/registry_errors.move:91:41 + │ +91 │ fun multiply_by_x(x: u64): |u64|u64 with store { + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types + +error: unsupported language construct + ┌─ tests/lambda/storable/registry_errors.move:95:42 + │ +95 │ fun multiply_by_x2(x: u64): |u64|u64 with store { + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types + +error: unsupported language construct + ┌─ tests/lambda/storable/registry_errors.move:96:9 + │ +96 │ move |y| multiply(x, y) + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/registry_errors.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/registry_errors.lambda.exp new file mode 100644 index 0000000000000..0cc07aff247e8 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/registry_errors.lambda.exp @@ -0,0 +1,83 @@ + +Diagnostics: +error: function type `|u64|u64 with store` is not allowed as a field type + ┌─ tests/lambda/storable/registry_errors.move:9:12 + │ +9 │ f: |u64| u64 with store, + │ ^^^^^^^^^^^^^^^^^^^^ + │ + = required by declaration of field `f` + +error: function type `|u64|u64 with store` is not allowed as a type argument (type was inferred) + ┌─ tests/lambda/storable/registry_errors.move:22:21 + │ +13 │ enum Option<T> { + │ - declaration of type parameter `T` + · +22 │ x = Option::Some(f.f) + │ ^^^^^^^^^^^^ + │ + = required by instantiating type parameter `T` of struct `Option` + +error: expected `&mut Function` but found a value of type `|u64|u64 with store` + ┌─ tests/lambda/storable/registry_errors.move:32:17 + │ +32 │ f.f = f; + │ ^^^ + +error: undeclared receiver function `append` for type `vector<Function>` + ┌─ tests/lambda/storable/registry_errors.move:38:13 + │ +38 │ v.append(new_record); + │ ^^^^^^^^^^^^^^^^^^^^ + +error: cannot return nothing from a function with result type `Option<Function>` + ┌─ tests/lambda/storable/registry_errors.move:38:33 + │ +38 │ v.append(new_record); + │ ^ + +error: cannot return nothing from a function with result type `Option<Function>` + ┌─ tests/lambda/storable/registry_errors.move:36:9 + │ +36 │ ╭ if (!done) { +37 │ │ let new_record = Function { f: f, key: k }; +38 │ │ v.append(new_record); +39 │ │ } + │ ╰─────────^ + +error: expected a struct with field `address` but found `signer` + ┌─ tests/lambda/storable/registry_errors.move:43:20 + │ +43 │ let addr = owner.address; + │ ^^^^^ + +error: undeclared `registry` + ┌─ tests/lambda/storable/registry_errors.move:48:38 + │ +48 │ move_to<Registry>(owner, registry); + │ ^^^^^^^^ + +error: cannot pass `vector<Function>` to a function which expects argument of type `&vector<Function>` + ┌─ tests/lambda/storable/registry_errors.move:68:29 + │ +68 │ match (get_function(registry.functions, k)) { + │ ^^^^^^^^^^^^^^^^^^ + +error: undeclared struct `test::Some` + ┌─ tests/lambda/storable/registry_errors.move:69:13 + │ +69 │ Some(func) => { + │ ^^^^ + +error: undeclared `func` + ┌─ tests/lambda/storable/registry_errors.move:70:52 + │ +70 │ let Function { f: f, key: key } = &func; + │ ^^^^ + +error: expected `|u64|u64 with copy+store` but found a value of type `&|u64|u64 with store` + ┌─ tests/lambda/storable/registry_errors.move:71:22 + │ +71 │ Some(f(x)) + │ ^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/registry_errors.move b/third_party/move/move-compiler-v2/tests/lambda/storable/registry_errors.move new file mode 100644 index 0000000000000..e79347c2f55ed --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/registry_errors.move @@ -0,0 +1,128 @@ +module 0x42::test { + use std::vector; + + struct Registry has key { + functions: vector<Function> + } + + struct Function has store { + f: |u64| u64 with store, + key: u64 + } + + enum Option<T> { + None(), + Some(T) + } + + fun get_function(v: &vector<Function>, k: u64): Option<Function> { + let x = Option::None(); + vector::for_each_ref(v, |f: &Function| { + if (f.key == k) { + x = Option::Some(f.f) + } + }); + x + } + + fun replace_or_add_function(v: &mut vector<Function>, k: u64, f: |u64| u64 with store): Option<Function> { + let done = false; + vector::for_each_mut(v, |f: &mut Function| { + if (f.key == k) { + f.f = f; + done = true; + } + }); + if (!done) { + let new_record = Function { f: f, key: k }; + v.append(new_record); + } + } + + fun register(owner: &signer, f: |u64| u64 with store, k: u64) acquires Registry { + let addr = owner.address; + if (!exists<Registry>(addr)) { + let new_registry = Registry { + functions: vector[] + }; + move_to<Registry>(owner, registry); + }; + let registry = borrow_global_mut<Registry>(addr); + replace_or_add_function(&mut registry.functions, k, f); + } + + fun invoke(addr: address, k: u64, x: u64): Option<u64> acquires Registry { + if (!exists<Registry>(addr)) { + return Option::None; + }; + let registry = borrow_global<Registry>(addr); + if (x == 1) { + return Option::None; + }; + if (x == 2) { + return Option::None(); + }; + if (x == 6) { + return Option::None() + }; + match (get_function(registry.functions, k)) { + Some(func) => { + let Function { f: f, key: key } = &func; + Some(f(x)) + }, + _ => { + Option::None() + } + } + } + + fun double(x: u64):u64 { + x * 2 + } + + fun triple(x: u64):u64 { + x * 3 + } + + public fun multiply(x: u64, y: u64): u64 { + x * y + } + + fun multiply_by_x(x: u64): |u64|u64 with store { + |y| multiply(x, y) + } + + fun multiply_by_x2(x: u64): |u64|u64 with store { + move |y| multiply(x, y) + } + + #[test(a = @0x42)] + fun test_registry1(a: signer) { + register(a, double, 2); + register(a, negate, 3); + register(a, multiply_by_x(4), 4); + register(a, multiply_by_x(5), 5); + register(a, multiply_by_x2(6), 6); + + match (invoke(a, 2, 10)) { + Some(x) => { assert!(x == 20); } + _ => assert!(false), + }; + match (invoke(a, 3, 11)) { + Some(x) => { assert!(x == 33); } + _ => assert!(false), + }; + match (invoke(a, 4, 2)) { + Some(x) => { assert!(x == 8); }, + _ => assert!(false), + }; + match (invoke(a, 5, 3)) { + Some(x) => { assert!(x == 15); } + _ => assert!(false), + }; + match (invoke(a, 6, 3)) { + Some(x) => { assert!(x == 18); } + _ => assert!(false), + }; + } +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/registry_ok.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/registry_ok.exp new file mode 100644 index 0000000000000..9292304f56251 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/registry_ok.exp @@ -0,0 +1,43 @@ + +Diagnostics: +error: unsupported language construct + ┌─ tests/lambda/storable/registry_ok.move:10:22 + │ +10 │ f: |u64| u64 with store+copy, + │ ^^^^^^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types + +error: unsupported language construct + ┌─ tests/lambda/storable/registry_ok.move:29:84 + │ +29 │ fun replace_or_add_function(v: &mut vector<Function>, k: u64, new_f: |u64| u64 with store+copy): Option<|u64| u64 with store+copy> { + │ ^^^^^^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types + +error: unsupported language construct + ┌─ tests/lambda/storable/registry_ok.move:29:119 + │ +29 │ fun replace_or_add_function(v: &mut vector<Function>, k: u64, new_f: |u64| u64 with store+copy): Option<|u64| u64 with store+copy> { + │ ^^^^^^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types + +error: unsupported language construct + ┌─ tests/lambda/storable/registry_ok.move:53:47 + │ +53 │ fun register(owner: &signer, f: |u64| u64 with store+copy, k: u64) acquires Registry { + │ ^^^^^^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types + +error: unsupported language construct + ┌─ tests/lambda/storable/registry_ok.move:106:41 + │ +106 │ fun multiply_by_x(x: u64): |u64|u64 with store { + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types + +error: unsupported language construct + ┌─ tests/lambda/storable/registry_ok.move:110:42 + │ +110 │ fun multiply_by_x2(x: u64): |u64|u64 with store { + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types + +error: unsupported language construct + ┌─ tests/lambda/storable/registry_ok.move:111:9 + │ +111 │ move |y| multiply(x, y) + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/registry_ok.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/registry_ok.lambda.exp new file mode 100644 index 0000000000000..cfe0567301c9b --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/registry_ok.lambda.exp @@ -0,0 +1,42 @@ + +Diagnostics: +error: function type `|u64|u64 with copy+store` is not allowed as a field type + ┌─ tests/lambda/storable/registry_ok.move:10:12 + │ +10 │ f: |u64| u64 with store+copy, + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ + = required by declaration of field `f` + +error: function type `|u64|u64 with copy+store` is not allowed as a type argument (type was inferred) + ┌─ tests/lambda/storable/registry_ok.move:23:21 + │ +14 │ enum Option<T> { + │ - declaration of type parameter `T` + · +23 │ x = Option::Some(f.f) + │ ^^^^^^^^^^^^ + │ + = required by instantiating type parameter `T` of struct `Option` + +error: function type `|u64|u64 with copy+store` is not allowed as a type argument + ┌─ tests/lambda/storable/registry_ok.move:29:109 + │ +14 │ enum Option<T> { + │ - declaration of type parameter `T` + · +29 │ fun replace_or_add_function(v: &mut vector<Function>, k: u64, new_f: |u64| u64 with store+copy): Option<|u64| u64 with store+copy> { + │ ^^^^^^^^^^^^^^^^^^^^^^^^^ + │ + = required by instantiating type parameter `T` of struct `Option` + +error: function type `|u64|u64 with copy+store` is not allowed as a type argument (type was inferred) + ┌─ tests/lambda/storable/registry_ok.move:33:26 + │ +14 │ enum Option<T> { + │ - declaration of type parameter `T` + · +33 │ result = Option::Some(f.f); + │ ^^^^^^^^^^^^ + │ + = required by instantiating type parameter `T` of struct `Option` diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/registry_ok.move b/third_party/move/move-compiler-v2/tests/lambda/storable/registry_ok.move new file mode 100644 index 0000000000000..047415e26d4ef --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/registry_ok.move @@ -0,0 +1,182 @@ +module 0x42::test { + use std::vector; + use std::signer; + + struct Registry has key { + functions: vector<Function> + } + + struct Function has store { + f: |u64| u64 with store+copy, + key: u64 + } + + enum Option<T> { + None(), + Some(T) + } + + fun get_function(v: &vector<Function>, k: u64): Option<Function> { + let x = Option::None; + vector::for_each_ref(v, |f: &Function| { + if (f.key == k) { + x = Option::Some(f.f) + } + }); + x + } + + fun replace_or_add_function(v: &mut vector<Function>, k: u64, new_f: |u64| u64 with store+copy): Option<|u64| u64 with store+copy> { + let result = Option::None; + vector::for_each_mut(v, |f: &mut Function| { + if (f.key == k) { + result = Option::Some(f.f); + f.f = new_f; + } + }); + if (result == Option::None) { + let new_record = Function { f: new_f, key: k }; + vector::push_back(v, new_record); + }; + result + } + + public fun alt_call_selected_function(v: &vector<Function>, k: u64, x: u64): Option<u64> { + for (i in 0..(vector::length(v))) { + if (v[i].key == k) { + return Option::Some((v[i].f)(x)) + } + }; + None + } + + fun register(owner: &signer, f: |u64| u64 with store+copy, k: u64) acquires Registry { + let addr = signer::address_of(owner); + if (!exists<Registry>(addr)) { + let new_registry = Registry { + functions: vector[] + }; + move_to<Registry>(owner, new_registry); + }; + let registry = borrow_global_mut<Registry>(addr); + replace_or_add_function(&mut registry.functions, k, f); + } + + fun invoke(addr: address, k: u64, x: u64): Option<u64> acquires Registry { + if (!exists<Registry>(addr)) { + return Option::None + }; + let registry = borrow_global<Registry>(addr); + match (get_function(®istry.functions, k)) { + Some(func) => { + let Function { f: f, key: key } = func; + Option::Some(f(x)) + }, + _ => { + Option::None + } + } + } + + fun invoke2(addr: address, k: u64, x: u64): Option<u64> acquires Registry { + if (!exists<Registry>(addr)) { + return Option::None + }; + let registry = borrow_global<Registry>(addr); + for (i in 0..(vector::length(®istry.functions))) { + if (registry.functions[i].key == k) { + return Option::Some((registry.functions[i].f)(x)) + } + }; + None + } + + fun double(x: u64):u64 { + x * 2 + } + + fun triple(x: u64):u64 { + x * 3 + } + + public fun multiply(x: u64, y: u64): u64 { + x * y + } + + fun multiply_by_x(x: u64): |u64|u64 with store { + |y| multiply(x, y) + } + + fun multiply_by_x2(x: u64): |u64|u64 with store { + move |y| multiply(x, y) + } + + #[test(a = @0x42)] + fun test_registry1(a: signer) { + register(a, double, 2); + register(a, negate, 3); + register(a, multiply_by_x(4), 4); + register(a, multiply_by_x(5), 5); + register(a, multiply_by_x2(6), 6); + + match (invoke(a, 2, 10)) { + Option::Some(x) => { assert!(x == 20); } + _ => assert!(false) + }; + match (invoke(a, 3, 11)) { + Option::Some(x) => { assert!(x == 33); } + _ => assert!(false) + }; + match (invoke(a, 4, 2)) { + Option::Some(x) => { assert!(x == 8); } + _ => assert!(false) + }; + match (invoke(a, 5, 3)) { + Option::Some(x) => { assert!(x == 15); } + _ => assert!(false) + }; + match (invoke(a, 6, 3)) { + Option::Some(x) => { assert!(x == 18); } + _ => assert!(false) + }; + } + + #[test(a = @0x42)] + fun test_registry2(a: signer) { + register(a, double, 2); + register(a, negate, 3); + register(a, multiply_by_x(4), 4); + register(a, multiply_by_x(5), 5); + register(a, multiply_by_x2(6), 6); + + match (invoke2(a, 2, 10)) { + Some(x) => { assert!(x == 20); } + _ => assert!(false) + }; + match (invoke2(a, 3, 11)) { + Some(x) => { assert!(x == 33); } + _ => assert!(false) + }; + match (invoke2(a, 4, 2)) { + Some(x) => { assert!(x == 8); } + _ => assert!(false) + }; + match (invoke2(a, 5, 3)) { + Some(x) => { assert!(x == 15); } + _ => assert!(false) + }; + match (invoke2(a, 6, 3)) { + Some(x) => { assert!(x == 18); } + _ => assert!(false) + }; + } + + + #[test(a = @0x42)] + fun test_registry3(a: signer) { + register(a, double, 2); + let registry = borrow_global<Registry>(a); + assert!(registry.functions[0].key == 2); + assert!((registry.functions[0].func)(3) == 6); + } +} diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/retain_funcs.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/retain_funcs.exp new file mode 100644 index 0000000000000..66d4547f944b1 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/retain_funcs.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: expected `bool` but found a value of type `integer` + ┌─ tests/lambda/storable/retain_funcs.move:6:23 + │ +6 │ let f = |x| { if (x) { 2 } else { false } }; + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/retain_funcs.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/retain_funcs.lambda.exp new file mode 100644 index 0000000000000..66d4547f944b1 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/retain_funcs.lambda.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: expected `bool` but found a value of type `integer` + ┌─ tests/lambda/storable/retain_funcs.move:6:23 + │ +6 │ let f = |x| { if (x) { 2 } else { false } }; + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/retain_funcs.move b/third_party/move/move-compiler-v2/tests/lambda/storable/retain_funcs.move new file mode 100644 index 0000000000000..81d75d4fa41ad --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/retain_funcs.move @@ -0,0 +1,20 @@ +//# publish +module 0x8675::M { + inline fun test1(r: u64): u64 { + let t = r; // t = 10 + let t2 = 0; // t2 = 0 + let f = |x| { if (x) { 2 } else { false } }; + while (r > 0) { + let x = r; // x = 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 + r = r - 1; // r = 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 + t2 = t2 + x; // t2= 10, 19, 27, 34, 40, 45, 49, 52, 54, 55 + }; + let t3 = r + t + t2; // 0 + 10 + 55 = 65 + t3 // 65 + } + public fun test(): u64 { + test1(10) + } +} + +//# run 0x8675::M::test diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.exp index 38e1020313014..bcd14792c5468 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.exp @@ -1,10 +1,187 @@ Diagnostics: -error: unexpected token - ┌─ tests/lambda/storable/return_func.move:14:41 - │ -14 │ fun multiply_by_x(x: u64): |u64|u64 has store { - │ ^^^ - │ │ - │ Unexpected 'has' - │ Expected '{' +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:20:41 + │ +20 │ fun multiply_by_x(x: u64): |u64|u64 with store { + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:21:9 + │ +21 │ move |y| multiply(x, y) with store + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:21:33 + │ +21 │ move |y| multiply(x, y) with store + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:24:46 + │ +24 │ fun choose_function(key: u64) : |u64|u64 with store { + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:34:46 + │ +34 │ fun choose_function2(key: u64): |u64|u64 with store { + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:36:13 + │ +36 │ move |x| double(x) with store + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:36:32 + │ +36 │ move |x| double(x) with store + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:38:13 + │ +38 │ move |x| triple(x) with store + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:38:32 + │ +38 │ move |x| triple(x) with store + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:41:13 + │ +41 │ move |x| f(x) with store + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:41:27 + │ +41 │ move |x| f(x) with store + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:44:13 + │ +44 │ move |x| f(x) with store + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:44:27 + │ +44 │ move |x| f(x) with store + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:46:21 + │ +46 │ let f = move |y| multiply(6, y) with store; + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:46:45 + │ +46 │ let f = move |y| multiply(6, y) with store; + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:49:13 + │ +49 │ move |y| multiply(y, 7) with store + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:49:37 + │ +49 │ move |y| multiply(y, 7) with store + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:51:21 + │ +51 │ let f = move |y| multiply(6, y) with store; + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:51:45 + │ +51 │ let f = move |y| multiply(6, y) with store; + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:52:13 + │ +52 │ move |x| f(x) with store + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:52:27 + │ +52 │ move |x| f(x) with store + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:55:13 + │ +55 │ move |x| f(x) with store + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:55:27 + │ +55 │ move |x| f(x) with store + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:57:13 + │ +57 │ move |y| multiply3(y, 3, 4) with store + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:57:41 + │ +57 │ move |y| multiply3(y, 3, 4) with store + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:61:47 + │ +61 │ fun choose_function3(key: u64) : |u64|u64 with store { + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:63:21 + │ +63 │ let f = move |x| double(x) with store; + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:63:40 + │ +63 │ let f = move |x| double(x) with store; + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:66:21 + │ +66 │ let g = move |x| triple(x) with store; + │ ^^^^ Move 2.2 language construct is not enabled: Modifier on lambda expression + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:66:40 + │ +66 │ let g = move |x| triple(x) with store; + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Abilities on function expressions + +error: unsupported language construct + ┌─ tests/lambda/storable/return_func.move:74:63 + │ +74 │ public fun test_functions(choose_function: |u64|(|u64|u64 with store)) { + │ ^^^^^^^^^^ Move 2.2 language construct is not enabled: Ability constraints on function types diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.lambda.exp index 38e1020313014..7dd9a43a5339c 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.lambda.exp +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.lambda.exp @@ -1,10 +1,47 @@ Diagnostics: -error: unexpected token - ┌─ tests/lambda/storable/return_func.move:14:41 - │ -14 │ fun multiply_by_x(x: u64): |u64|u64 has store { - │ ^^^ - │ │ - │ Unexpected 'has' - │ Expected '{' +error: type `|u64|u64 with copy` is missing required ability `store` + ┌─ tests/lambda/storable/return_func.move:26:13 + │ +26 │ double + │ ^^^^^^ + +error: type `|u64|u64 with copy` is missing required ability `store` + ┌─ tests/lambda/storable/return_func.move:28:13 + │ +28 │ triple + │ ^^^^^^ + +error: expected `|integer|_ with copy+store` but found a value of type `u64` + ┌─ tests/lambda/storable/return_func.move:85:37 + │ +85 │ vector::push_back(&mut sum, f(5)); + │ ^^^^ + +error: expected `|integer|_ with copy+store` but found a value of type `u64` + ┌─ tests/lambda/storable/return_func.move:86:37 + │ +86 │ vector::push_back(&mut sum, g(7)); + │ ^^^^ + +error: expected `|integer|_ with copy+store` but found a value of type `u64` + ┌─ tests/lambda/storable/return_func.move:87:37 + │ +87 │ vector::push_back(&mut sum, h(6)); + │ ^^^^ + +error: function type `|integer|_` is not allowed as a type argument (type was inferred) + ┌─ tests/lambda/storable/return_func.move:89:21 + │ +89 │ let funcs = vector[choose_function(0), choose_function(1), choose_function(2)]; + │ ^^^^^^ + │ + = required by instantiating vector type parameter + +error: function type `|u64|u64 with store` is not allowed as a type argument (type was inferred) + ┌─ tests/lambda/storable/return_func.move:89:21 + │ +89 │ let funcs = vector[choose_function(0), choose_function(1), choose_function(2)]; + │ ^^^^^^ + │ + = required by instantiating vector type parameter diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.move b/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.move index 4f6e078d8a460..40c0e4966cf03 100644 --- a/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.move +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/return_func.move @@ -1,4 +1,6 @@ module 0x42::test { + use std::vector; + fun double(x: u64): u64 { x * 2 } @@ -11,36 +13,57 @@ module 0x42::test { x * y } - fun multiply_by_x(x: u64): |u64|u64 has store { - curry(&multiply, x) + public fun multiply3(x: u64, y: u64, z: u64): u64 { + x * y * z + } + + fun multiply_by_x(x: u64): |u64|u64 with store { + move |y| multiply(x, y) with store } - fun choose_function(key: u64) : |u64|u64 has store { - if key == 0 { - &double - } else if key == 1 { - &triple + fun choose_function(key: u64) : |u64|u64 with store { + if (key == 0) { + double + } else if (key == 1) { + triple } else { multiply_by_x(4) } } - fun choose_function2(key: u64) : |u64|u64 has store { - if key == 0 { - |x| double(x); - } else if key == 1 { - |x| triple(x); + fun choose_function2(key: u64): |u64|u64 with store { + if (key == 0) { + move |x| double(x) with store + } else if (key == 1) { + move |x| triple(x) with store + } else if (key == 2) { + let f = multiply_by_x(4); + move |x| f(x) with store + } else if (key == 3) { + let f = multiply_by_x(5); + move |x| f(x) with store + } else if (key == 4) { + let f = move |y| multiply(6, y) with store; + f + } else if (key == 5) { + move |y| multiply(y, 7) with store + } else if (key == 6) { + let f = move |y| multiply(6, y) with store; + move |x| f(x) with store + } else if (key == 7) { + let f = multiply_by_x(5); + move |x| f(x) with store } else { - |x| multiply_by_x(4)(x) + move |y| multiply3(y, 3, 4) with store } } - fun choose_function3(key: u64) : |u64|u64 has store { - if key == 0 { - let f = |x| double(x); + fun choose_function3(key: u64) : |u64|u64 with store { + if (key == 0) { + let f = move |x| double(x) with store; f - } else if key == 1 { - let g = |x| triple(x); + } else if (key == 1) { + let g = move |x| triple(x) with store; g } else { let h = multiply_by_x(4); @@ -48,32 +71,32 @@ module 0x42::test { } } - public fun test_functions(choose_function: |u64|(|u64|u64 has store)) { - let sum = vector[]; + public fun test_functions(choose_function: |u64|(|u64|u64 with store)) { + let sum = vector<u64>[]; let x = 3; - sum.push_back(choose_function(0)(x)); - sum.push_back(choose_function(1)(x)); - sum.push_back(choose_function(2)(x)); + vector::push_back(&mut sum, (choose_function(0))(x)); + vector::push_back(&mut sum, (choose_function(1))(x)); + vector::push_back(&mut sum, (choose_function(2))(x)); let g = choose_function(1)(x); let h = choose_function(2)(x); let f = choose_function(0)(x); - sum.push_back(f(5)); - sum.push_back(g(7)); - sum.push_back(h(6)); + vector::push_back(&mut sum, f(5)); + vector::push_back(&mut sum, g(7)); + vector::push_back(&mut sum, h(6)); let funcs = vector[choose_function(0), choose_function(1), choose_function(2)]; - sum.push_back(f[0](9)); - sum.push_back(f[1](11)); - sum.push_back(f[2](13)); + vector::push_back(&mut sum, (funcs[0])(9)); + vector::push_back(&mut sum, (funcs[1])(11)); + vector::push_back(&mut sum, (funcs[2])(13)); - assert!(vector<u64>[6, 9, 12, 10, 21, 24, 18, 33, 52]) + assert!(sum == vector<u64>[6, 9, 12, 10, 21, 24, 18, 33, 52]) } public fun test_function_choosers() { - test_functions(&choose_function); - test_functions(&choose_function2); - test_functions(&choose_function3); + test_functions(choose_function); + test_functions(choose_function2); + test_functions(choose_function3); } } diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/simplifier_func.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/simplifier_func.exp new file mode 100644 index 0000000000000..cbd7f88334ab1 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/simplifier_func.exp @@ -0,0 +1,51 @@ + +Diagnostics: +warning: Unused local variable `f`. Consider removing or prefixing with an underscore: `_f` + ┌─ tests/lambda/storable/simplifier_func.move:7:13 + │ +7 │ let f = |x: u64| { let t = S { x: 3 }; x }; + │ ^ + +warning: Unused local variable `t`. Consider removing or prefixing with an underscore: `_t` + ┌─ tests/lambda/storable/simplifier_func.move:7:32 + │ +7 │ let f = |x: u64| { let t = S { x: 3 }; x }; + │ ^ + +// -- Model dump before bytecode pipeline +module 0x42::mod1 { + struct S { + x: u64, + } + public fun triple(x: u64): u64 { + { + let f: |u64|u64 with copy+store = |x: u64| { + let t: S = pack mod1::S(3); + x + }; + Mul<u64>(x, 3) + } + } +} // end 0x42::mod1 + +// -- Sourcified model before bytecode pipeline +module 0x42::mod1 { + struct S { + x: u64, + } + public fun triple(x: u64): u64 { + let f = |x| { + let t = S{x: 3}; + x + }; + x * 3 + } +} + + +Diagnostics: +error: Function-typed values not yet supported except as parameters to calls to inline functions + ┌─ tests/lambda/storable/simplifier_func.move:7:17 + │ +7 │ let f = |x: u64| { let t = S { x: 3 }; x }; + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/simplifier_func.lambda.exp b/third_party/move/move-compiler-v2/tests/lambda/storable/simplifier_func.lambda.exp new file mode 100644 index 0000000000000..233e8b77f24dd --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/simplifier_func.lambda.exp @@ -0,0 +1,206 @@ +// -- Model dump before env processor pipeline: +module 0x42::mod1 { + struct S { + x: u64, + } + public fun triple(x: u64): u64 { + { + let f: |u64|u64 with copy+store = |x: u64| { + let t: S = pack mod1::S(3); + x + }; + Mul<u64>(x, 3) + } + } +} // end 0x42::mod1 + + +// -- Model dump after env processor unused checks: +module 0x42::mod1 { + struct S { + x: u64, + } + public fun triple(x: u64): u64 { + { + let f: |u64|u64 with copy+store = |x: u64| { + let t: S = pack mod1::S(3); + x + }; + Mul<u64>(x, 3) + } + } +} // end 0x42::mod1 + + +// -- Model dump after env processor type parameter check: +module 0x42::mod1 { + struct S { + x: u64, + } + public fun triple(x: u64): u64 { + { + let f: |u64|u64 with copy+store = |x: u64| { + let t: S = pack mod1::S(3); + x + }; + Mul<u64>(x, 3) + } + } +} // end 0x42::mod1 + + +// -- Model dump after env processor check recursive struct definition: +module 0x42::mod1 { + struct S { + x: u64, + } + public fun triple(x: u64): u64 { + { + let f: |u64|u64 with copy+store = |x: u64| { + let t: S = pack mod1::S(3); + x + }; + Mul<u64>(x, 3) + } + } +} // end 0x42::mod1 + + +// -- Model dump after env processor check cyclic type instantiation: +module 0x42::mod1 { + struct S { + x: u64, + } + public fun triple(x: u64): u64 { + { + let f: |u64|u64 with copy+store = |x: u64| { + let t: S = pack mod1::S(3); + x + }; + Mul<u64>(x, 3) + } + } +} // end 0x42::mod1 + + +// -- Model dump after env processor unused struct params check: +module 0x42::mod1 { + struct S { + x: u64, + } + public fun triple(x: u64): u64 { + { + let f: |u64|u64 with copy+store = |x: u64| { + let t: S = pack mod1::S(3); + x + }; + Mul<u64>(x, 3) + } + } +} // end 0x42::mod1 + + +// -- Model dump after env processor access and use check before inlining: +module 0x42::mod1 { + struct S { + x: u64, + } + public fun triple(x: u64): u64 { + { + let f: |u64|u64 with copy+store = |x: u64| { + let t: S = pack mod1::S(3); + x + }; + Mul<u64>(x, 3) + } + } +} // end 0x42::mod1 + + +// -- Model dump after env processor inlining: +module 0x42::mod1 { + struct S { + x: u64, + } + public fun triple(x: u64): u64 { + { + let f: |u64|u64 with copy+store = |x: u64| { + let t: S = pack mod1::S(3); + x + }; + Mul<u64>(x, 3) + } + } +} // end 0x42::mod1 + + +// -- Model dump after env processor access and use check after inlining: +module 0x42::mod1 { + struct S { + x: u64, + } + public fun triple(x: u64): u64 { + { + let f: |u64|u64 with copy+store = |x: u64| { + let t: S = pack mod1::S(3); + x + }; + Mul<u64>(x, 3) + } + } +} // end 0x42::mod1 + + +// -- Model dump after env processor acquires check: +module 0x42::mod1 { + struct S { + x: u64, + } + public fun triple(x: u64): u64 { + { + let f: |u64|u64 with copy+store = |x: u64| { + let t: S = pack mod1::S(3); + x + }; + Mul<u64>(x, 3) + } + } +} // end 0x42::mod1 + + +// -- Model dump after env processor simplifier: +module 0x42::mod1 { + struct S { + x: u64, + } + public fun triple(x: u64): u64 { + { + let f: |u64|u64 with copy+store = |x: u64| { + let t: S = pack mod1::S(3); + x + }; + Mul<u64>(x, 3) + } + } +} // end 0x42::mod1 + + + +Diagnostics: +warning: Unused local variable `f`. Consider removing or prefixing with an underscore: `_f` + ┌─ tests/lambda/storable/simplifier_func.move:7:13 + │ +7 │ let f = |x: u64| { let t = S { x: 3 }; x }; + │ ^ + +warning: Unused local variable `t`. Consider removing or prefixing with an underscore: `_t` + ┌─ tests/lambda/storable/simplifier_func.move:7:32 + │ +7 │ let f = |x: u64| { let t = S { x: 3 }; x }; + │ ^ + +error: Currently, lambda expressions must explicitly declare `move` capture of free variables, except when appearing as an argument to an inline function call. + ┌─ tests/lambda/storable/simplifier_func.move:7:17 + │ +7 │ let f = |x: u64| { let t = S { x: 3 }; x }; + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/lambda/storable/simplifier_func.move b/third_party/move/move-compiler-v2/tests/lambda/storable/simplifier_func.move new file mode 100644 index 0000000000000..a418d25cf855a --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/lambda/storable/simplifier_func.move @@ -0,0 +1,10 @@ +module 0x42::mod1 { + struct S { // no drop + x: u64 + } + + public fun triple(x: u64) : u64 { + let f = |x: u64| { let t = S { x: 3 }; x }; + x * 3 + } +} diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression.exp index eb41afe8197db..83950af3cd058 100644 --- a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression.exp +++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression.exp @@ -1,10 +1,19 @@ Diagnostics: -error: unexpected token - ┌─ tests/more-v1/parser/invalid_call_lhs_complex_expression.move:3:29 +error: expected `|()|_` but found a value of type `integer` + ┌─ tests/more-v1/parser/invalid_call_lhs_complex_expression.move:3:20 │ 3 │ (if (true) 5 else 0)(); - │ ^ - │ │ - │ Unexpected '(' - │ Expected ';' + │ ^ + +error: expected `|()|_` but found a value of type `integer` + ┌─ tests/more-v1/parser/invalid_call_lhs_complex_expression.move:3:27 + │ +3 │ (if (true) 5 else 0)(); + │ ^ + +error: expected `|(integer, integer)|_` but found a value of type `()` + ┌─ tests/more-v1/parser/invalid_call_lhs_complex_expression.move:4:9 + │ +4 │ (while (false) {})(0, 1); + │ ^^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression2.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression2.exp index 03ed8ceb2af6f..6e260fff7fec5 100644 --- a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression2.exp +++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_complex_expression2.exp @@ -1,10 +1,19 @@ Diagnostics: -error: unexpected token - ┌─ tests/more-v1/parser/invalid_call_lhs_complex_expression2.move:3:29 +error: expected `|()|_` but found a value of type `integer` + ┌─ tests/more-v1/parser/invalid_call_lhs_complex_expression2.move:3:20 │ 3 │ (if (true) 5 else 0)(); - │ ^ - │ │ - │ Unexpected '(' - │ Expected ';' + │ ^ + +error: expected `|()|_` but found a value of type `integer` + ┌─ tests/more-v1/parser/invalid_call_lhs_complex_expression2.move:3:27 + │ +3 │ (if (true) 5 else 0)(); + │ ^ + +error: expected `|(integer, integer)|_` but found a value of type `()` + ┌─ tests/more-v1/parser/invalid_call_lhs_complex_expression2.move:4:9 + │ +4 │ (while (false) {})(0, 1); + │ ^^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name.exp index 222dec853b372..8d362e905076d 100644 --- a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name.exp +++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name.exp @@ -1,10 +1,7 @@ Diagnostics: -error: unexpected token - ┌─ tests/more-v1/parser/invalid_call_lhs_parens_around_name.move:3:14 +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/more-v1/parser/invalid_call_lhs_parens_around_name.move:3:9 │ 3 │ (foo)() - │ ^ - │ │ - │ Unexpected '(' - │ Expected ';' + │ ^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name2.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name2.exp index f47f13fe5ecb6..7429935364695 100644 --- a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name2.exp +++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_parens_around_name2.exp @@ -1,10 +1,7 @@ Diagnostics: -error: unexpected token - ┌─ tests/more-v1/parser/invalid_call_lhs_parens_around_name2.move:3:14 +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/more-v1/parser/invalid_call_lhs_parens_around_name2.move:3:9 │ 3 │ (foo)() - │ ^ - │ │ - │ Unexpected '(' - │ Expected ';' + │ ^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return.exp index 332165ecd3108..4890ecb1afef1 100644 --- a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return.exp +++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return.exp @@ -1,10 +1,7 @@ Diagnostics: -error: unexpected token - ┌─ tests/more-v1/parser/invalid_call_lhs_return.move:3:20 +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/more-v1/parser/invalid_call_lhs_return.move:3:9 │ 3 │ (return ())(0, 1); - │ ^ - │ │ - │ Unexpected '(' - │ Expected ';' + │ ^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return2.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return2.exp index b9972c50113c3..9b0ec32618792 100644 --- a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return2.exp +++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_return2.exp @@ -1,10 +1,7 @@ Diagnostics: -error: unexpected token - ┌─ tests/more-v1/parser/invalid_call_lhs_return2.move:3:20 +error: Calls to function values other than inline function parameters not yet supported + ┌─ tests/more-v1/parser/invalid_call_lhs_return2.move:3:9 │ 3 │ (return ())(0, 1); - │ ^ - │ │ - │ Unexpected '(' - │ Expected ';' + │ ^^^^^^^^^^^^^^^^^ diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value.exp index d17d58623b224..6df708c2205eb 100644 --- a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value.exp +++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value.exp @@ -1,10 +1,13 @@ Diagnostics: -error: unexpected token - ┌─ tests/more-v1/parser/invalid_call_lhs_value.move:3:10 +error: expected `|()|_` but found a value of type `integer` + ┌─ tests/more-v1/parser/invalid_call_lhs_value.move:3:9 │ 3 │ 5(); - │ ^ - │ │ - │ Unexpected '(' - │ Expected ';' + │ ^ + +error: expected `|(integer, integer)|_` but found a value of type `integer` + ┌─ tests/more-v1/parser/invalid_call_lhs_value.move:4:9 + │ +4 │ 5(0, 1); + │ ^ diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value2.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value2.exp index e2f3d92b38d92..34a3e9e9a6b5b 100644 --- a/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value2.exp +++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/invalid_call_lhs_value2.exp @@ -1,10 +1,13 @@ Diagnostics: -error: unexpected token - ┌─ tests/more-v1/parser/invalid_call_lhs_value2.move:3:10 +error: expected `|()|_` but found a value of type `integer` + ┌─ tests/more-v1/parser/invalid_call_lhs_value2.move:3:9 │ 3 │ 5(); - │ ^ - │ │ - │ Unexpected '(' - │ Expected ';' + │ ^ + +error: expected `|(integer, integer)|_` but found a value of type `integer` + ┌─ tests/more-v1/parser/invalid_call_lhs_value2.move:4:9 + │ +4 │ 5(0, 1); + │ ^ diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/spec_parsing_ok.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/spec_parsing_ok.exp index 729c903a835a0..bec31b588f3e5 100644 --- a/third_party/move/move-compiler-v2/tests/more-v1/parser/spec_parsing_ok.exp +++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/spec_parsing_ok.exp @@ -48,7 +48,7 @@ error: expression construct not supported in specifications 69 │ ensures RET = {let y = x; y + 1}; │ ^^^^^^^^^^^^^^^^^^^^^^^^ -error: cannot pass `|(num, num)|num` to a function which expects argument of type `|(num, num)|bool` +error: cannot pass `|(num, num)|num with copy+store` to a function which expects argument of type `|(num, num)|bool` ┌─ tests/more-v1/parser/spec_parsing_ok.move:77:24 │ 77 │ ensures all(x, |y, z| x + y + z); diff --git a/third_party/move/move-compiler-v2/tests/more-v1/parser/unexpected_token_after_ability_function_constraint.exp b/third_party/move/move-compiler-v2/tests/more-v1/parser/unexpected_token_after_ability_function_constraint.exp index b9eafd1f9f753..9808aa198bb4b 100644 --- a/third_party/move/move-compiler-v2/tests/more-v1/parser/unexpected_token_after_ability_function_constraint.exp +++ b/third_party/move/move-compiler-v2/tests/more-v1/parser/unexpected_token_after_ability_function_constraint.exp @@ -4,7 +4,6 @@ error: unexpected token ┌─ tests/more-v1/parser/unexpected_token_after_ability_function_constraint.move:4:21 │ 4 │ fun foo<T: copy & drop>() {} - │ ^ - │ │ - │ Unexpected '&' - │ Expected one of: '+', '>', or ',' + │ - ^ Expected '>' + │ │ + │ To match this '<' diff --git a/third_party/move/move-compiler-v2/tests/testsuite.rs b/third_party/move/move-compiler-v2/tests/testsuite.rs index acbab3106d398..eff9be3737cf6 100644 --- a/third_party/move/move-compiler-v2/tests/testsuite.rs +++ b/third_party/move/move-compiler-v2/tests/testsuite.rs @@ -174,7 +174,8 @@ const TEST_CONFIGS: Lazy<BTreeMap<&str, TestConfig>> = Lazy::new(|| { .set_experiment(Experiment::LAMBDA_IN_PARAMS, true) .set_experiment(Experiment::LAMBDA_IN_RETURNS, true) .set_experiment(Experiment::LAMBDA_VALUES, true) - .set_experiment(Experiment::LAMBDA_LIFTING, true), + .set_experiment(Experiment::LAMBDA_LIFTING, true) + .set_language_version(LanguageVersion::V2_LAMBDA), stop_after: StopAfter::FileFormat, dump_ast: DumpLevel::AllStages, dump_bytecode: DumpLevel::EndStage, diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/multi_param_typed.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/multi_param_typed.exp index a4bb458cc6f57..e368f5af7f888 100644 --- a/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/multi_param_typed.exp +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/inlining/multi_param_typed.exp @@ -24,7 +24,7 @@ comparison between v1 and v2 failed: = - error[E01013]: unsupported language construct - ┌─ TEMPFILE:24:73 -+ error: cannot pass `|(u64, u64)|integer` to a function which expects argument of type `|(&integer, &mut integer)|u64` ++ error: cannot pass `|(u64, u64)|integer with copy+store` to a function which expects argument of type `|(&integer, &mut integer)|u64` + ┌─ TEMPFILE:24:64 = │ = 24 │ assert!(elem_for_each_ref(&mut vector[Elem{k:1, v:2}], |x: u64, y: u64| *x + *y) == 3, 0) diff --git a/third_party/move/move-compiler/src/expansion/ast.rs b/third_party/move/move-compiler/src/expansion/ast.rs index 47db86f2654ba..8a241a6091ae3 100644 --- a/third_party/move/move-compiler/src/expansion/ast.rs +++ b/third_party/move/move-compiler/src/expansion/ast.rs @@ -6,8 +6,8 @@ use crate::{ expansion::translate::is_valid_struct_constant_or_schema_name, parser::ast::{ self as P, Ability, Ability_, BinOp, CallKind, ConstantName, Field, FunctionName, Label, - ModuleName, QuantKind, SpecApplyPattern, StructName, UnaryOp, UseDecl, Var, VariantName, - ENTRY_MODIFIER, + LambdaCaptureKind, ModuleName, QuantKind, SpecApplyPattern, StructName, UnaryOp, UseDecl, + Var, VariantName, ENTRY_MODIFIER, }, shared::{ ast_debug::*, @@ -401,7 +401,7 @@ pub enum Type_ { Multiple(Vec<Type>), Apply(ModuleAccess, Vec<Type>), Ref(bool, Box<Type>), - Fun(Vec<Type>, Box<Type>), + Fun(Vec<Type>, Box<Type>, AbilitySet), UnresolvedError, } pub type Type = Spanned<Type_>; @@ -498,6 +498,7 @@ pub enum Exp_ { Name(ModuleAccess, Option<Vec<Type>>), Call(ModuleAccess, CallKind, Option<Vec<Type>>, Spanned<Vec<Exp>>), + ExpCall(Box<Exp>, Spanned<Vec<Exp>>), Pack(ModuleAccess, Option<Vec<Type>>, Fields<Exp>), Vector(Loc, Option<Vec<Type>>, Spanned<Vec<Exp>>), @@ -506,7 +507,7 @@ pub enum Exp_ { While(Option<Label>, Box<Exp>, Box<Exp>), Loop(Option<Label>, Box<Exp>), Block(Sequence), - Lambda(TypedLValueList, Box<Exp>), + Lambda(TypedLValueList, Box<Exp>, LambdaCaptureKind, AbilitySet), Quant( QuantKind, LValueWithRangeList, @@ -908,6 +909,17 @@ impl fmt::Display for Visibility { } } +impl fmt::Display for AbilitySet { + fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result { + if !self.is_empty() { + write!(f, ": ")?; + write!(f, "{}", format_delim(self, "+")) + } else { + Ok(()) + } + } +} + impl fmt::Display for Type_ { fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result { use Type_::*; @@ -916,19 +928,18 @@ impl fmt::Display for Type_ { Apply(n, tys) => { write!(f, "{}", n)?; if !tys.is_empty() { - write!(f, "<")?; - write!(f, "{}", format_comma(tys))?; - write!(f, ">")?; + write!(f, "<{}>", format_comma(tys)) + } else { + Ok(()) } - Ok(()) }, Ref(mut_, ty) => write!(f, "&{}{}", if *mut_ { "mut " } else { "" }, ty), - Fun(args, result) => write!(f, "({}):{}", format_comma(args), result), + Fun(args, result, abilities) => { + write!(f, "({}):{}{}", format_comma(args), result, abilities) + }, Unit => write!(f, "()"), Multiple(tys) => { - write!(f, "(")?; - write!(f, "{}", format_comma(tys))?; - write!(f, ")") + write!(f, "({})", format_comma(tys)) }, } } @@ -1444,11 +1455,12 @@ impl AstDebug for Type_ { } s.ast_debug(w) }, - Type_::Fun(args, result) => { + Type_::Fun(args, result, abilities) => { w.write("|"); w.comma(args, |w, ty| ty.ast_debug(w)); w.write("|"); result.ast_debug(w); + ability_constraints_ast_debug(w, abilities); }, Type_::UnresolvedError => w.write("_|_"), } @@ -1609,6 +1621,12 @@ impl AstDebug for Exp_ { w.comma(rhs, |w, e| e.ast_debug(w)); w.write(")"); }, + E::ExpCall(fexp, sp!(_, rhs)) => { + fexp.ast_debug(w); + w.write("("); + w.comma(rhs, |w, e| e.ast_debug(w)); + w.write(")"); + }, E::Pack(ma, tys_opt, fields) => { ma.ast_debug(w); if let Some(ss) = tys_opt { @@ -1674,11 +1692,15 @@ impl AstDebug for Exp_ { } }, E::Block(seq) => w.block(|w| seq.ast_debug(w)), - E::Lambda(sp!(_, bs), e) => { + E::Lambda(sp!(_, bs), e, capture_kind, abilities) => { + if *capture_kind != LambdaCaptureKind::Default { + w.write(format!(" {}", capture_kind)); + } w.write("|"); bs.ast_debug(w); w.write("|"); e.ast_debug(w); + ability_constraints_ast_debug(w, abilities) }, E::Quant(kind, sp!(_, rs), trs, c_opt, e) => { kind.ast_debug(w); diff --git a/third_party/move/move-compiler/src/expansion/dependency_ordering.rs b/third_party/move/move-compiler/src/expansion/dependency_ordering.rs index 732161adb2bc5..c18086f59d530 100644 --- a/third_party/move/move-compiler/src/expansion/dependency_ordering.rs +++ b/third_party/move/move-compiler/src/expansion/dependency_ordering.rs @@ -373,7 +373,7 @@ fn type_(context: &mut Context, sp!(_, ty_): &E::Type) { types(context, tys); }, T::Multiple(tys) => types(context, tys), - T::Fun(tys, ret_ty) => { + T::Fun(tys, ret_ty, _abilities) => { types(context, tys); type_(context, ret_ty) }, @@ -451,6 +451,10 @@ fn exp(context: &mut Context, sp!(_loc, e_): &E::Exp) { types_opt(context, tys_opt); args_.iter().for_each(|e| exp(context, e)) }, + E::ExpCall(fexp, sp!(_, args_)) => { + exp(context, fexp); + args_.iter().for_each(|e| exp(context, e)) + }, E::Pack(ma, tys_opt, fields) => { module_access(context, ma); types_opt(context, tys_opt); @@ -512,7 +516,7 @@ fn exp(context: &mut Context, sp!(_loc, e_): &E::Exp) { tys.iter().for_each(|ty| type_(context, ty)) }, - E::Lambda(ll, e) => { + E::Lambda(ll, e, _capture_kind, _abilities) => { use crate::expansion::ast::TypedLValue_; let mapped = ll.value.iter().map(|sp!(_, TypedLValue_(lv, _opt_ty))| lv); lvalues(context, mapped); diff --git a/third_party/move/move-compiler/src/expansion/translate.rs b/third_party/move/move-compiler/src/expansion/translate.rs index b8ea685e454d7..fdd72da1469f7 100644 --- a/third_party/move/move-compiler/src/expansion/translate.rs +++ b/third_party/move/move-compiler/src/expansion/translate.rs @@ -2243,10 +2243,11 @@ fn type_(context: &mut Context, sp!(loc, pt_): P::Type) -> E::Type { } }, PT::Ref(mut_, inner) => ET::Ref(mut_, Box::new(type_(context, *inner))), - PT::Fun(args, result) => { + PT::Fun(args, result, abilities_vec) => { let args = types(context, args); let result = type_(context, *result); - ET::Fun(args, Box::new(result)) + let abilities = ability_set(context, "modifier", abilities_vec); + ET::Fun(args, Box::new(result), abilities) }, }; sp(loc, t_) @@ -2561,6 +2562,11 @@ fn exp_(context: &mut Context, sp!(loc, pe_): P::Exp) -> E::Exp { }, } }, + PE::ExpCall(boxed_fexp, sp!(rloc, args)) => { + let e_fexp = exp(context, *boxed_fexp); + let e_args = sp(rloc, exps(context, args)); + EE::ExpCall(e_fexp, e_args) + }, PE::Pack(pn, ptys_opt, pfields) => { let en_opt = name_access_chain( context, @@ -2623,11 +2629,12 @@ fn exp_(context: &mut Context, sp!(loc, pe_): P::Exp) -> E::Exp { PE::While(label, pb, ploop) => EE::While(label, exp(context, *pb), exp(context, *ploop)), PE::Loop(label, ploop) => EE::Loop(label, exp(context, *ploop)), PE::Block(seq) => EE::Block(sequence(context, loc, seq)), - PE::Lambda(pbs, pe) => { + PE::Lambda(pbs, pe, capture_kind, abilities_vec) => { let tbs_opt = typed_bind_list(context, pbs); let e = exp_(context, *pe); + let abilities = ability_set(context, "lambda expression", abilities_vec); match tbs_opt { - Some(tbs) => EE::Lambda(tbs, Box::new(e)), + Some(tbs) => EE::Lambda(tbs, Box::new(e), capture_kind, abilities), None => { assert!(context.env.has_errors()); EE::UnresolvedError @@ -3326,6 +3333,10 @@ fn unbound_names_exp(unbound: &mut UnboundNames, sp!(_, e_): &E::Exp) { } unbound_names_exps(unbound, es_); }, + EE::ExpCall(fexp, sp!(_, es_)) => { + unbound_names_exp(unbound, fexp); + unbound_names_exps(unbound, es_); + }, EE::Vector(_, _, sp!(_, es_)) => unbound_names_exps(unbound, es_), EE::Pack(_, _, es) => unbound_names_exps(unbound, es.iter().map(|(_, _, (_, e))| e)), EE::IfElse(econd, et, ef) => { @@ -3350,7 +3361,7 @@ fn unbound_names_exp(unbound: &mut UnboundNames, sp!(_, e_): &E::Exp) { EE::Loop(_, eloop) => unbound_names_exp(unbound, eloop), EE::Block(seq) => unbound_names_sequence(unbound, seq), - EE::Lambda(ls, er) => { + EE::Lambda(ls, er, _capture_kind, _abilities) => { unbound_names_exp(unbound, er); // remove anything in `ls` unbound_names_typed_binds(unbound, ls); diff --git a/third_party/move/move-compiler/src/naming/translate.rs b/third_party/move/move-compiler/src/naming/translate.rs index ee37a1d68a8ac..7d9f03c0df593 100644 --- a/third_party/move/move-compiler/src/naming/translate.rs +++ b/third_party/move/move-compiler/src/naming/translate.rs @@ -807,7 +807,7 @@ fn type_(context: &mut Context, sp!(loc, ety_): E::Type) -> N::Type { } }, }, - ET::Fun(args, result) => { + ET::Fun(args, result, _abilities) => { let mut args = types(context, args); args.push(type_(context, *result)); NT::builtin_(sp(loc, N::BuiltinTypeName_::Fun), args) @@ -941,7 +941,7 @@ fn exp_(context: &mut Context, e: E::Exp) -> N::Exp { EE::While(_, eb, el) => NE::While(exp(context, *eb), exp(context, *el)), EE::Loop(_, el) => NE::Loop(exp(context, *el)), EE::Block(seq) => NE::Block(sequence(context, seq)), - EE::Lambda(args, body) => { + EE::Lambda(args, body, _lambda_capture_kind, _abilities) => { let bind_opt = bind_typed_list(context, args); match bind_opt { None => { @@ -1088,6 +1088,23 @@ fn exp_(context: &mut Context, e: E::Exp) -> N::Exp { }, } }, + EE::ExpCall(efunc, eargs, ..) => { + let nfunc = exp(context, *efunc); + let nargs = call_args(context, eargs); + match *nfunc { + sp!(_loc, NE::Use(Var(v))) => NE::VarCall(Var(v), nargs), + sp!(loc, _) => { + context.env.add_diag(diag!( + Syntax::UnsupportedLanguageItem, + ( + loc, + "Calls through computed functions not supported by this compiler" + ) + )); + NE::UnresolvedError + }, + } + }, EE::Vector(vec_loc, tys_opt, rhs) => { let ty_args = tys_opt.map(|tys| types(context, tys)); let nes = call_args(context, rhs); diff --git a/third_party/move/move-compiler/src/parser/ast.rs b/third_party/move/move-compiler/src/parser/ast.rs index 86be3a5cdcdd2..1981d00013cb9 100644 --- a/third_party/move/move-compiler/src/parser/ast.rs +++ b/third_party/move/move-compiler/src/parser/ast.rs @@ -487,8 +487,8 @@ pub enum Type_ { // &t // &mut t Ref(bool, Box<Type>), - // (t1,...,tn):t - Fun(Vec<Type>, Box<Type>), + // |t1,...,tn|t with store+copy + Fun(Vec<Type>, Box<Type>, Vec<Ability>), // () Unit, // (t1, t2, ... , tn) @@ -645,6 +645,31 @@ pub enum CallKind { Receiver, } +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Default)] +pub enum LambdaCaptureKind { + /// Direct use (e.g., inlining) + #[default] + Default, + /// Copy + Copy, + /// Move + Move, +} + +impl fmt::Display for LambdaCaptureKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + LambdaCaptureKind::Default => { + write!(f, "") + }, + LambdaCaptureKind::Copy => { + write!(f, "copy") + }, + LambdaCaptureKind::Move => write!(f, "move"), + } + } +} + #[derive(Debug, Clone, PartialEq)] #[allow(clippy::large_enum_variant)] pub enum Exp_ { @@ -666,6 +691,9 @@ pub enum Exp_ { Spanned<Vec<Exp>>, ), + // e(earg,* [..]?) + ExpCall(Box<Exp>, Spanned<Vec<Exp>>), + // tn {f1: e1, ... , f_n: e_n } Pack(NameAccessChain, Option<Vec<Type>>, Vec<(Field, Exp)>), @@ -688,8 +716,8 @@ pub enum Exp_ { // { seq } Block(Sequence), - // | x1 [: t1], ..., xn [: tn] | e - Lambda(TypedBindList, Box<Exp>), + // | x1 [: t1], ..., xn [: tn] | e [ with <abilities> ] + Lambda(TypedBindList, Box<Exp>, LambdaCaptureKind, Vec<Ability>), // forall/exists x1 : e1, ..., xn [{ t1, .., tk } *] [where cond]: en. Quant( QuantKind, @@ -1733,11 +1761,12 @@ impl AstDebug for Type_ { } s.ast_debug(w) }, - Type_::Fun(args, result) => { + Type_::Fun(args, result, abilities) => { w.write("("); w.comma(args, |w, ty| ty.ast_debug(w)); w.write("):"); result.ast_debug(w); + ability_constraints_ast_debug(w, abilities); }, } } @@ -1834,6 +1863,12 @@ impl AstDebug for Exp_ { w.comma(rhs, |w, e| e.ast_debug(w)); w.write(")"); }, + E::ExpCall(arg, sp!(_, rhs)) => { + arg.ast_debug(w); + w.write("("); + w.comma(rhs, |w, e| e.ast_debug(w)); + w.write(")"); + }, E::Pack(ma, tys_opt, fields) => { ma.ast_debug(w); if let Some(ss) = tys_opt { @@ -1900,11 +1935,21 @@ impl AstDebug for Exp_ { e.ast_debug(w); }, E::Block(seq) => w.block(|w| seq.ast_debug(w)), - E::Lambda(sp!(_, tbs), e) => { + E::Lambda(sp!(_, tbs), e, capture_kind, abilities) => { + if *capture_kind != LambdaCaptureKind::Default { + w.write(format!("{} ", capture_kind)); + } w.write("|"); tbs.ast_debug(w); w.write("|"); e.ast_debug(w); + if !abilities.is_empty() { + w.write(" with "); + w.list(abilities, ", ", |w, ab_mod| { + ab_mod.ast_debug(w); + false + }); + } }, E::Quant(kind, sp!(_, rs), trs, c_opt, e) => { kind.ast_debug(w); diff --git a/third_party/move/move-compiler/src/parser/syntax.rs b/third_party/move/move-compiler/src/parser/syntax.rs index 98071ea2b7a16..e093ffde9fd67 100644 --- a/third_party/move/move-compiler/src/parser/syntax.rs +++ b/third_party/move/move-compiler/src/parser/syntax.rs @@ -90,6 +90,23 @@ fn require_move_2(context: &mut Context, loc: Loc, description: &str) -> bool { ) } +fn require_move_version( + min_language_version: LanguageVersion, + context: &mut Context, + loc: Loc, + description: &str, +) -> bool { + require_language_version_msg( + context, + loc, + min_language_version, + &format!( + "Move {} language construct is not enabled: {}", + min_language_version, description + ), + ) +} + fn require_language_version( context: &mut Context, loc: Loc, @@ -132,6 +149,21 @@ fn require_move_2_and_advance( Ok(require_move_2(context, loc, description)) } +fn require_move_version_and_advance( + min_language_version: LanguageVersion, + context: &mut Context, + description: &str, +) -> Result<bool, Box<Diagnostic>> { + let loc = current_token_loc(context.tokens); + context.tokens.advance()?; + Ok(require_move_version( + min_language_version, + context, + loc, + description, + )) +} + pub fn make_loc(file_hash: FileHash, start: usize, end: usize) -> Loc { Loc::new(file_hash, start as u32, end as u32) } @@ -1131,6 +1163,7 @@ fn parse_sequence(context: &mut Context) -> Result<Sequence, Box<Diagnostic>> { // | "abort" <Exp> // | "for" "(" <Exp> "in" <Exp> ".." <Exp> ")" "{" <Exp> "}" // | <NameExp> +// | <Term> <CallArgs> // --> ExpCall fn parse_term(context: &mut Context) -> Result<Exp, Box<Diagnostic>> { const VECTOR_IDENT: &str = "vector"; const FOR_IDENT: &str = "for"; @@ -1286,12 +1319,14 @@ fn parse_term(context: &mut Context) -> Result<Exp, Box<Diagnostic>> { }, }; let end_loc = context.tokens.previous_end_loc(); - Ok(spanned( - context.tokens.file_hash(), - start_loc, - end_loc, - term, - )) + let mut result_term = spanned(context.tokens.file_hash(), start_loc, end_loc, term); + while matches!(context.tokens.peek(), Tok::LParen) { + let args = parse_call_args(context)?; + let term = Exp_::ExpCall(Box::new(result_term), args); + let end_loc = context.tokens.previous_end_loc(); + result_term = spanned(context.tokens.file_hash(), start_loc, end_loc, term); + } + Ok(result_term) } fn parse_cast_or_test_exp( @@ -1842,6 +1877,7 @@ fn parse_name_exp(context: &mut Context) -> Result<Exp_, Box<Diagnostic>> { // Parse the arguments to a call: // CallArgs = // "(" Comma<Exp> ")" +// Result is a list <args> fn parse_call_args(context: &mut Context) -> Result<Spanned<Vec<Exp>>, Box<Diagnostic>> { let start_loc = context.tokens.start_loc(); let args = parse_comma_list( @@ -1901,9 +1937,43 @@ fn at_start_of_exp(context: &mut Context) -> bool { ) } +// Parse the rest of a lambda expression, after already processing any capture designator (move/copy). +// LambdaRest = +// <LambdaBindList> <Exp> <WithAbilities> +fn parse_lambda( + context: &mut Context, + start_loc: usize, + capture_kind: LambdaCaptureKind, + token: Tok, +) -> Result<Exp_, Box<Diagnostic>> { + let bindings = if token == Tok::Pipe { + parse_lambda_bind_list(context)? + } else { + // token is Tok::PipePipe, i.e., empty bind list in this context. + consume_token(context.tokens, Tok::PipePipe)?; + let end_loc = context.tokens.previous_end_loc(); + spanned(context.tokens.file_hash(), start_loc, end_loc, vec![]) + }; + let body = Box::new(parse_exp(context)?); + let abilities_start = context.tokens.start_loc(); + let abilities = parse_with_abilities(context)?; + if !abilities.is_empty() { + let abilities_end = context.tokens.previous_end_loc(); + let loc = make_loc(context.tokens.file_hash(), abilities_start, abilities_end); + require_move_version( + LanguageVersion::V2_2, + context, + loc, + "Abilities on function expressions", + ); + } + + Ok(Exp_::Lambda(bindings, body, capture_kind, abilities)) +} + // Parse an expression: // Exp = -// <LambdaBindList> <Exp> +// ( "move" | "copy" )? <LambdaBindList> <Exp> <WithAbilities> // | <Quantifier> spec only // | <BinOpExp> // | <UnaryExp> "=" <Exp> @@ -1913,16 +1983,33 @@ fn parse_exp(context: &mut Context) -> Result<Exp, Box<Diagnostic>> { let start_loc = context.tokens.start_loc(); let token = context.tokens.peek(); let exp = match token { - Tok::Pipe | Tok::PipePipe => { - let bindings = if token == Tok::Pipe { - parse_lambda_bind_list(context)? - } else { - // token is Tok::PipePipe, i.e., empty bind list in this context. - consume_token(context.tokens, Tok::PipePipe)?; - spanned(context.tokens.file_hash(), start_loc, start_loc + 1, vec![]) + Tok::Move | Tok::Copy + if matches!( + context.tokens.lookahead_with_start_loc(), + Ok((Tok::Pipe | Tok::PipePipe, _)) + ) => + { + let _ = require_move_version_and_advance( + LanguageVersion::V2_2, + context, + "Modifier on lambda expression", + ); // consume the Move/Copy + let capture_kind = match token { + Tok::Move => LambdaCaptureKind::Move, + Tok::Copy => LambdaCaptureKind::Copy, + _ => { + panic!("can't happen"); + }, }; - let body = Box::new(parse_exp(context)?); - Exp_::Lambda(bindings, body) + parse_lambda( + context, + context.tokens.start_loc(), + capture_kind, + context.tokens.peek(), + )? + }, + Tok::Pipe | Tok::PipePipe => { + parse_lambda(context, start_loc, LambdaCaptureKind::default(), token)? }, Tok::Identifier if is_quant(context) => parse_quant(context)?, _ => { @@ -2118,7 +2205,7 @@ fn parse_binop_exp(context: &mut Context, lhs: Exp, min_prec: u32) -> Result<Exp // | "*" <UnaryExp> // | "move" <Var> // | "copy" <Var> -// | <DotOrIndexChain> +// | <DotOrIndexOrCallChain> fn parse_unary_exp(context: &mut Context) -> Result<Exp, Box<Diagnostic>> { let start_loc = context.tokens.start_loc(); let exp = match context.tokens.peek() { @@ -2165,7 +2252,8 @@ fn parse_unary_exp(context: &mut Context) -> Result<Exp, Box<Diagnostic>> { Ok(spanned(context.tokens.file_hash(), start_loc, end_loc, exp)) } -// Parse an expression term optionally followed by a chain of dot or index accesses: +// Parse an expression term optionally followed by a chain of dot accesses and/or index accesses +// and/or calls of function values. // DotOrIndexChain = // <DotOrIndexChain> "." <Identifier> [ ["::" "<" Comma<Type> ">"]? <CallArgs> ]? // | <DotOrIndexChain> "[" <Exp> "]" @@ -2398,10 +2486,10 @@ fn make_builtin_call(loc: Loc, name: Symbol, type_args: Option<Vec<Type>>, args: // Parse a Type: // Type = -// <NameAccessChain> ('<' Comma<Type> ">")? +// <NameAccessChain> ("<" Comma<Type> ">")? // | "&" <Type> // | "&mut" <Type> -// | "|" Comma<Type> "|" <Type>? +// | "|" Comma<Type> "|" <Type>? <WithAbilities> // | "(" Comma<Type> ")" fn parse_type(context: &mut Context) -> Result<Type, Box<Diagnostic>> { let start_loc = context.tokens.start_loc(); @@ -2443,11 +2531,23 @@ fn parse_type(context: &mut Context) -> Result<Type, Box<Diagnostic>> { Type_::Unit, ) }; + let abilities_start = context.tokens.start_loc(); + let abilities = parse_with_abilities(context)?; + if !abilities.is_empty() { + let abilities_end = context.tokens.previous_end_loc(); + let loc = make_loc(context.tokens.file_hash(), abilities_start, abilities_end); + require_move_version( + LanguageVersion::V2_2, + context, + loc, + "Ability constraints on function types", + ); + } return Ok(spanned( context.tokens.file_hash(), start_loc, context.tokens.previous_end_loc(), - Type_::Fun(args, Box::new(result)), + Type_::Fun(args, Box::new(result), abilities), )); }, _ => { @@ -2522,6 +2622,43 @@ fn parse_ability(context: &mut Context) -> Result<Ability, Box<Diagnostic>> { } } +// Parse an optional "with" type constraint: +// WithAbilities = +// ( "with" <Ability> (+ <Ability>)* )? +fn parse_with_abilities(context: &mut Context) -> Result<Vec<Ability>, Box<Diagnostic>> { + if context.tokens.peek() == Tok::Identifier && context.tokens.content() == "with" { + context.tokens.advance()?; + parse_type_constraints_core(context) + } else { + Ok(vec![]) + } +} + +// Parse an optional type constraint: +// Constraint = +// ( ":" <Ability> (+ <Ability>)* )? +fn parse_type_constraints(context: &mut Context) -> Result<Vec<Ability>, Box<Diagnostic>> { + if match_token(context.tokens, Tok::Colon)? { + parse_type_constraints_core(context) + } else { + Ok(vec![]) + } +} + +fn parse_type_constraints_core(context: &mut Context) -> Result<Vec<Ability>, Box<Diagnostic>> { + parse_list( + context, + |context| match context.tokens.peek() { + Tok::Plus => { + context.tokens.advance()?; + Ok(true) + }, + _ => Ok(false), + }, + parse_ability, + ) +} + // Parse a type parameter: // TypeParameter = // <Identifier> <Constraint>? @@ -2530,30 +2667,7 @@ fn parse_ability(context: &mut Context) -> Result<Ability, Box<Diagnostic>> { fn parse_type_parameter(context: &mut Context) -> Result<(Name, Vec<Ability>), Box<Diagnostic>> { let n = parse_identifier(context)?; - let ability_constraints = if match_token(context.tokens, Tok::Colon)? { - parse_list( - context, - |context| match context.tokens.peek() { - Tok::Plus => { - context.tokens.advance()?; - Ok(true) - }, - Tok::Greater | Tok::Comma => Ok(false), - _ => Err(unexpected_token_error( - context.tokens, - &format!( - "one of: '{}', '{}', or '{}'", - Tok::Plus, - Tok::Greater, - Tok::Comma - ), - )), - }, - parse_ability, - )? - } else { - vec![] - }; + let ability_constraints = parse_type_constraints(context)?; Ok((n, ability_constraints)) } diff --git a/third_party/move/move-compiler/src/shared/ast_debug.rs b/third_party/move/move-compiler/src/shared/ast_debug.rs index e26578f6306b8..00db7d7502c65 100644 --- a/third_party/move/move-compiler/src/shared/ast_debug.rs +++ b/third_party/move/move-compiler/src/shared/ast_debug.rs @@ -24,6 +24,7 @@ /// } /// } /// ``` + pub trait AstDebug { fn ast_debug(&self, w: &mut AstWriter); } diff --git a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_complex_expression.exp b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_complex_expression.exp index fee0df0f4e049..84b113412d052 100644 --- a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_complex_expression.exp +++ b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_complex_expression.exp @@ -1,9 +1,18 @@ -error[E01002]: unexpected token - ┌─ tests/move_check/parser/invalid_call_lhs_complex_expression.move:3:29 +error[E02004]: invalid 'module' declaration + ┌─ tests/move_check/parser/invalid_call_lhs_complex_expression.move:1:8 + │ +1 │ module M { + │ ^ Invalid module declaration. The module does not have a specified address. Either declare it inside of an 'address <address> {' block or declare it with an address 'module <address>::M'' + +error[E01013]: unsupported language construct + ┌─ tests/move_check/parser/invalid_call_lhs_complex_expression.move:3:9 │ 3 │ (if (true) 5 else 0)(); - │ ^ - │ │ - │ Unexpected '(' - │ Expected ';' + │ ^^^^^^^^^^^^^^^^^^^^ Calls through computed functions not supported by this compiler + +error[E01013]: unsupported language construct + ┌─ tests/move_check/parser/invalid_call_lhs_complex_expression.move:4:9 + │ +4 │ (while (false) {})(0, 1); + │ ^^^^^^^^^^^^^^^^^^ Calls through computed functions not supported by this compiler diff --git a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_complex_expression2.exp b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_complex_expression2.exp index 7201cb27d3396..f66a597b72ba6 100644 --- a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_complex_expression2.exp +++ b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_complex_expression2.exp @@ -1,9 +1,12 @@ -error[E01002]: unexpected token - ┌─ tests/move_check/parser/invalid_call_lhs_complex_expression2.move:3:29 +error[E01013]: unsupported language construct + ┌─ tests/move_check/parser/invalid_call_lhs_complex_expression2.move:3:9 │ 3 │ (if (true) 5 else 0)(); - │ ^ - │ │ - │ Unexpected '(' - │ Expected ';' + │ ^^^^^^^^^^^^^^^^^^^^ Calls through computed functions not supported by this compiler + +error[E01013]: unsupported language construct + ┌─ tests/move_check/parser/invalid_call_lhs_complex_expression2.move:4:9 + │ +4 │ (while (false) {})(0, 1); + │ ^^^^^^^^^^^^^^^^^^ Calls through computed functions not supported by this compiler diff --git a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_parens_around_name.exp b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_parens_around_name.exp index 49558ae3304f2..90b98ee3c2b8f 100644 --- a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_parens_around_name.exp +++ b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_parens_around_name.exp @@ -1,9 +1,12 @@ -error[E01002]: unexpected token - ┌─ tests/move_check/parser/invalid_call_lhs_parens_around_name.move:3:14 +error[E02004]: invalid 'module' declaration + ┌─ tests/move_check/parser/invalid_call_lhs_parens_around_name.move:1:8 + │ +1 │ module M { + │ ^ Invalid module declaration. The module does not have a specified address. Either declare it inside of an 'address <address> {' block or declare it with an address 'module <address>::M'' + +error[E03009]: unbound variable + ┌─ tests/move_check/parser/invalid_call_lhs_parens_around_name.move:3:10 │ 3 │ (foo)() - │ ^ - │ │ - │ Unexpected '(' - │ Expected ';' + │ ^^^ Invalid function usage. Unbound variable 'foo' diff --git a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_parens_around_name2.exp b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_parens_around_name2.exp index fefac05537b4b..fe742a0fa5cae 100644 --- a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_parens_around_name2.exp +++ b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_parens_around_name2.exp @@ -1,9 +1,6 @@ -error[E01002]: unexpected token - ┌─ tests/move_check/parser/invalid_call_lhs_parens_around_name2.move:3:14 +error[E03009]: unbound variable + ┌─ tests/move_check/parser/invalid_call_lhs_parens_around_name2.move:3:10 │ 3 │ (foo)() - │ ^ - │ │ - │ Unexpected '(' - │ Expected ';' + │ ^^^ Invalid function usage. Unbound variable 'foo' diff --git a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_return.exp b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_return.exp index 89356898a0db1..e5b94f2d457bb 100644 --- a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_return.exp +++ b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_return.exp @@ -1,9 +1,12 @@ -error[E01002]: unexpected token - ┌─ tests/move_check/parser/invalid_call_lhs_return.move:3:20 +error[E02004]: invalid 'module' declaration + ┌─ tests/move_check/parser/invalid_call_lhs_return.move:1:8 + │ +1 │ module M { + │ ^ Invalid module declaration. The module does not have a specified address. Either declare it inside of an 'address <address> {' block or declare it with an address 'module <address>::M'' + +error[E01013]: unsupported language construct + ┌─ tests/move_check/parser/invalid_call_lhs_return.move:3:9 │ 3 │ (return ())(0, 1); - │ ^ - │ │ - │ Unexpected '(' - │ Expected ';' + │ ^^^^^^^^^^^ Calls through computed functions not supported by this compiler diff --git a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_return2.exp b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_return2.exp index 2527998d56005..de8427768b4df 100644 --- a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_return2.exp +++ b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_return2.exp @@ -1,9 +1,6 @@ -error[E01002]: unexpected token - ┌─ tests/move_check/parser/invalid_call_lhs_return2.move:3:20 +error[E01013]: unsupported language construct + ┌─ tests/move_check/parser/invalid_call_lhs_return2.move:3:9 │ 3 │ (return ())(0, 1); - │ ^ - │ │ - │ Unexpected '(' - │ Expected ';' + │ ^^^^^^^^^^^ Calls through computed functions not supported by this compiler diff --git a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_value.exp b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_value.exp index e75abc53ec0b7..c6ca3545b9588 100644 --- a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_value.exp +++ b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_value.exp @@ -1,9 +1,18 @@ -error[E01002]: unexpected token - ┌─ tests/move_check/parser/invalid_call_lhs_value.move:3:10 +error[E02004]: invalid 'module' declaration + ┌─ tests/move_check/parser/invalid_call_lhs_value.move:1:8 + │ +1 │ module M { + │ ^ Invalid module declaration. The module does not have a specified address. Either declare it inside of an 'address <address> {' block or declare it with an address 'module <address>::M'' + +error[E01013]: unsupported language construct + ┌─ tests/move_check/parser/invalid_call_lhs_value.move:3:9 │ 3 │ 5(); - │ ^ - │ │ - │ Unexpected '(' - │ Expected ';' + │ ^ Calls through computed functions not supported by this compiler + +error[E01013]: unsupported language construct + ┌─ tests/move_check/parser/invalid_call_lhs_value.move:4:9 + │ +4 │ 5(0, 1); + │ ^ Calls through computed functions not supported by this compiler diff --git a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_value2.exp b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_value2.exp index cd650973ac819..fd6099db101c0 100644 --- a/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_value2.exp +++ b/third_party/move/move-compiler/tests/move_check/parser/invalid_call_lhs_value2.exp @@ -1,9 +1,12 @@ -error[E01002]: unexpected token - ┌─ tests/move_check/parser/invalid_call_lhs_value2.move:3:10 +error[E01013]: unsupported language construct + ┌─ tests/move_check/parser/invalid_call_lhs_value2.move:3:9 │ 3 │ 5(); - │ ^ - │ │ - │ Unexpected '(' - │ Expected ';' + │ ^ Calls through computed functions not supported by this compiler + +error[E01013]: unsupported language construct + ┌─ tests/move_check/parser/invalid_call_lhs_value2.move:4:9 + │ +4 │ 5(0, 1); + │ ^ Calls through computed functions not supported by this compiler diff --git a/third_party/move/move-compiler/tests/move_check/parser/unexpected_token_after_ability_function_constraint.exp b/third_party/move/move-compiler/tests/move_check/parser/unexpected_token_after_ability_function_constraint.exp index 2482eef2ec13f..4ff6fe24775c0 100644 --- a/third_party/move/move-compiler/tests/move_check/parser/unexpected_token_after_ability_function_constraint.exp +++ b/third_party/move/move-compiler/tests/move_check/parser/unexpected_token_after_ability_function_constraint.exp @@ -2,8 +2,7 @@ error[E01002]: unexpected token ┌─ tests/move_check/parser/unexpected_token_after_ability_function_constraint.move:4:21 │ 4 │ fun foo<T: copy & drop>() {} - │ ^ - │ │ - │ Unexpected '&' - │ Expected one of: '+', '>', or ',' + │ - ^ Expected '>' + │ │ + │ To match this '<' diff --git a/third_party/move/move-model/Cargo.toml b/third_party/move/move-model/Cargo.toml index 49f76a32dfdf1..820a2b5b5af9b 100644 --- a/third_party/move/move-model/Cargo.toml +++ b/third_party/move/move-model/Cargo.toml @@ -21,6 +21,7 @@ move-symbol-pool = { path = "../move-symbol-pool" } # external dependencies codespan = { workspace = true } codespan-reporting = { workspace = true } +either = { workspace = true } internment = { workspace = true, features = ["arc"] } itertools = { workspace = true } log = { workspace = true } diff --git a/third_party/move/move-model/bytecode/ast-generator-tests/tests/testsuite.rs b/third_party/move/move-model/bytecode/ast-generator-tests/tests/testsuite.rs index d1d392fcde9ca..dcd03c9ca3eb9 100644 --- a/third_party/move/move-model/bytecode/ast-generator-tests/tests/testsuite.rs +++ b/third_party/move/move-model/bytecode/ast-generator-tests/tests/testsuite.rs @@ -96,22 +96,22 @@ fn generate_output(target: &FunctionTarget, test_output: &mut String) -> Option< }; *test_output += &format!( "--- Raw Generated AST\n{}\n\n", - exp.display_for_fun(target.func_env.clone()) + exp.display_for_fun(target.func_env) ); let exp = astifier::transform_assigns(target, exp); *test_output += &format!( "--- Assign-Transformed Generated AST\n{}\n\n", - exp.display_for_fun(target.func_env.clone()) + exp.display_for_fun(target.func_env) ); let exp = astifier::transform_conditionals(target, exp); *test_output += &format!( "--- If-Transformed Generated AST\n{}\n\n", - exp.display_for_fun(target.func_env.clone()) + exp.display_for_fun(target.func_env) ); let exp = astifier::bind_free_vars(target, exp); *test_output += &format!( "--- Var-Bound Generated AST\n{}\n\n", - exp.display_for_fun(target.func_env.clone()) + exp.display_for_fun(target.func_env) ); Some(exp) } diff --git a/third_party/move/move-model/bytecode/src/function_target_pipeline.rs b/third_party/move/move-model/bytecode/src/function_target_pipeline.rs index 6834b82844cb3..4fd4d5b0e0485 100644 --- a/third_party/move/move-model/bytecode/src/function_target_pipeline.rs +++ b/third_party/move/move-model/bytecode/src/function_target_pipeline.rs @@ -368,7 +368,7 @@ impl FunctionTargetPipeline { let src_idx = nodes.get(&fun_id).unwrap(); let fun_env = env.get_function(fun_id); for callee in fun_env - .get_called_functions() + .get_used_functions() .expect("called functions must be computed") { let dst_idx = nodes diff --git a/third_party/move/move-model/src/ast.rs b/third_party/move/move-model/src/ast.rs index e1c91a3e29b3a..7c5e120fd9de7 100644 --- a/third_party/move/move-model/src/ast.rs +++ b/third_party/move/move-model/src/ast.rs @@ -14,11 +14,12 @@ use crate::{ symbol::{Symbol, SymbolPool}, ty::{ReferenceKind, Type, TypeDisplayContext}, }; +use either::Either; use internment::LocalIntern; use itertools::{EitherOrBoth, Itertools}; use move_binary_format::{ file_format, - file_format::{CodeOffset, Visibility}, + file_format::{AbilitySet, CodeOffset, Visibility}, }; use move_core_types::account_address::AccountAddress; use num::BigInt; @@ -349,6 +350,23 @@ impl Spec { self.any(move |c| c.kind == kind) } + /// Returns the functions used (called or loaded as a function value) in this spec, along with + /// the sites of the calls or loads. + pub fn used_funs_with_uses(&self) -> BTreeMap<QualifiedId<FunId>, BTreeSet<NodeId>> { + let mut result = BTreeMap::new(); + for cond in self.conditions.iter().chain(self.update_map.values()) { + for exp in cond.all_exps() { + result.append(&mut exp.used_funs_with_uses()) + } + } + for on_impl in self.on_impl.values() { + result.append(&mut on_impl.used_funs_with_uses()) + } + result + } + + /// Returns the functions called in this spec. Does not include any functions used + /// as function values. pub fn called_funs_with_callsites(&self) -> BTreeMap<QualifiedId<FunId>, BTreeSet<NodeId>> { let mut result = BTreeMap::new(); for cond in self.conditions.iter().chain(self.update_map.values()) { @@ -512,6 +530,31 @@ pub enum AddressSpecifier { Call(QualifiedInstId<FunId>, Symbol), } +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Default)] +pub enum LambdaCaptureKind { + /// No modifier (e.g., inlining) + #[default] + Default, + /// Copy + Copy, + /// Move + Move, +} + +impl fmt::Display for LambdaCaptureKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + LambdaCaptureKind::Default => { + write!(f, "") + }, + LambdaCaptureKind::Copy => { + write!(f, "copy") + }, + LambdaCaptureKind::Move => write!(f, "move"), + } + } +} + impl ResourceSpecifier { /// Checks whether this resource specifier matches the given struct. A function /// instantiation is passed to instantiate the specifier in the calling context @@ -598,7 +641,7 @@ pub enum ExpData { /// Represents an invocation of a function value, as a lambda. Invoke(NodeId, Exp, Vec<Exp>), /// Represents a lambda. - Lambda(NodeId, Pattern, Exp), + Lambda(NodeId, Pattern, Exp, LambdaCaptureKind, AbilitySet), /// Represents a quantified formula over multiple variables and ranges. Quant( NodeId, @@ -889,12 +932,12 @@ impl ExpData { use ExpData::*; use VisitorPosition::*; match (e, pos) { - (Lambda(_, pat, _), Pre) | (Block(_, pat, _, _), BeforeBody) => { + (Lambda(_, pat, ..), Pre) | (Block(_, pat, _, _), BeforeBody) => { // Add declared variables to shadow; in the Block case, // do it only after processing bindings. for_syms_in_pat_shadow_or_unshadow(pat, true, &mut shadow_map); }, - (Lambda(_, pat, _), Post) | (Block(_, pat, _, _), Post) => { + (Lambda(_, pat, ..), Post) | (Block(_, pat, _, _), Post) => { // Remove declared variables from shadow for_syms_in_pat_shadow_or_unshadow(pat, false, &mut shadow_map); }, @@ -1044,20 +1087,52 @@ impl ExpData { temps } - /// Returns the Move functions called by this expression - pub fn called_funs(&self) -> BTreeSet<QualifiedId<FunId>> { - let mut called = BTreeSet::new(); + /// Returns the Move functions referenced by this expression + pub fn used_funs(&self) -> BTreeSet<QualifiedId<FunId>> { + let mut used = BTreeSet::new(); let mut visitor = |e: &ExpData| { match e { ExpData::Call(_, Operation::MoveFunction(mid, fid), _) - | ExpData::Call(_, Operation::Closure(mid, fid), _) => { - called.insert(mid.qualified(*fid)); + | ExpData::Value(_, Value::Function(mid, fid)) => { + used.insert(mid.qualified(*fid)); }, _ => {}, } true // keep going }; self.visit_post_order(&mut visitor); + used + } + + /// Returns the Move functions called or referenced by this expression, along with nodes of call sites or references. + pub fn used_funs_with_uses(&self) -> BTreeMap<QualifiedId<FunId>, BTreeSet<NodeId>> { + let mut used: BTreeMap<_, BTreeSet<_>> = BTreeMap::new(); + let mut visitor = |e: &ExpData| { + match e { + ExpData::Call(node_id, Operation::MoveFunction(mid, fid), _) + | ExpData::Value(node_id, Value::Function(mid, fid)) => { + used.entry(mid.qualified(*fid)) + .or_default() + .insert(*node_id); + }, + _ => {}, + }; + true // keep going + }; + self.visit_post_order(&mut visitor); + used + } + + /// Returns the Move functions called by this expression + pub fn called_funs(&self) -> BTreeSet<QualifiedId<FunId>> { + let mut called = BTreeSet::new(); + let mut visitor = |e: &ExpData| { + if let ExpData::Call(_, Operation::MoveFunction(mid, fid), _) = e { + called.insert(mid.qualified(*fid)); + }; + true // keep going + }; + self.visit_post_order(&mut visitor); called } @@ -1366,7 +1441,7 @@ impl ExpData { exp.visit_positions_impl(visitor)?; } }, - Lambda(_, _, body) => body.visit_positions_impl(visitor)?, + Lambda(_, _, body, _, _) => body.visit_positions_impl(visitor)?, Quant(_, _, ranges, triggers, condition, body) => { for (_, range) in ranges { range.visit_positions_impl(visitor)?; @@ -1739,6 +1814,14 @@ impl ExpRewriterFunctions for LoopNestRewriter { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Operation { MoveFunction(ModuleId, FunId), + /// Build a closure by binding 1 or more leading arguments to a function value. + /// First argument to the operation must be a function; the remaining + /// arguments will be bound, in order, to the leading parameters of that function, + /// generating a function which takes the remaining parameters and then calls + /// the function with the complete set of parameters. + /// (move |x, y| f(z, x, y)) === ExpData::Call(_, EarlyBind, vec![f, z]) + /// (move || f(z, x, y)) === ExpData::Call(_, EarlyBind, vec![f, z, x, y]) + EarlyBind, Pack(ModuleId, StructId, /*variant*/ Option<Symbol>), Tuple, Select(ModuleId, StructId, FieldId), @@ -1751,7 +1834,6 @@ pub enum Operation { // Specification specific SpecFunction(ModuleId, SpecFunId, Option<Vec<MemoryLabel>>), - Closure(ModuleId, FunId), UpdateField(ModuleId, StructId, FieldId), Result(usize), Index, @@ -2221,7 +2303,7 @@ impl Pattern { PatDisplay { env: fun_env.module_env.env, pat: self, - fun_env: Some(fun_env.clone()), + fun_env: Some(fun_env), show_type: false, } .to_string() @@ -2240,7 +2322,7 @@ impl Pattern { PatDisplay { env: other.env, pat: self, - fun_env: other.fun_env.clone(), + fun_env: other.fun_env, show_type: other.show_type, } } @@ -2249,7 +2331,7 @@ impl Pattern { PatDisplay { env: other.env, pat: self, - fun_env: other.fun_env.clone(), + fun_env: other.fun_env, show_type: true, } } @@ -2259,7 +2341,7 @@ impl Pattern { pub struct PatDisplay<'a> { env: &'a GlobalEnv, pat: &'a Pattern, - fun_env: Option<FunctionEnv<'a>>, + fun_env: Option<&'a FunctionEnv<'a>>, show_type: bool, } @@ -2403,6 +2485,8 @@ pub enum Value { AddressArray(Vec<Address>), // TODO: merge AddressArray to Vector type in the future Vector(Vec<Value>), Tuple(Vec<Value>), + /// Represents a reference to a Move Function as a function value. + Function(ModuleId, FunId), } impl Value { @@ -2491,6 +2575,9 @@ impl Value { Some(false) } }, + (Value::Function(mid1, sid1), Value::Function(mid2, sid2)) => { + Some(mid1 == mid2 && sid1 == sid2) + }, _ => Some(false), } } else { @@ -2511,6 +2598,14 @@ impl<'a> fmt::Display for EnvDisplay<'a, Value> { Value::AddressArray(array) => write!(f, "a{:?}", array), Value::Vector(array) => write!(f, "{:?}", array), Value::Tuple(array) => write!(f, "({:?})", array), + Value::Function(mid, fid) => write!( + f, + "{}", + self.env + .get_function_opt(mid.qualified(*fid)) + .map(|fun| fun.get_full_name_str()) + .unwrap_or_else(|| "<?unknown function?>".to_string()) + ), } } } @@ -2574,12 +2669,12 @@ impl Operation { match self { MoveFunction(..) => false, // could abort SpecFunction(..) => false, // Spec - Closure(..) => false, // Spec Pack(..) => false, // Could yield an undroppable value Tuple => true, Select(..) => false, // Move-related SelectVariants(..) => false, // Move-related UpdateField(..) => false, // Move-related + EarlyBind => true, // Specification specific Result(..) => false, // Spec @@ -3035,28 +3130,32 @@ impl ExpData { fun_env: None, verbose: false, annotator: None, + tctx: Either::Left(TypeDisplayContext::new(env)), } } /// Creates a display of an expression which can be used in formatting, based /// on a function env for getting names of locals and type parameters. - pub fn display_for_fun<'a>(&'a self, fun_env: FunctionEnv<'a>) -> ExpDisplay<'a> { + pub fn display_for_fun<'a>(&'a self, fun_env: &'a FunctionEnv<'a>) -> ExpDisplay<'a> { + let tctx = Either::Left(fun_env.get_type_display_ctx()); ExpDisplay { env: fun_env.module_env.env, exp: self, fun_env: Some(fun_env), verbose: false, annotator: None, + tctx, } } - fn display_cont<'a>(&'a self, other: &ExpDisplay<'a>) -> ExpDisplay<'a> { + fn display_cont<'a>(&'a self, other: &'a ExpDisplay<'a>) -> ExpDisplay<'a> { ExpDisplay { env: other.env, exp: self, - fun_env: other.fun_env.clone(), + fun_env: other.fun_env, verbose: other.verbose, annotator: other.annotator, + tctx: Either::Right(other.get_tctx()), } } @@ -3067,6 +3166,7 @@ impl ExpData { fun_env: None, verbose: true, annotator: None, + tctx: Either::Left(TypeDisplayContext::new(env)), } } @@ -3084,6 +3184,7 @@ impl ExpData { fun_env: None, verbose: false, annotator: Some(annotator), + tctx: Either::Left(TypeDisplayContext::new(env)), } } } @@ -3092,9 +3193,19 @@ impl ExpData { pub struct ExpDisplay<'a> { env: &'a GlobalEnv, exp: &'a ExpData, - fun_env: Option<FunctionEnv<'a>>, + fun_env: Option<&'a FunctionEnv<'a>>, verbose: bool, annotator: Option<&'a dyn Fn(NodeId) -> String>, + tctx: Either<TypeDisplayContext<'a>, &'a TypeDisplayContext<'a>>, +} + +impl<'a> ExpDisplay<'a> { + fn get_tctx(&'a self) -> &'a TypeDisplayContext<'a> { + match &self.tctx { + Either::Left(tctx) => tctx, + Either::Right(tctx_ref) => tctx_ref, + } + } } impl<'a> fmt::Display for ExpDisplay<'a> { @@ -3140,22 +3251,44 @@ impl<'a> fmt::Display for ExpDisplay<'a> { self.fmt_exps(args) ) }, - Lambda(id, pat, body) => { + Lambda(id, pat, body, capture_kind, abilities) => { if self.verbose { write!( f, - "{}: |{}| {}", + "{}: {}{}|{}| {}", id.as_usize(), + if *capture_kind != LambdaCaptureKind::Default { + " " + } else { + "" + }, + capture_kind, pat.display_for_exp(self), body.display_cont(self) - ) + )?; } else { write!( f, - "|{}| {}", + "{}{}|{}| {}", + if *capture_kind != LambdaCaptureKind::Default { + " " + } else { + "" + }, + capture_kind, pat.display_for_exp(self), body.display_cont(self) - ) + )?; + } + if !abilities.is_subset(AbilitySet::FUNCTIONS) { + let abilities_as_str = abilities + .iter() + .map(|a| a.to_string()) + .reduce(|l, r| format!("{}, {}", l, r)) + .unwrap_or_default(); + write!(f, " with {}", abilities_as_str) + } else { + Ok(()) } }, Block(id, pat, binding, body) => { @@ -3349,7 +3482,21 @@ impl Operation { env, oper: self, node_id, - tctx, + tctx: Either::Left(tctx), + } + } + + fn display_with_context_ref<'a>( + &'a self, + env: &'a GlobalEnv, + node_id: NodeId, + tctx: &'a TypeDisplayContext<'a>, + ) -> OperationDisplay<'a> { + OperationDisplay { + env, + oper: self, + node_id, + tctx: Either::Right(tctx), } } @@ -3373,17 +3520,8 @@ impl Operation { exp_display: &'a ExpDisplay, node_id: NodeId, ) -> OperationDisplay<'a> { - let tctx = if let Some(fe) = &exp_display.fun_env { - fe.get_type_display_ctx() - } else { - TypeDisplayContext::new(exp_display.env) - }; - OperationDisplay { - env: exp_display.env, - oper: self, - node_id, - tctx, - } + let tctx = exp_display.get_tctx(); + self.display_with_context_ref(exp_display.env, node_id, tctx) } } @@ -3392,7 +3530,16 @@ pub struct OperationDisplay<'a> { env: &'a GlobalEnv, node_id: NodeId, oper: &'a Operation, - tctx: TypeDisplayContext<'a>, + tctx: Either<TypeDisplayContext<'a>, &'a TypeDisplayContext<'a>>, +} + +impl<'a> OperationDisplay<'a> { + fn get_tctx(&'a self) -> &'a TypeDisplayContext<'a> { + match &self.tctx { + Either::Left(tctx) => tctx, + Either::Right(tctx_ref) => tctx_ref, + } + } } impl<'a> fmt::Display for OperationDisplay<'a> { @@ -3401,7 +3548,7 @@ impl<'a> fmt::Display for OperationDisplay<'a> { match self.oper { Cast => { let ty = self.env.get_node_type(self.node_id); - write!(f, "{:?}<{}>", self.oper, ty.display(&self.tctx)) + write!(f, "{:?}<{}>", self.oper, ty.display(self.get_tctx())) }, SpecFunction(mid, fid, labels_opt) => { write!(f, "{}", self.fun_str(mid, fid))?; @@ -3419,18 +3566,13 @@ impl<'a> fmt::Display for OperationDisplay<'a> { f, "{}", self.env - .get_function(mid.qualified(*fid)) - .get_full_name_str() + .get_function_opt(mid.qualified(*fid)) + .map(|fun| fun.get_full_name_str()) + .unwrap_or_else(|| "<?unknown function?>".to_string()) ) }, - Closure(mid, fid) => { - write!( - f, - "closure {}", - self.env - .get_function(mid.qualified(*fid)) - .get_full_name_str() - ) + EarlyBind => { + write!(f, "earlybind") }, Global(label_opt) => { write!(f, "global")?; @@ -3488,7 +3630,10 @@ impl<'a> fmt::Display for OperationDisplay<'a> { write!( f, "<{}>", - type_inst.iter().map(|ty| ty.display(&self.tctx)).join(", ") + type_inst + .iter() + .map(|ty| ty.display(self.get_tctx())) + .join(", ") )?; } Ok(()) @@ -3507,12 +3652,23 @@ impl<'a> OperationDisplay<'a> { } fn struct_str(&self, mid: &ModuleId, sid: &StructId) -> String { - let module_env = self.env.get_module(*mid); - let struct_env = module_env.get_struct(*sid); + let module_env_opt = self.env.get_module_opt(*mid); + let struct_env_str = module_env_opt + .clone() + .map(|module_env| { + module_env + .get_struct(*sid) + .get_name() + .display(self.env.symbol_pool()) + .to_string() + }) + .unwrap_or_else(|| "None".to_string()); format!( "{}::{}", - module_env.get_name().display(self.env), - struct_env.get_name().display(self.env.symbol_pool()), + module_env_opt + .map(|module_env| module_env.get_name().display(self.env).to_string()) + .unwrap_or_else(|| "None".to_string()), + struct_env_str ) } diff --git a/third_party/move/move-model/src/builder/exp_builder.rs b/third_party/move/move-model/src/builder/exp_builder.rs index 8f16fa60111de..f91e4dd28bd9f 100644 --- a/third_party/move/move-model/src/builder/exp_builder.rs +++ b/third_party/move/move-model/src/builder/exp_builder.rs @@ -4,9 +4,9 @@ use crate::{ ast::{ - AccessSpecifier, Address, AddressSpecifier, Exp, ExpData, MatchArm, ModuleName, Operation, - Pattern, QualifiedSymbol, QuantKind, ResourceSpecifier, RewriteResult, Spec, TempIndex, - Value, + AccessSpecifier, Address, AddressSpecifier, Exp, ExpData, LambdaCaptureKind, MatchArm, + ModuleName, Operation, Pattern, QualifiedSymbol, QuantKind, ResourceSpecifier, + RewriteResult, Spec, TempIndex, Value, }, builder::{ model_builder::{ @@ -178,9 +178,28 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo et } - pub fn check_language_version(&self, loc: &Loc, feature: &str, version_min: LanguageVersion) { + /// Returns `true` if language version is ok. Otherwise, + /// issues an error message and returns `false`. + pub fn test_language_version( + &self, + loc: &Loc, + feature: &str, + version_min: LanguageVersion, + ) -> bool { + self.parent.test_language_version(loc, feature, version_min) + } + + /// Returns `Some(())` if language version checks out. Otherwise, + /// issues an error message and returns `None`. + pub fn check_language_version( + &self, + loc: &Loc, + feature: &str, + version_min: LanguageVersion, + ) -> Option<()> { self.parent - .check_language_version(loc, feature, version_min); + .test_language_version(loc, feature, version_min) + .then_some(()) } pub fn set_spec_block_map(&mut self, map: BTreeMap<EA::SpecId, EA::SpecBlock>) { @@ -891,6 +910,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo self.translate_hlir_base_types(&args[0..args.len() - 1]), )), Box::new(self.translate_hlir_base_type(&args[args.len() - 1])), + AbilitySet::FUNCTIONS, ), }, ModuleType(m, n) => { @@ -1061,9 +1081,10 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo ReferenceKind::from_is_mut(*is_mut), Box::new(self.translate_type(ty)), ), - Fun(args, result) => Type::Fun( + Fun(args, result, abilities) => Type::Fun( Box::new(Type::tuple(self.translate_types(args.as_ref()))), Box::new(self.translate_type(result)), + AbilitySet::FUNCTIONS | self.parent.translate_abilities(abilities), ), Unit => Type::Tuple(vec![]), Multiple(vst) => Type::Tuple(self.translate_types(vst.as_ref())), @@ -1147,16 +1168,16 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo &loc, "read/write access specifiers. Try `acquires` instead.", LanguageVersion::V2_0, - ) + )?; } else if *negated { - self.check_language_version(&loc, "access specifier negation", LanguageVersion::V2_0) + self.check_language_version(&loc, "access specifier negation", LanguageVersion::V2_0)?; } else if type_args.is_some() && !type_args.as_ref().unwrap().is_empty() { self.check_language_version( &loc, "access specifier type instantiation. Try removing the type instantiation.", LanguageVersion::V2_0, - ) - } + )?; + }; let resource = match (module_address, module_name, resource_name) { (None, None, None) => { // This stems from a specifier of the form `acquires *(0x1)` @@ -1248,8 +1269,8 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo &loc, "address and wildcard access specifiers. Only resource type names can be provided.", LanguageVersion::V2_0, - ); - } + )?; + }; let address = self.translate_address_specifier(address)?; Some(AccessSpecifier { loc: loc.clone(), @@ -1272,7 +1293,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo &loc, "wildcard address specifiers", LanguageVersion::V2_0, - ); + )?; (loc, AddressSpecifier::Any) }, EA::AddressSpecifier_::Literal(addr) => { @@ -1280,7 +1301,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo &loc, "literal address specifiers", LanguageVersion::V2_0, - ); + )?; ( loc, AddressSpecifier::Address(Address::Numerical(addr.into_inner())), @@ -1291,7 +1312,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo &loc, "named address specifiers", LanguageVersion::V2_0, - ); + )?; // Construct an expansion name exp for regular type check let maccess = sp(name.loc, EA::ModuleAccess_::Name(*name)); self.translate_name( @@ -1311,7 +1332,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo &loc, "derived address specifiers", LanguageVersion::V2_0, - ); + )?; // Construct an expansion function call for regular type check let name_exp = sp( name.loc, @@ -1380,6 +1401,15 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo self.translate_exp_in_context(exp, expected_type, &ErrorMessageContext::General) } + /// Translates LambdaCaptureKind + pub fn translate_lambda_capture_kind(kind: PA::LambdaCaptureKind) -> LambdaCaptureKind { + match kind { + PA::LambdaCaptureKind::Default => LambdaCaptureKind::Default, + PA::LambdaCaptureKind::Copy => LambdaCaptureKind::Copy, + PA::LambdaCaptureKind::Move => LambdaCaptureKind::Move, + } + } + /// Translates an expression in a specific error message context. pub fn translate_exp_in_context( &mut self, @@ -1511,6 +1541,19 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo ) } }, + EA::Exp_::ExpCall(efexp, args) => { + let args_ref: Vec<_> = args.value.iter().collect(); + let (arg_types, args) = self.translate_exp_list(&args_ref); + + let fun_t = Type::Fun( + Box::new(Type::tuple(arg_types)), + Box::new(expected_type.clone()), + AbilitySet::FUNCTIONS, + ); + let fexp = self.translate_exp(efexp, &fun_t); + let id = self.new_node_id_with_type_loc(expected_type, &loc); + ExpData::Invoke(id, fexp.into_exp(), args) + }, EA::Exp_::Pack(maccess, generics, fields) => self .translate_pack( &loc, @@ -1608,9 +1651,15 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo ExpData::LoopCont(id, nest, true) }, EA::Exp_::Block(seq) => self.translate_seq(&loc, seq, expected_type, context), - EA::Exp_::Lambda(bindings, exp) => { - self.translate_lambda(&loc, bindings, exp, expected_type, context) - }, + EA::Exp_::Lambda(bindings, exp, capture_kind, abilities) => self.translate_lambda( + &loc, + bindings, + exp, + expected_type, + context, + Self::translate_lambda_capture_kind(*capture_kind), + AbilitySet::FUNCTIONS | self.parent.translate_abilities(abilities), + ), EA::Exp_::Quant(kind, ranges, triggers, condition, body) => self.translate_quant( &loc, *kind, @@ -3143,7 +3192,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo // handles call of struct/variant with positional fields let expected_type = &self.subs.specialize(expected_type); if self.can_resolve_to_struct(expected_type, maccess) { - self.check_language_version(loc, "positional fields", LanguageVersion::V2_0); + self.check_language_version(loc, "positional fields", LanguageVersion::V2_0)?; // translates StructName(e0, e1, ...) to pack<StructName> { 0: e0, 1: e1, ... } let fields: EA::Fields<_> = EA::Fields::maybe_from_iter(args.iter().enumerate().map(|(i, &arg)| { @@ -3185,8 +3234,15 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo let fun_t = Type::Fun( Box::new(Type::tuple(arg_types)), Box::new(expected_type.clone()), + if let Type::Fun(.., abilities) = &sym_ty { + *abilities + } else { + // Don't constraint Abilities of sym_ty. + AbilitySet::MAXIMAL_FUNCTIONS + }, ); let sym_ty = self.check_type(loc, &sym_ty, &fun_t, context); + let local_id = self.new_node_id_with_type_loc(&sym_ty, &self.to_loc(&n.loc)); let local_var = ExpData::LocalVar(local_id, sym); let id = self.new_node_id_with_type_loc(expected_type, loc); @@ -3289,8 +3345,9 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo /// translated expression. pub fn translate_exp_free(&mut self, exp: &EA::Exp) -> (Type, ExpData) { let tvar = self.fresh_type_var(); - let exp = self.translate_exp(exp, &tvar); - (self.subs.specialize(&tvar), exp) + let exp_out = self.translate_exp(exp, &tvar); + let tsub = self.subs.specialize(&tvar); + (tsub, exp_out) } /// Translates a sequence expression. @@ -3520,6 +3577,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo let instantiation = self.translate_types(type_args.as_slice()); let ty = ty.instantiate(&instantiation); let ty = self.check_type(loc, &ty, expected_type, context); + // Create expression global<GhostMem>(@0).v which backs up the ghost variable. let ghost_mem_id = StructId::new( self.parent @@ -3549,6 +3607,45 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo vec![global_access.into_exp()], ); } + + if let Some(entry) = self.parent.parent.fun_table.get(&global_var_sym) { + let module_id = entry.module_id; + let fun_id = entry.fun_id; + let fun_abilities = if entry.visibility.is_public() { + AbilitySet::PUBLIC_FUNCTIONS + } else { + AbilitySet::PRIVATE_FUNCTIONS + }; + let result_type = entry.result_type.clone(); + let type_params = entry.type_params.clone(); + let param_types = entry + .params + .iter() + .map(|param| param.get_type()) + .collect_vec(); + let Some(instantiation) = self.make_instantiation_or_report( + loc, + false, + global_var_sym.symbol, + &type_params, + type_args, + ) else { + return self.new_error_exp(); + }; + let fun_type = Type::Fun( + Box::new(Type::tuple(param_types)), + Box::new(result_type), + fun_abilities, + ); + let fun_type = fun_type.instantiate(&instantiation); + let fun_type = self.check_type(loc, &fun_type, expected_type, context); + + let id = self.env().new_node(loc.clone(), fun_type); + self.env().set_node_instantiation(id, instantiation); + let fn_exp = ExpData::Value(id, Value::Function(module_id, fun_id)); + return fn_exp; + } + // If a qualified name is not explicitly specified, do not print it out let qualified_display = if let EA::ModuleAccess_::ModuleAccess(..) = maccess.value { global_var_sym.display(self.env()) @@ -3768,7 +3865,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo .struct_table .contains_key(&global_var_sym) { - self.check_language_version(loc, "resource indexing", LanguageVersion::V2_0); + self.check_language_version(loc, "resource indexing", LanguageVersion::V2_0)?; if self .parent .parent @@ -3798,7 +3895,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo } } if !self.is_spec_mode() { - self.check_language_version(loc, "vector indexing", LanguageVersion::V2_0); + self.check_language_version(loc, "vector indexing", LanguageVersion::V2_0)?; // Translate to vector indexing in impl mode if the target is not a resource or a spec schema // spec mode is handled in `translate_index` if call.is_none() { @@ -4125,7 +4222,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo expected_type: &Type, context: &ErrorMessageContext, ) -> ExpData { - // Translate arguments. + // Translate arguments: arg_types is needed to do candidate matching. let (mut arg_types, mut translated_args) = self.translate_exp_list(args); // Special handling of receiver call functions @@ -4224,6 +4321,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo self.error(loc, &format!("no function named `{}` found", display)); return self.new_error_exp(); } + // Partition candidates in those which matched and which have been outruled. let mut outruled = vec![]; let mut matching = vec![]; @@ -4283,6 +4381,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo continue; } } + // Process arguments let mut success = true; for (i, arg_ty) in arg_types.iter().enumerate() { @@ -4369,6 +4468,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo let (cand, subs, instantiation) = matching.remove(0); let (_, _, result_type) = cand.get_signature(); let result_type = result_type.instantiate(&instantiation); + // Commit the candidate substitution to this expression translator. self.subs = subs; @@ -4409,8 +4509,10 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo .add_used_spec_fun(module_id.qualified(spec_fun_id)); self.called_spec_funs.insert((module_id, spec_fun_id)); } + let translated_args = self.add_conversions(cand, &instantiation, translated_args); let specialized_expected_type = self.subs.specialize(expected_type); + let call_exp = ExpData::Call(id, oper, translated_args).into_exp(); // Insert freeze for the return value let call_exp = if let (Type::Tuple(ref result_tys), Type::Tuple(expected_tys)) = @@ -4553,7 +4655,11 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo args: Vec<Exp>, expected_type: &Type, ) -> ExpData { - self.check_language_version(loc, "receiver style function calls", LanguageVersion::V2_0); + if !self.test_language_version(loc, "receiver style function calls", LanguageVersion::V2_0) + { + let id = self.new_node_id_with_type_loc(&Type::Error, loc); + return ExpData::Invalid(id); + } let generics = generics .as_ref() .map(|tys| self.translate_types_with_loc(tys)); @@ -4586,16 +4692,12 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo /// Translate a list of expressions and deliver them together with their types. fn translate_exp_list(&mut self, exps: &[&EA::Exp]) -> (Vec<Type>, Vec<Exp>) { - let mut types = vec![]; - let exps = exps - .iter() + exps.iter() .map(|e| { let (t, e) = self.translate_exp_free(e); - types.push(t); - e.into_exp() + (t, e.into_exp()) }) - .collect_vec(); - (types, exps) + .unzip() } /// Creates a type instantiation using optionally provided type arguments. @@ -5135,6 +5237,8 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo body: &EA::Exp, expected_type: &Type, context: &ErrorMessageContext, + capture_kind: LambdaCaptureKind, + abilities: AbilitySet, ) -> ExpData { // Translate the argument list let arg_type = self.fresh_type_var(); @@ -5155,14 +5259,18 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo let ty = self.fresh_type_var(); let rty = self.check_type( loc, - &Type::Fun(Box::new(arg_type), Box::new(ty.clone())), + &Type::Fun( + Box::new(arg_type.clone()), + Box::new(ty.clone()), + abilities.union(AbilitySet::MAXIMAL_FUNCTIONS), + ), expected_type, context, ); let rbody = self.translate_exp(body, &ty); self.exit_scope(); let id = self.new_node_id_with_type_loc(&rty, loc); - ExpData::Lambda(id, pat, rbody.into_exp()) + ExpData::Lambda(id, pat, rbody.into_exp(), capture_kind, abilities) } fn translate_quant( @@ -5257,6 +5365,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo ExpData::Quant(id, rkind, rranges, rtriggers, rcondition, rbody.into_exp()) } + /// Unify types with order `LeftToRight` and shallow variance pub fn check_type( &mut self, loc: &Loc, @@ -5267,6 +5376,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo self.check_type_with_order(WideningOrder::LeftToRight, loc, ty, expected, context) } + /// Unify types with order `Join` and shallow variance, and specified error message override pub fn join_type( &mut self, loc: &Loc, @@ -5277,6 +5387,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo self.check_type_with_order(WideningOrder::Join, loc, ty1, ty2, context) } + /// Unify types with shallow variance, and specified error message override fn check_type_with_order( &mut self, order: WideningOrder, @@ -5293,6 +5404,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo }) } + /// Unify types with specified variance and order fn unify_types( &mut self, variance: Variance, @@ -5379,8 +5491,8 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo | (Type::TypeParameter(_), MoveValue::Struct(_)) | (Type::Reference(_, _), MoveValue::Vector(_)) | (Type::Reference(_, _), MoveValue::Struct(_)) - | (Type::Fun(_, _), MoveValue::Vector(_)) - | (Type::Fun(_, _), MoveValue::Struct(_)) + | (Type::Fun(..), MoveValue::Vector(_)) + | (Type::Fun(..), MoveValue::Struct(_)) | (Type::TypeDomain(_), MoveValue::Vector(_)) | (Type::TypeDomain(_), MoveValue::Struct(_)) | (Type::ResourceDomain(_, _, _), MoveValue::Vector(_)) 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 79586773981db..55c3b34520c19 100644 --- a/third_party/move/move-model/src/builder/model_builder.rs +++ b/third_party/move/move-model/src/builder/model_builder.rs @@ -496,20 +496,24 @@ impl<'env> ModelBuilder<'env> { for cur_mod in target_modules { let cur_mod_env = self.env.get_module(cur_mod); let cur_mod_name = cur_mod_env.get_name().clone(); - for need_to_be_friended_by in cur_mod_env.need_to_be_friended_by() { - let need_to_be_friend_with = self.env.get_module_data_mut(need_to_be_friended_by); + let needed = cur_mod_env.need_to_be_friended_by(); + for need_to_be_friended_by in needed { + let need_to_be_friend_with = self.env.get_module(need_to_be_friended_by); let already_friended = need_to_be_friend_with - .friend_decls + .get_friend_decls() .iter() .any(|friend_decl| friend_decl.module_name == cur_mod_name); if !already_friended { - let loc = need_to_be_friend_with.loc.clone(); + let loc = need_to_be_friend_with.get_loc(); let friend_decl = FriendDecl { loc, module_name: cur_mod_name.clone(), module_id: Some(cur_mod), }; - need_to_be_friend_with.friend_decls.push(friend_decl); + self.env + .get_module_data_mut(need_to_be_friended_by) + .friend_decls + .push(friend_decl); } } } 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 e6e1f65ff313f..048b68444e709 100644 --- a/third_party/move/move-model/src/builder/module_builder.rs +++ b/third_party/move/move-model/src/builder/module_builder.rs @@ -918,7 +918,14 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> { /// # Definition Analysis impl<'env, 'translator> ModuleBuilder<'env, 'translator> { - pub fn check_language_version(&self, loc: &Loc, feature: &str, version_min: LanguageVersion) { + /// Returns `true` if language version is ok. Otherwise, + /// issues an error message and returns `false`. + pub fn test_language_version( + &self, + loc: &Loc, + feature: &str, + version_min: LanguageVersion, + ) -> bool { if !self.parent.env.language_version().is_at_least(version_min) { self.parent.env.error( loc, @@ -926,7 +933,10 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> { "not supported before language version `{}`: {}", version_min, feature ), - ) + ); + false + } else { + true } } @@ -1012,11 +1022,13 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> { if !self.parent.const_table.contains_key(&qsym) { continue; } - self.check_language_version( + if !self.test_language_version( &loc, "constant definitions referring to other constants", LanguageVersion::V2_0, - ); + ) { + continue; + } if visited.contains(&const_name) { continue; } @@ -2634,10 +2646,13 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> { ) { // Type check and translate lhs and rhs. They must have the same type. let mut et = self.exp_translator_for_context(loc, context, &ConditionKind::Requires); - let (expected_ty, lhs) = et.translate_exp_free(lhs); - let rhs = et.translate_exp(rhs, &expected_ty); + let (expected_ty, translated_lhs) = et.translate_exp_free(lhs); + let translated_rhs = et.translate_exp(rhs, &expected_ty); et.finalize_types(); - if lhs.extract_ghost_mem_access(self.parent.env).is_some() { + if translated_lhs + .extract_ghost_mem_access(self.parent.env) + .is_some() + { // Add as a condition to the context. self.add_conditions_to_context( context, @@ -2646,15 +2661,15 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> { loc: loc.clone(), kind: ConditionKind::Update, properties: Default::default(), - exp: rhs.into_exp(), - additional_exps: vec![lhs.into_exp()], + exp: translated_rhs.into_exp(), + additional_exps: vec![translated_lhs.into_exp()], }], PropertyBag::default(), "", ); } else { self.parent.error( - &self.parent.env.get_node_loc(lhs.node_id()), + &self.parent.env.get_node_loc(translated_lhs.node_id()), "target of `update` restricted to specification variables", ) } @@ -3726,6 +3741,7 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> { let spec = self.fun_specs.remove(&name.symbol).unwrap_or_default(); let def = self.fun_defs.remove(&name.symbol); let called_funs = Some(def.as_ref().map(|e| e.called_funs()).unwrap_or_default()); + let used_funs = Some(def.as_ref().map(|e| e.used_funs()).unwrap_or_default()); let access_specifiers = self.fun_access_specifiers.remove(&name.symbol); let fun_id = FunId::new(name.symbol); let data = FunctionData { @@ -3751,6 +3767,9 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> { called_funs, calling_funs: RefCell::default(), transitive_closure_of_called_funs: RefCell::default(), + used_funs, + using_funs: RefCell::default(), + transitive_closure_of_used_funs: RefCell::default(), }; function_data.insert(fun_id, data); } diff --git a/third_party/move/move-model/src/exp_rewriter.rs b/third_party/move/move-model/src/exp_rewriter.rs index d55b7842c3e1f..af93e0e72553f 100644 --- a/third_party/move/move-model/src/exp_rewriter.rs +++ b/third_party/move/move-model/src/exp_rewriter.rs @@ -4,15 +4,17 @@ use crate::{ ast::{ - Condition, Exp, ExpData, MatchArm, MemoryLabel, Operation, Pattern, Spec, SpecBlockTarget, - TempIndex, Value, + Condition, Exp, ExpData, LambdaCaptureKind, MatchArm, MemoryLabel, Operation, Pattern, + Spec, SpecBlockTarget, TempIndex, Value, }, model::{GlobalEnv, Loc, ModuleId, NodeId, SpecVarId}, symbol::Symbol, ty::Type, + FunId, }; use codespan_reporting::diagnostic::Severity; use itertools::Itertools; +use move_binary_format::file_format::AbilitySet; use std::collections::{BTreeMap, BTreeSet}; /// Rewriter for expressions, allowing to substitute locals by expressions as well as instantiate @@ -179,6 +181,9 @@ pub trait ExpRewriterFunctions { fn rewrite_value(&mut self, id: NodeId, value: &Value) -> Option<Exp> { None } + fn rewrite_move_function(&mut self, id: NodeId, mid: ModuleId, fid: FunId) -> Option<Exp> { + None + } fn rewrite_spec_var( &mut self, id: NodeId, @@ -194,7 +199,14 @@ pub trait ExpRewriterFunctions { fn rewrite_invoke(&mut self, id: NodeId, target: &Exp, args: &[Exp]) -> Option<Exp> { None } - fn rewrite_lambda(&mut self, id: NodeId, pat: &Pattern, body: &Exp) -> Option<Exp> { + fn rewrite_lambda( + &mut self, + id: NodeId, + pat: &Pattern, + body: &Exp, + capture_kind: LambdaCaptureKind, + abilities: AbilitySet, + ) -> Option<Exp> { None } // Optionally can rewrite pat and return new value, otherwise is unchanged. @@ -351,16 +363,18 @@ pub trait ExpRewriterFunctions { exp } }, - Lambda(id, pat, body) => { + Lambda(id, pat, body, capture_kind, abilities) => { let (id_changed, new_id) = self.internal_rewrite_id(*id); let (pat_changed, new_pat) = self.internal_rewrite_pattern(pat, true); self.rewrite_enter_scope(new_id, new_pat.vars().iter()); let (body_changed, new_body) = self.internal_rewrite_exp(body); self.rewrite_exit_scope(new_id); - if let Some(new_exp) = self.rewrite_lambda(new_id, &new_pat, &new_body) { + if let Some(new_exp) = + self.rewrite_lambda(new_id, &new_pat, &new_body, *capture_kind, *abilities) + { new_exp } else if id_changed || pat_changed || body_changed { - Lambda(new_id, new_pat, new_body).into_exp() + Lambda(new_id, new_pat, new_body, *capture_kind, *abilities).into_exp() } else { exp } diff --git a/third_party/move/move-model/src/metadata.rs b/third_party/move/move-model/src/metadata.rs index 0a6bacc5e7330..a26a67ffef4f1 100644 --- a/third_party/move/move-model/src/metadata.rs +++ b/third_party/move/move-model/src/metadata.rs @@ -207,6 +207,11 @@ pub enum LanguageVersion { V2_2, } +impl LanguageVersion { + /// Leave this symbolic for now in case of more versions. + pub const V2_LAMBDA: Self = Self::V2_2; +} + impl Default for LanguageVersion { fn default() -> Self { static MOVE_LANGUAGE_V2: Lazy<bool> = Lazy::new(|| read_bool_env_var("MOVE_LANGUAGE_V2")); diff --git a/third_party/move/move-model/src/model.rs b/third_party/move/move-model/src/model.rs index 9428d08ec9617..e7a87dd266c74 100644 --- a/third_party/move/move-model/src/model.rs +++ b/third_party/move/move-model/src/model.rs @@ -44,7 +44,7 @@ use codespan_reporting::{ }; use itertools::Itertools; #[allow(unused_imports)] -use log::{info, warn}; +use log::{debug, info, warn}; pub use move_binary_format::file_format::{AbilitySet, Visibility}; #[allow(deprecated)] use move_binary_format::normalized::Type as MType; @@ -85,6 +85,8 @@ use std::{ rc::Rc, }; +static DEBUG_TRACE: bool = true; + // ================================================================================================= /// # Constants @@ -200,13 +202,21 @@ impl Loc { && self.inlined_from_loc == other.inlined_from_loc && GlobalEnv::enclosing_span(self.span, other.span) } + + /// Returns true if this location is the default one. + pub fn is_default(&self) -> bool { + *self == Loc::default() + } } impl Default for Loc { fn default() -> Self { - let mut files = Files::new(); - let dummy_id = files.add(String::new(), String::new()); - Loc::new(dummy_id, Span::default()) + static DEFAULT: Lazy<Loc> = Lazy::new(|| { + let mut files = Files::new(); + let dummy_id = files.add(String::new(), String::new()); + Loc::new(dummy_id, Span::default()) + }); + DEFAULT.clone() } } @@ -884,11 +894,15 @@ impl GlobalEnv { }); if *DUMP_BACKTRACE { let bt = Backtrace::capture(); - if BacktraceStatus::Captured == bt.status() { + let msg_out = if BacktraceStatus::Captured == bt.status() { format!("{}\nBacktrace: {:#?}", msg, bt) } else { msg.to_owned() + }; + if DEBUG_TRACE { + debug!("{}", msg_out); } + msg_out } else { msg.to_owned() } @@ -1628,11 +1642,16 @@ impl GlobalEnv { FunId(self.symbol_pool.make(name_str)) }; - // While releasing any mutation, compute the called functions if needed. + // While releasing any mutation, compute the used/called functions if needed. let fun_data = &self.module_data[module_id.0 as usize] .function_data .get(&fun_id) .unwrap(); + let used_funs = if fun_data.used_funs.is_none() { + Some(self.get_used_funs_from_bytecode(&module, def_idx)) + } else { + None + }; let called_funs = if fun_data.called_funs.is_none() { Some(self.get_called_funs_from_bytecode(&module, def_idx)) } else { @@ -1644,6 +1663,9 @@ impl GlobalEnv { fun_data.def_idx = Some(def_idx); fun_data.handle_idx = Some(handle_idx); mod_data.function_idx_to_id.insert(def_idx, fun_id); + if let Some(used_funs) = used_funs { + fun_data.used_funs = Some(used_funs); + } if let Some(called_funs) = called_funs { fun_data.called_funs = Some(called_funs); } @@ -1660,6 +1682,15 @@ impl GlobalEnv { mod_data.source_map = Some(source_map); } + fn get_used_funs_from_bytecode( + &self, + module: &CompiledModule, + def_idx: FunctionDefinitionIndex, + ) -> BTreeSet<QualifiedId<FunId>> { + // TODO(LAMBDA) -- fix when we extend bytecode with function values + self.get_called_funs_from_bytecode(module, def_idx) + } + fn get_called_funs_from_bytecode( &self, module: &CompiledModule, @@ -1865,6 +1896,11 @@ impl GlobalEnv { self.get_module(fun.module_id).into_function(fun.id) } + pub fn get_function_opt(&self, fun: QualifiedId<FunId>) -> Option<FunctionEnv<'_>> { + self.get_module_opt(fun.module_id) + .map(|module| module.into_function(fun.id)) + } + /// Sets the AST based definition of the function. pub fn set_function_def(&mut self, fun: QualifiedId<FunId>, def: Exp) { let data = self @@ -1874,6 +1910,7 @@ impl GlobalEnv { .function_data .get_mut(&fun.id) .unwrap(); + data.used_funs = Some(def.used_funs()); data.called_funs = Some(def.called_funs()); data.def = Some(def); } @@ -1891,6 +1928,7 @@ impl GlobalEnv { result_type: Type, def: Exp, ) { + let used_funs = def.used_funs(); let called_funs = def.called_funs(); let data = FunctionData { name, @@ -1915,6 +1953,9 @@ impl GlobalEnv { called_funs: Some(called_funs), calling_funs: RefCell::new(None), transitive_closure_of_called_funs: RefCell::new(None), + used_funs: Some(used_funs), + using_funs: RefCell::new(None), + transitive_closure_of_used_funs: RefCell::new(None), }; assert!(self .module_data @@ -2032,6 +2073,15 @@ impl GlobalEnv { } } + /// Gets a module by id. + pub fn get_module_opt(&self, id: ModuleId) -> Option<ModuleEnv<'_>> { + let module_data = self.module_data.get(id.0 as usize); + module_data.map(|module_data| ModuleEnv { + env: self, + data: module_data, + }) + } + pub(crate) fn get_module_data_mut(&mut self, id: ModuleId) -> &mut ModuleData { &mut self.module_data[id.0 as usize] } @@ -2354,7 +2404,7 @@ impl GlobalEnv { // Removes all functions not matching the predicate from // module_data fields function_data and function_idx_to_id - // remaining function_data fields called_funs and calling_funs + // remaining function_data fields used_funs and using_funs pub fn filter_functions<F>(&mut self, mut predicate: F) where F: FnMut(&QualifiedId<FunId>) -> bool, @@ -2368,11 +2418,11 @@ impl GlobalEnv { .function_idx_to_id .retain(|_, fun_id| predicate(&module_id.qualified(*fun_id))); module_data.function_data.values_mut().for_each(|fun_data| { - if let Some(called_funs) = fun_data.called_funs.as_mut() { - called_funs.retain(|qfun_id| predicate(qfun_id)) + if let Some(used_funs) = fun_data.used_funs.as_mut() { + used_funs.retain(|qfun_id| predicate(qfun_id)) } - if let Some(calling_funs) = &mut *fun_data.calling_funs.borrow_mut() { - calling_funs.retain(|qfun_id| predicate(qfun_id)) + if let Some(using_funs) = &mut *fun_data.using_funs.borrow_mut() { + using_funs.retain(|qfun_id| predicate(qfun_id)) } }); } @@ -2608,7 +2658,7 @@ impl GlobalEnv { if let Some(exp) = fun_def { emitln!(writer, " {"); writer.indent(); - emitln!(writer, "{}", exp.display_for_fun(fun.clone())); + emitln!(writer, "{}", exp.display_for_fun(fun)); writer.unindent(); emitln!(writer, "}"); } else { @@ -2811,6 +2861,11 @@ impl<'env> ModuleEnv<'env> { &self.data.use_decls } + /// Returns the friend declarations of this module. + pub fn get_friend_decls(&self) -> &[FriendDecl] { + &self.data.friend_decls + } + /// Does this module declare `module_id` as a friend? pub fn has_friend(&self, module_id: &ModuleId) -> bool { self.data.friend_modules.contains(module_id) @@ -2921,7 +2976,7 @@ impl<'env> ModuleEnv<'env> { } /// Returns the set of modules in the current package, - /// whose public(package) functions are called in the current module. + /// whose public(package) functions are called or referenced in the current module. /// Requires: `self` is a primary target. pub fn need_to_be_friended_by(&self) -> BTreeSet<ModuleId> { debug_assert!(self.is_primary_target()); @@ -2930,17 +2985,18 @@ impl<'env> ModuleEnv<'env> { return deps; } for fun_env in self.get_functions() { - let called_funs = fun_env.get_called_functions().expect("called functions"); - for fun in called_funs { - let mod_id = fun.module_id; - if self.get_id() == mod_id { + for used_fun in fun_env.get_used_functions().expect("used functions") { + let used_mod_id = used_fun.module_id; + if self.get_id() == used_mod_id { // no need to friend self continue; } - let mod_env = self.env.get_module(mod_id); - let fun_env = mod_env.get_function(fun.id); - if fun_env.has_package_visibility() && self.can_call_package_fun_in(&mod_env) { - deps.insert(mod_id); + let used_mod_env = self.env.get_module(used_mod_id); + let used_fun_env = used_mod_env.get_function(used_fun.id); + if used_fun_env.has_package_visibility() + && self.can_call_package_fun_in(&used_mod_env) + { + deps.insert(used_mod_id); } } } @@ -3309,7 +3365,7 @@ impl<'env> ModuleEnv<'env> { self.data.module_spec.borrow() } - /// Returns whether a spec fun is ever called or not. + /// Returns whether a spec fun is ever called/referenced or not. pub fn spec_fun_is_used(&self, spec_fun_id: SpecFunId) -> bool { self.env .used_spec_funs @@ -4056,6 +4112,20 @@ impl Default for TypeParameterKind { #[derive(Debug, Clone, PartialEq, Eq)] pub struct Parameter(pub Symbol, pub Type, pub Loc); +impl Parameter { + pub fn get_name(&self) -> Symbol { + self.0 + } + + pub fn get_type(&self) -> Type { + self.1.clone() + } + + pub fn get_loc(&self) -> Loc { + self.2.clone() + } +} + impl EqIgnoringLoc for Parameter { /// equal ignoring Loc fn eq_ignoring_loc(&self, other: &Self) -> bool { @@ -4147,6 +4217,15 @@ pub struct FunctionData { /// A cache for the transitive closure of the called functions. pub(crate) transitive_closure_of_called_funs: RefCell<Option<BTreeSet<QualifiedId<FunId>>>>, + + /// A cache for the used functions. Used functions are those called or with values taken here. + pub(crate) used_funs: Option<BTreeSet<QualifiedId<FunId>>>, + + /// A cache for the using functions. Using functions are those which call or take value of this. + pub(crate) using_funs: RefCell<Option<BTreeSet<QualifiedId<FunId>>>>, + + /// A cache for the transitive closure of the used functions. + pub(crate) transitive_closure_of_used_funs: RefCell<Option<BTreeSet<QualifiedId<FunId>>>>, } impl FunctionData { @@ -4170,6 +4249,9 @@ impl FunctionData { called_funs: None, calling_funs: RefCell::new(None), transitive_closure_of_called_funs: RefCell::new(None), + used_funs: None, + using_funs: RefCell::new(None), + transitive_closure_of_used_funs: RefCell::new(None), } } } @@ -4790,6 +4872,58 @@ impl<'env> FunctionEnv<'env> { !matches!(scope, VerificationScope::Only(..)) && self.is_pragma_false(VERIFY_PRAGMA) } + /// Get the functions that use this one, if available. + pub fn get_using_functions(&self) -> Option<BTreeSet<QualifiedId<FunId>>> { + if let Some(using) = &*self.data.using_funs.borrow() { + return Some(using.clone()); + } + let mut set: BTreeSet<QualifiedId<FunId>> = BTreeSet::new(); + for module_env in self.module_env.env.get_modules() { + for fun_env in module_env.get_functions() { + if fun_env + .get_used_functions()? + .contains(&self.get_qualified_id()) + { + set.insert(fun_env.get_qualified_id()); + } + } + } + *self.data.using_funs.borrow_mut() = Some(set.clone()); + Some(set) + } + + /// Get the functions that this one uses, if available. + pub fn get_used_functions(&self) -> Option<&'_ BTreeSet<QualifiedId<FunId>>> { + self.data.used_funs.as_ref() + } + + /// Get the transitive closure of the used functions. This requires that all functions + /// in the closure have `get_used_functions` available; if one of them not, this + /// function panics. + pub fn get_transitive_closure_of_used_functions(&self) -> BTreeSet<QualifiedId<FunId>> { + if let Some(trans_used) = &*self.data.transitive_closure_of_used_funs.borrow() { + return trans_used.clone(); + } + + let mut set = BTreeSet::new(); + let mut reachable_funcs = VecDeque::new(); + reachable_funcs.push_back(self.clone()); + + // BFS in reachable_funcs to collect all reachable functions + while !reachable_funcs.is_empty() { + let fnc = reachable_funcs.pop_front().unwrap(); + for callee in fnc.get_used_functions().expect("call info available") { + let f = self.module_env.env.get_function(*callee); + let qualified_id = f.get_qualified_id(); + if set.insert(qualified_id) { + reachable_funcs.push_back(f.clone()); + } + } + } + *self.data.transitive_closure_of_used_funs.borrow_mut() = Some(set.clone()); + set + } + /// Get the functions that call this one, if available. pub fn get_calling_functions(&self) -> Option<BTreeSet<QualifiedId<FunId>>> { if let Some(calling) = &*self.data.calling_funs.borrow() { @@ -5035,6 +5169,20 @@ impl GetNameString for QualifiedId<SpecFunId> { } } +impl<'a, T> fmt::Display for EnvDisplay<'a, Vec<T>> +where + EnvDisplay<'a, T>: std::fmt::Display, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let xs = self + .val + .iter() + .map(|x| format!("{}", self.env.display(x))) + .collect_vec(); + write!(f, "({})", xs.iter().join(",")) + } +} + impl<'a, Id: Clone> fmt::Display for EnvDisplay<'a, QualifiedId<Id>> where QualifiedId<Id>: GetNameString, @@ -5069,3 +5217,15 @@ impl<'a> fmt::Display for EnvDisplay<'a, Symbol> { write!(f, "{}", self.val.display(self.env.symbol_pool())) } } + +impl<'a> fmt::Display for EnvDisplay<'a, Parameter> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let p = self.val; + write!( + f, + "{}:{}", + p.get_name().display(self.env.symbol_pool()), + p.get_type().display(&self.env.get_type_display_ctx()) + ) + } +} diff --git a/third_party/move/move-model/src/sourcifier.rs b/third_party/move/move-model/src/sourcifier.rs index d185f1dd2db4e..fb5e2754c9d7c 100644 --- a/third_party/move/move-model/src/sourcifier.rs +++ b/third_party/move/move-model/src/sourcifier.rs @@ -4,7 +4,8 @@ use crate::{ ast::{ - AddressSpecifier, Exp, ExpData, Operation, Pattern, ResourceSpecifier, TempIndex, Value, + self, AddressSpecifier, Exp, ExpData, LambdaCaptureKind, Operation, Pattern, + ResourceSpecifier, TempIndex, Value, }, code_writer::CodeWriter, emit, emitln, @@ -284,6 +285,15 @@ impl<'a> Sourcifier<'a> { emit!(self.writer, "{}", self.env().display(address)) }) }, + Value::Function(mid, fid) => { + emit!( + self.writer, + "{}", + self.env() + .get_function(mid.qualified(*fid)) + .get_full_name_str() + ); + }, } } @@ -525,9 +535,22 @@ impl<'a> ExpSourcifier<'a> { match exp.as_ref() { // Following forms are all atomic and do not require parenthesis Invalid(_) => emit!(self.wr(), "*invalid*"), - Value(_, v) => { + Value(id, v) => { let ty = self.env().get_node_type(exp.node_id()); - self.parent.print_value(v, Some(&ty)) + self.parent.print_value(v, Some(&ty)); + if let ast::Value::Function(..) = v { + let type_inst = self.env().get_node_instantiation(*id); + if !type_inst.is_empty() { + emit!( + self.wr(), + "<{}>", + type_inst + .iter() + .map(|ty| ty.display(&self.type_display_context)) + .join(", ") + ); + } + } }, LocalVar(_, name) => { emit!(self.wr(), "{}", self.sym(*name)) @@ -540,12 +563,19 @@ impl<'a> ExpSourcifier<'a> { } }, // Following forms may require parenthesis - Lambda(_, pat, body) => { + Lambda(_, pat, body, capture_kind, abilities) => { self.parenthesize(context_prio, Prio::General, || { + if *capture_kind != LambdaCaptureKind::Default { + emit!(self.wr(), "{} ", capture_kind); + }; emit!(self.wr(), "|"); self.print_pat(pat); emit!(self.wr(), "| "); - self.print_exp(Prio::General, true, body) + self.print_exp(Prio::General, true, body); + if !abilities.is_subset(AbilitySet::FUNCTIONS) { + let abilities_as_str = abilities.iter().map(|a| a.to_string()).join("+"); + emit!(self.wr(), " with {}", abilities_as_str); + } }); }, Block(..) | Sequence(..) => { @@ -793,6 +823,11 @@ impl<'a> ExpSourcifier<'a> { self.print_exp_list("(", ")", args) }) }, + Operation::EarlyBind => self.parenthesize(context_prio, Prio::Postfix, || { + emit!(self.wr(), "earlybind"); + self.print_node_inst(id); + self.print_exp_list("(", ")", args) + }), Operation::Pack(mid, sid, variant) => { self.parenthesize(context_prio, Prio::Postfix, || { let qid = mid.qualified_inst(*sid, self.env().get_node_instantiation(id)); @@ -962,7 +997,6 @@ impl<'a> ExpSourcifier<'a> { | Operation::EventStoreIncludes | Operation::EventStoreIncludedIn | Operation::SpecFunction(_, _, _) - | Operation::Closure(_, _) | Operation::UpdateField(_, _, _) | Operation::Result(_) | Operation::Index @@ -1024,7 +1058,11 @@ impl<'a> ExpSourcifier<'a> { self.parenthesize(context_prio, prio, || { self.print_exp(prio, false, &args[0]); emit!(self.wr(), " {} ", repr); - self.print_exp(prio + 1, false, &args[1]) + if args.len() > 1 { + self.print_exp(prio + 1, false, &args[1]) + } else { + emit!(self.wr(), "ERROR") + } }) } diff --git a/third_party/move/move-model/src/ty.rs b/third_party/move/move-model/src/ty.rs index 6e947c60d7442..485bd3c273a96 100644 --- a/third_party/move/move-model/src/ty.rs +++ b/third_party/move/move-model/src/ty.rs @@ -44,7 +44,11 @@ pub enum Type { Vector(Box<Type>), Struct(ModuleId, StructId, /*type-params*/ Vec<Type>), TypeParameter(u16), - Fun(/*args*/ Box<Type>, /*result*/ Box<Type>), + Fun( + /* known args */ Box<Type>, + /*result*/ Box<Type>, + AbilitySet, + ), // Types only appearing in programs. Reference(ReferenceKind, Box<Type>), @@ -968,7 +972,7 @@ impl Type { use Type::*; match self { Primitive(p) => p.is_spec(), - Fun(args, result) => args.is_spec() || result.is_spec(), + Fun(args, result, _) => args.is_spec() || result.is_spec(), TypeDomain(..) | ResourceDomain(..) | Error => true, Var(..) | TypeParameter(..) => false, Tuple(ts) => ts.iter().any(|t| t.is_spec()), @@ -1195,9 +1199,10 @@ impl Type { Type::Reference(*kind, Box::new(bt.replace(params, subs, use_constr))) }, Type::Struct(mid, sid, args) => Type::Struct(*mid, *sid, replace_vec(args)), - Type::Fun(arg, result) => Type::Fun( + Type::Fun(arg, result, abilities) => Type::Fun( Box::new(arg.replace(params, subs, use_constr)), Box::new(result.replace(params, subs, use_constr)), + *abilities, ), Type::Tuple(args) => Type::Tuple(replace_vec(args)), Type::Vector(et) => Type::Vector(Box::new(et.replace(params, subs, use_constr))), @@ -1223,7 +1228,7 @@ impl Type { match self { Type::Reference(_, bt) => bt.contains(p), Type::Struct(_, _, args) => contains_vec(args), - Type::Fun(arg, result) => arg.contains(p) || result.contains(p), + Type::Fun(arg, result, _) => arg.contains(p) || result.contains(p), Type::Tuple(args) => contains_vec(args), Type::Vector(et) => et.contains(p), _ => false, @@ -1237,7 +1242,7 @@ impl Type { match self { Var(_) => true, Tuple(ts) => ts.iter().any(|t| t.is_incomplete()), - Fun(a, r) => a.is_incomplete() || r.is_incomplete(), + Fun(a, r, _) => a.is_incomplete() || r.is_incomplete(), Struct(_, _, ts) => ts.iter().any(|t| t.is_incomplete()), Vector(et) => et.is_incomplete(), Reference(_, bt) => bt.is_incomplete(), @@ -1258,7 +1263,7 @@ impl Type { use Type::*; match self { Tuple(ts) => ts.iter().for_each(|t| t.module_usage(usage)), - Fun(a, r) => { + Fun(a, r, _) => { a.module_usage(usage); r.module_usage(usage); }, @@ -1424,7 +1429,7 @@ impl Type { vars.insert(*id); }, Tuple(ts) => ts.iter().for_each(|t| t.internal_get_vars(vars)), - Fun(a, r) => { + Fun(a, r, _) => { a.internal_get_vars(vars); r.internal_get_vars(vars); }, @@ -1447,7 +1452,7 @@ impl Type { Type::Vector(bt) => bt.visit(visitor), Type::Struct(_, _, tys) => visit_slice(tys, visitor), Type::Reference(_, ty) => ty.visit(visitor), - Type::Fun(a, ty) => { + Type::Fun(a, ty, _) => { a.visit(visitor); ty.visit(visitor); }, @@ -2050,7 +2055,10 @@ impl Substitution { Ok(()) } }, - Fun(_, _) => check(AbilitySet::FUNCTIONS), + Fun(_, _, abilities) => { + assert!(AbilitySet::FUNCTIONS.is_subset(*abilities)); + check(*abilities) + }, Reference(_, _) => check(AbilitySet::REFERENCES), TypeDomain(_) | ResourceDomain(_, _, _) => check(AbilitySet::EMPTY), Error => Ok(()), @@ -2312,13 +2320,15 @@ impl Substitution { .map_err(TypeUnificationError::lift(order, t1, t2))?, )); }, - (Type::Fun(a1, r1), Type::Fun(a2, r2)) => { + (Type::Fun(a1, r1, abilities1), Type::Fun(a2, r2, abilities2)) => { // Same as for tuples, we pass on `variance` not `sub_variance`, allowing // conversion for arguments. We also have contra-variance of arguments: // |T1|R1 <= |T2|R2 <==> T1 >= T2 && R1 <= R2 // Intuitively, function f1 can safely _substitute_ function f2 if any argument // of type T2 can be passed as a T1 -- which is the case since T1 >= T2 (every // T2 is also a T1). + // + // We test for abilities match last, to give more intuitive error messages. return Ok(Type::Fun( Box::new( self.unify(context, variance, order.swap(), a1, a2) @@ -2328,6 +2338,25 @@ impl Substitution { self.unify(context, variance, order, r1, r2) .map_err(TypeUnificationError::lift(order, t1, t2))?, ), + { + // Widening/conversion can remove abilities, not add them. So check that + // the target has no more abilities than the source. + let (missing_abilities, bad_ty) = match order { + WideningOrder::LeftToRight => (abilities2.setminus(*abilities1), t1), + WideningOrder::RightToLeft => (abilities1.setminus(*abilities2), t2), + WideningOrder::Join => (AbilitySet::EMPTY, t1), + }; + if missing_abilities.is_empty() { + abilities1.intersect(*abilities2) + } else { + return Err(TypeUnificationError::MissingAbilities( + Loc::default(), + bad_ty.clone(), + missing_abilities, + None, + )); + } + }, )); }, (Type::Struct(m1, s1, ts1), Type::Struct(m2, s2, ts2)) => { @@ -2980,6 +3009,7 @@ impl TypeUnificationError { | TypeUnificationError::MissingAbilities(loc, ..) => Some(loc.clone()), _ => None, } + .and_then(|loc| if loc.is_default() { None } else { Some(loc) }) } /// Return the message for this error. @@ -3584,12 +3614,22 @@ impl<'a> fmt::Display for TypeDisplay<'a> { } f.write_str(">") }, - Fun(a, t) => { + Fun(a, t, abilities) => { f.write_str("|")?; write!(f, "{}", a.display(self.context))?; f.write_str("|")?; if !t.is_unit() { - write!(f, "{}", t.display(self.context)) + write!(f, "{}", t.display(self.context))?; + } + if !abilities.is_subset(AbilitySet::FUNCTIONS) { + // Default formatter for Abilities is not compact, manually convert here. + let abilities_as_str = abilities + .setminus(AbilitySet::FUNCTIONS) + .iter() + .map(|a| a.to_string()) + .reduce(|l, r| format!("{}+{}", l, r)) + .unwrap_or_default(); + write!(f, " with {}", abilities_as_str) } else { Ok(()) } @@ -3731,7 +3771,7 @@ pub trait AbilityInference: AbilityContext { /// Infers the abilities of the type. The returned boolean indicates whether /// the type is a phantom type parameter, fn infer_abilities(&self, ty: &Type) -> (bool, AbilitySet) { - match ty { + let res = match ty { Type::Primitive(p) => match p { PrimitiveType::Bool | PrimitiveType::U8 @@ -3767,10 +3807,12 @@ pub trait AbilityInference: AbilityContext { .reduce(|a, b| a.intersect(b)) .unwrap_or(AbilitySet::PRIMITIVES), ), - Type::Fun(_, _) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error => { + Type::Fun(_, _, abilities) => (false, *abilities), + Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error => { (false, AbilitySet::EMPTY) }, - } + }; + res } fn infer_struct_abilities(&self, qid: QualifiedId<StructId>, ty_args: &[Type]) -> AbilitySet { diff --git a/third_party/move/move-model/tests/sources/expressions_err.exp b/third_party/move/move-model/tests/sources/expressions_err.exp index e9ce7d95a641f..7de3fb7c474b4 100644 --- a/third_party/move/move-model/tests/sources/expressions_err.exp +++ b/third_party/move/move-model/tests/sources/expressions_err.exp @@ -34,7 +34,7 @@ error: cannot pass `u256` to a function which expects argument of type `bool` 37 │ fun wrongly_typed_caller(): num { wrongly_typed_callee(1, 1) } │ ^ -error: cannot pass `|num|bool` to a function which expects argument of type `|num|num` +error: cannot pass `|num|bool with copy+store` to a function which expects argument of type `|num|num` ┌─ tests/sources/expressions_err.move:41:76 │ 41 │ fun wrongly_typed_fun_arg_caller(): num { wrongly_typed_fun_arg_callee(|x| false) } diff --git a/third_party/move/move-model/tests/sources/expressions_err.v2_exp b/third_party/move/move-model/tests/sources/expressions_err.v2_exp index e9ce7d95a641f..7de3fb7c474b4 100644 --- a/third_party/move/move-model/tests/sources/expressions_err.v2_exp +++ b/third_party/move/move-model/tests/sources/expressions_err.v2_exp @@ -34,7 +34,7 @@ error: cannot pass `u256` to a function which expects argument of type `bool` 37 │ fun wrongly_typed_caller(): num { wrongly_typed_callee(1, 1) } │ ^ -error: cannot pass `|num|bool` to a function which expects argument of type `|num|num` +error: cannot pass `|num|bool with copy+store` to a function which expects argument of type `|num|num` ┌─ tests/sources/expressions_err.move:41:76 │ 41 │ fun wrongly_typed_fun_arg_caller(): num { wrongly_typed_fun_arg_callee(|x| false) } diff --git a/third_party/move/move-prover/boogie-backend/src/boogie_helpers.rs b/third_party/move/move-prover/boogie-backend/src/boogie_helpers.rs index 0062a401306a7..0b58373ba8267 100644 --- a/third_party/move/move-prover/boogie-backend/src/boogie_helpers.rs +++ b/third_party/move/move-prover/boogie-backend/src/boogie_helpers.rs @@ -592,6 +592,7 @@ pub fn boogie_value(env: &GlobalEnv, _options: &BoogieOptions, val: &Value) -> S .collect_vec(), ), Value::Tuple(vec) => format!("<<unsupported Tuple({:?})>>", vec), + Value::Function(mid, fid) => format!("<unsupported Function({:?}, {:?}>", mid, fid), // TODO(LAMBDA) } } diff --git a/third_party/move/move-prover/boogie-backend/src/boogie_wrapper.rs b/third_party/move/move-prover/boogie-backend/src/boogie_wrapper.rs index c2a45a85651b1..bf8d80391edb4 100644 --- a/third_party/move/move-prover/boogie-backend/src/boogie_wrapper.rs +++ b/third_party/move/move-prover/boogie-backend/src/boogie_wrapper.rs @@ -1436,7 +1436,7 @@ impl ModelValue { }, Type::Tuple(_) | Type::Primitive(_) - | Type::Fun(_, _) + | Type::Fun(..) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error diff --git a/third_party/move/move-prover/boogie-backend/src/bytecode_translator.rs b/third_party/move/move-prover/boogie-backend/src/bytecode_translator.rs index c6f7d71839415..350e912f8f284 100644 --- a/third_party/move/move-prover/boogie-backend/src/bytecode_translator.rs +++ b/third_party/move/move-prover/boogie-backend/src/bytecode_translator.rs @@ -2071,7 +2071,7 @@ impl<'env> FunctionTranslator<'env> { | Type::Struct(_, _, _) | Type::TypeParameter(_) | Type::Reference(_, _) - | Type::Fun(_, _) + | Type::Fun(..) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error @@ -2108,7 +2108,7 @@ impl<'env> FunctionTranslator<'env> { | Type::Struct(_, _, _) | Type::TypeParameter(_) | Type::Reference(_, _) - | Type::Fun(_, _) + | Type::Fun(..) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error @@ -2165,7 +2165,7 @@ impl<'env> FunctionTranslator<'env> { | Type::Struct(_, _, _) | Type::TypeParameter(_) | Type::Reference(_, _) - | Type::Fun(_, _) + | Type::Fun(..) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error @@ -2202,7 +2202,7 @@ impl<'env> FunctionTranslator<'env> { | Type::Struct(_, _, _) | Type::TypeParameter(_) | Type::Reference(_, _) - | Type::Fun(_, _) + | Type::Fun(..) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error @@ -2242,7 +2242,7 @@ impl<'env> FunctionTranslator<'env> { | Type::Struct(_, _, _) | Type::TypeParameter(_) | Type::Reference(_, _) - | Type::Fun(_, _) + | Type::Fun(..) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error @@ -2283,7 +2283,7 @@ impl<'env> FunctionTranslator<'env> { | Type::Struct(_, _, _) | Type::TypeParameter(_) | Type::Reference(_, _) - | Type::Fun(_, _) + | Type::Fun(..) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error @@ -2314,7 +2314,7 @@ impl<'env> FunctionTranslator<'env> { | Type::Struct(_, _, _) | Type::TypeParameter(_) | Type::Reference(_, _) - | Type::Fun(_, _) + | Type::Fun(..) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error @@ -2354,7 +2354,7 @@ impl<'env> FunctionTranslator<'env> { | Type::Struct(_, _, _) | Type::TypeParameter(_) | Type::Reference(_, _) - | Type::Fun(_, _) + | Type::Fun(..) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error @@ -2448,7 +2448,7 @@ impl<'env> FunctionTranslator<'env> { | Type::Struct(_, _, _) | Type::TypeParameter(_) | Type::Reference(_, _) - | Type::Fun(_, _) + | Type::Fun(..) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error @@ -3017,7 +3017,7 @@ pub fn has_native_equality(env: &GlobalEnv, options: &BoogieOptions, ty: &Type) | Type::Tuple(_) | Type::TypeParameter(_) | Type::Reference(_, _) - | Type::Fun(_, _) + | Type::Fun(..) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error diff --git a/third_party/move/move-prover/boogie-backend/src/spec_translator.rs b/third_party/move/move-prover/boogie-backend/src/spec_translator.rs index 43e54ef7ceff7..b674d30b855b9 100644 --- a/third_party/move/move-prover/boogie-backend/src/spec_translator.rs +++ b/third_party/move/move-prover/boogie-backend/src/spec_translator.rs @@ -528,7 +528,7 @@ impl<'env> SpecTranslator<'env> { | Type::Struct(_, _, _) | Type::TypeParameter(_) | Type::Reference(_, _) - | Type::Fun(_, _) + | Type::Fun(..) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error @@ -774,6 +774,10 @@ impl<'env> SpecTranslator<'env> { let loc = self.env.get_node_loc(node_id); self.error(&loc, &format!("tuple value not yet supported: {:#?}", val)) }, + Value::Function(_mid, _fid) => { + let loc = self.env.get_node_loc(node_id); + self.error(&loc, "Function values not yet supported") // TODO(LAMBDA) + }, } } @@ -836,7 +840,6 @@ impl<'env> SpecTranslator<'env> { .get_extension::<GlobalNumberOperationState>() .expect("global number operation state"); match oper { - Operation::Closure(..) => unimplemented!("closures in specs"), // Operators we introduced in the top level public entry `SpecTranslator::translate`, // mapping between Boogies single value domain and our typed world. Operation::BoxValue | Operation::UnboxValue => panic!("unexpected box/unbox"), @@ -1012,6 +1015,7 @@ impl<'env> SpecTranslator<'env> { | Operation::Deref | Operation::MoveTo | Operation::MoveFrom + | Operation::EarlyBind | Operation::Old => { self.env.error( &self.env.get_node_loc(node_id), @@ -1464,7 +1468,7 @@ impl<'env> SpecTranslator<'env> { | Type::Tuple(_) | Type::TypeParameter(_) | Type::Reference(_, _) - | Type::Fun(_, _) + | Type::Fun(..) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error @@ -1627,7 +1631,7 @@ impl<'env> SpecTranslator<'env> { | Type::Tuple(_) | Type::TypeParameter(_) | Type::Reference(_, _) - | Type::Fun(_, _) + | Type::Fun(..) | Type::Error | Type::Var(_) => panic!("unexpected type"), } diff --git a/third_party/move/move-prover/bytecode-pipeline/src/memory_instrumentation.rs b/third_party/move/move-prover/bytecode-pipeline/src/memory_instrumentation.rs index 0839554ad8db5..5b94625163859 100644 --- a/third_party/move/move-prover/bytecode-pipeline/src/memory_instrumentation.rs +++ b/third_party/move/move-prover/bytecode-pipeline/src/memory_instrumentation.rs @@ -99,7 +99,7 @@ impl<'a> Instrumenter<'a> { | Tuple(_) | TypeParameter(_) | Reference(_, _) - | Fun(_, _) + | Fun(..) | TypeDomain(_) | ResourceDomain(_, _, _) | Error diff --git a/third_party/move/move-prover/move-abigen/src/abigen.rs b/third_party/move/move-prover/move-abigen/src/abigen.rs index bcc86cd7ae149..c4af6d2ae4e4a 100644 --- a/third_party/move/move-prover/move-abigen/src/abigen.rs +++ b/third_party/move/move-prover/move-abigen/src/abigen.rs @@ -324,7 +324,7 @@ impl<'env> Abigen<'env> { }, Tuple(_) | TypeParameter(_) - | Fun(_, _) + | Fun(..) | TypeDomain(_) | ResourceDomain(..) | Error diff --git a/third_party/move/move-prover/move-docgen/src/docgen.rs b/third_party/move/move-prover/move-docgen/src/docgen.rs index 88aa960f6a468..c0941a2b946ee 100644 --- a/third_party/move/move-prover/move-docgen/src/docgen.rs +++ b/third_party/move/move-prover/move-docgen/src/docgen.rs @@ -925,9 +925,9 @@ impl<'env> Docgen<'env> { let curr_env = self.env.get_function(id); let curr_name = name_of(&curr_env); let next_list = if is_forward { - curr_env.get_called_functions().cloned().unwrap_or_default() + curr_env.get_used_functions().cloned().unwrap_or_default() } else { - curr_env.get_calling_functions().unwrap_or_default() + curr_env.get_using_functions().unwrap_or_default() }; if fun_env.module_env.get_id() == curr_env.module_env.get_id() {