From d564d474fa602739c4f2ac407a48b1058b89d8f4 Mon Sep 17 00:00:00 2001 From: "Brian R. Murphy" <132495859+brmataptos@users.noreply.github.com> Date: Fri, 27 Sep 2024 21:43:52 -0700 Subject: [PATCH] add parser code for lambda types --- .../move/evm/move-to-yul/src/context.rs | 2 +- .../move/evm/move-to-yul/src/solidity_ty.rs | 2 +- .../src/bytecode_generator.rs | 38 ++-- .../src/env_pipeline/ast_simplifier.rs | 2 +- .../env_pipeline/flow_insensitive_checkers.rs | 2 +- .../src/env_pipeline/function_checker.rs | 6 +- .../src/env_pipeline/inliner.rs | 2 +- .../src/env_pipeline/lambda_lifter.rs | 44 ++-- .../src/env_pipeline/unused_params_checker.rs | 21 +- .../file_format_generator/module_generator.rs | 2 +- .../invalid_call_lhs_complex_expression.exp | 15 +- .../invalid_call_lhs_complex_expression2.exp | 15 +- .../invalid_call_lhs_parens_around_name.exp | 9 +- .../invalid_call_lhs_parens_around_name2.exp | 9 +- .../parser/invalid_call_lhs_return.exp | 9 +- .../parser/invalid_call_lhs_return2.exp | 9 +- .../more-v1/parser/invalid_call_lhs_value.exp | 15 +- .../parser/invalid_call_lhs_value2.exp | 15 +- ...oken_after_ability_function_constraint.exp | 7 +- .../move/move-compiler/src/expansion/ast.rs | 71 +++--- .../src/expansion/dependency_ordering.rs | 8 +- .../move-compiler/src/expansion/translate.rs | 205 ++++++++++-------- .../move-compiler/src/naming/translate.rs | 21 +- .../move/move-compiler/src/parser/ast.rs | 59 +++-- .../move/move-compiler/src/parser/syntax.rs | 63 +++--- .../invalid_call_lhs_complex_expression.exp | 21 +- .../invalid_call_lhs_complex_expression2.exp | 15 +- .../invalid_call_lhs_parens_around_name.exp | 15 +- .../invalid_call_lhs_parens_around_name2.exp | 9 +- .../parser/invalid_call_lhs_return.exp | 15 +- .../parser/invalid_call_lhs_return2.exp | 9 +- .../parser/invalid_call_lhs_value.exp | 21 +- .../parser/invalid_call_lhs_value2.exp | 15 +- ...oken_after_ability_function_constraint.exp | 7 +- third_party/move/move-model/src/ast.rs | 26 ++- .../move-model/src/builder/exp_builder.rs | 103 ++++++--- .../move/move-model/src/exp_rewriter.rs | 55 +++-- third_party/move/move-model/src/ty.rs | 44 ++-- .../boogie-backend/src/boogie_wrapper.rs | 2 +- .../boogie-backend/src/bytecode_translator.rs | 45 ++-- .../boogie-backend/src/spec_translator.rs | 6 +- .../src/memory_instrumentation.rs | 2 +- .../move-prover/move-abigen/src/abigen.rs | 2 +- 43 files changed, 652 insertions(+), 411 deletions(-) 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-compiler-v2/src/bytecode_generator.rs b/third_party/move/move-compiler-v2/src/bytecode_generator.rs index 2b024cb47991d..317889024f90d 100644 --- a/third_party/move/move-compiler-v2/src/bytecode_generator.rs +++ b/third_party/move/move-compiler-v2/src/bytecode_generator.rs @@ -483,7 +483,7 @@ 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", ), @@ -1334,9 +1334,12 @@ impl<'env> Generator<'env> { }; self.gen_borrow_field_operation(id, borrow_dest, str, fields, oper_temp); if need_read_ref { - self.emit_call(id, vec![target], BytecodeOperation::ReadRef, vec![ - borrow_dest, - ]) + self.emit_call( + id, + vec![target], + BytecodeOperation::ReadRef, + vec![borrow_dest], + ) } } @@ -1524,10 +1527,13 @@ enum MatchMode { impl MatchMode { /// Whether this match is in probing mode. fn is_probing(&self) -> bool { - matches!(self, MatchMode::Refutable { - probing_vars: Some(_), - .. - }) + matches!( + self, + MatchMode::Refutable { + probing_vars: Some(_), + .. + } + ) } /// Whether a variable appearing in the pattern should be bound to a temporary. @@ -1655,9 +1661,12 @@ impl<'env> Generator<'env> { ReferenceKind::Immutable, Box::new(value_ty.clone()), )); - self.emit_call(id, vec![value_ref], BytecodeOperation::BorrowLoc, vec![ - value, - ]); + self.emit_call( + id, + vec![value_ref], + BytecodeOperation::BorrowLoc, + vec![value], + ); needs_probing = true; value_ref } @@ -1779,10 +1788,11 @@ impl<'env> Generator<'env> { ), ); return Some( - ExpData::Call(id, Operation::Deref, vec![ExpData::LocalVar( - new_id, var, + ExpData::Call( + id, + Operation::Deref, + vec![ExpData::LocalVar(new_id, var).into_exp()], ) - .into_exp()]) .into_exp(), ); } 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..6b679c8da1525 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 => { 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..07cd34081d3a7 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..3a3987ca63c63 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 @@ -20,7 +20,7 @@ fn identify_function_types_with_functions_in_args(func_types: Vec) -> Vec< func_types .into_iter() .filter_map(|ty| { - if let Type::Fun(argt, _) = &ty { + if let Type::Fun(argt, _, _) = &ty { if argt.deref().has_function() { Some(ty) } else { @@ -41,7 +41,7 @@ fn identify_function_typed_params_with_functions_in_rets( func_types .iter() .filter_map(|param| { - if let Type::Fun(_argt, rest) = ¶m.1 { + if let Type::Fun(_argt, rest, _) = ¶m.1 { let rest_unboxed = rest.deref(); if rest_unboxed.has_function() { Some((*param, rest_unboxed)) @@ -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; 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 77a4ce7eefede..2c71fcce589c1 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 @@ -1156,7 +1156,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 = 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..eb70934815c3b 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 @@ -40,6 +40,7 @@ //! ``` use itertools::Itertools; +use move_binary_format::file_format::AbilitySet; use move_binary_format::file_format::Visibility; use move_model::{ ast::{Exp, ExpData, Operation, Pattern, TempIndex}, @@ -259,10 +260,13 @@ impl<'a> ExpRewriterFunctions for LambdaLifter<'a> { fn rewrite_assign(&mut self, _node_id: NodeId, lhs: &Pattern, _rhs: &Exp) -> Option { for (node_id, name) in lhs.vars() { - self.free_locals.insert(name, VarInfo { - node_id, - modified: true, - }); + self.free_locals.insert( + name, + VarInfo { + node_id, + modified: true, + }, + ); } None } @@ -271,16 +275,22 @@ impl<'a> ExpRewriterFunctions for LambdaLifter<'a> { if matches!(oper, Operation::Borrow(ReferenceKind::Mutable)) { match args[0].as_ref() { ExpData::LocalVar(node_id, name) => { - self.free_locals.insert(*name, VarInfo { - node_id: *node_id, - modified: true, - }); + self.free_locals.insert( + *name, + VarInfo { + node_id: *node_id, + modified: true, + }, + ); }, ExpData::Temporary(node_id, param) => { - self.free_params.insert(*param, VarInfo { - node_id: *node_id, - modified: true, - }); + self.free_params.insert( + *param, + VarInfo { + node_id: *node_id, + modified: true, + }, + ); }, _ => {}, } @@ -288,7 +298,13 @@ impl<'a> ExpRewriterFunctions for LambdaLifter<'a> { None } - fn rewrite_lambda(&mut self, id: NodeId, pat: &Pattern, body: &Exp) -> Option { + fn rewrite_lambda( + &mut self, + id: NodeId, + pat: &Pattern, + body: &Exp, + _abilities: AbilitySet, // TODO(LAMBDA): do something with this + ) -> Option { if self.exempted_lambdas.contains(&id) { return None; } @@ -356,7 +372,7 @@ impl<'a> ExpRewriterFunctions for LambdaLifter<'a> { 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 result_type = if let Type::Fun(_, result_type, _) = &lambda_type { *result_type.clone() } else { Type::Error // type error reported 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..6d73f23a50e3c 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 @@ -32,13 +32,18 @@ fn check_unused_params(struct_env: &StructEnv) { for (i, TypeParameter(name, kind, loc)) in struct_env.get_type_parameters().iter().enumerate() { if !kind.is_phantom && !used_params_in_fields.contains(&(i as u16)) { let name = name.display(struct_env.symbol_pool()); - env.diag_with_labels(Severity::Warning, loc, "unused type parameter", vec![( - loc.clone(), - format!( - "Unused type parameter `{}`. Consider declaring it as phantom", - name - ), - )]); + env.diag_with_labels( + Severity::Warning, + loc, + "unused type parameter", + vec![( + loc.clone(), + format!( + "Unused type parameter `{}`. Consider declaring it as phantom", + name + ), + )], + ); } } } @@ -60,7 +65,7 @@ fn used_type_parameters_in_ty(ty: &Type) -> BTreeSet { }, 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 483020e61a99e..635636cbb93f9 100644 --- a/third_party/move/move-compiler-v2/src/file_format_generator/module_generator.rs +++ b/third_party/move/move-compiler-v2/src/file_format_generator/module_generator.rs @@ -365,7 +365,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, 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..cc556f788c76c 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,13 @@ 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:9 │ 3 │ (if (true) 5 else 0)(); - │ ^ - │ │ - │ Unexpected '(' - │ Expected ';' + │ ^^^^^^^^^^^^^^^^^^^^^^ + +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..f9bd44939a1a8 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,13 @@ 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:9 │ 3 │ (if (true) 5 else 0)(); - │ ^ - │ │ - │ Unexpected '(' - │ Expected ';' + │ ^^^^^^^^^^^^^^^^^^^^^^ + +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..e86d08c0250ef 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: undeclared `foo` + ┌─ tests/more-v1/parser/invalid_call_lhs_parens_around_name.move:3:10 │ 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..483fe4de5d478 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: undeclared `foo` + ┌─ tests/more-v1/parser/invalid_call_lhs_parens_around_name2.move:3:10 │ 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..0d8f8e057c68b 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..52bca969403f5 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..9a9a96a0285a4 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..63bab502411bb 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/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() {} - │ ^ - │ │ - │ Unexpected '&' - │ Expected one of: '+', '>', or ',' + │ - ^ Expected '>' + │ │ + │ To match this '<' diff --git a/third_party/move/move-compiler/src/expansion/ast.rs b/third_party/move/move-compiler/src/expansion/ast.rs index 880234d6fc715..e612069665010 100644 --- a/third_party/move/move-compiler/src/expansion/ast.rs +++ b/third_party/move/move-compiler/src/expansion/ast.rs @@ -402,7 +402,7 @@ pub enum Type_ { Multiple(Vec), Apply(ModuleAccess, Vec), Ref(bool, Box), - Fun(Vec, Box), + Fun(Vec, Box, AbilitySet), UnresolvedError, } pub type Type = Spanned; @@ -499,6 +499,7 @@ pub enum Exp_ { Name(ModuleAccess, Option>), Call(ModuleAccess, CallKind, Option>, Spanned>), + ExpCall(Box, Spanned>), Pack(ModuleAccess, Option>, Fields), Vector(Loc, Option>, Spanned>), @@ -507,7 +508,7 @@ pub enum Exp_ { While(Box, Box), Loop(Box), Block(Sequence), - Lambda(TypedLValueList, Box), + Lambda(TypedLValueList, Box, AbilitySet), Quant( QuantKind, LValueWithRangeList, @@ -900,12 +901,27 @@ impl fmt::Display for ModuleAccess_ { impl fmt::Display for Visibility { fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", match &self { - Visibility::Public(_) => Visibility::PUBLIC, - Visibility::Package(_) => Visibility::PACKAGE, - Visibility::Friend(_) => Visibility::FRIEND, - Visibility::Internal => Visibility::INTERNAL, - }) + write!( + f, + "{}", + match &self { + Visibility::Public(_) => Visibility::PUBLIC, + Visibility::Package(_) => Visibility::PACKAGE, + Visibility::Friend(_) => Visibility::FRIEND, + Visibility::Internal => Visibility::INTERNAL, + } + ) + } +} + +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(()) + } } } @@ -917,19 +933,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)) }, } } @@ -1064,13 +1079,11 @@ impl AstDebug for ModuleDefinition { w.writeln(&format!("{}", n)) } attributes.ast_debug(w); - w.writeln( - if *is_source_module { - "source module" - } else { - "library module" - }, - ); + w.writeln(if *is_source_module { + "source module" + } else { + "library module" + }); w.writeln(&format!("dependency order #{}", dependency_order)); for (mident, neighbor) in immediate_neighbors.key_cloned_iter() { w.write(&format!("{} {};", neighbor, mident)); @@ -1445,11 +1458,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("_|_"), } @@ -1610,6 +1624,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 { @@ -1669,11 +1689,12 @@ impl AstDebug for Exp_ { } }, E::Block(seq) => w.block(|w| seq.ast_debug(w)), - E::Lambda(sp!(_, bs), e) => { + E::Lambda(sp!(_, bs), e, abilities) => { 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 9912bd62634ff..25a02e0a1b68e 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, _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 12cc0f80cc2af..6e0a2e01b076a 100644 --- a/third_party/move/move-compiler/src/expansion/translate.rs +++ b/third_party/move/move-compiler/src/expansion/translate.rs @@ -816,17 +816,20 @@ fn attribute( ) -> Option { use E::Attribute_ as EA; use P::Attribute_ as PA; - Some(sp(loc, match attribute_ { - PA::Name(n) => EA::Name(n), - PA::Assigned(n, v) => EA::Assigned(n, Box::new(attribute_value(context, *v)?)), - PA::Parameterized(n, sp!(_, pattrs_)) => { - let attrs = pattrs_ - .into_iter() - .map(|a| attribute(context, attr_position, a)) - .collect::>>()?; - EA::Parameterized(n, unique_attributes(context, attr_position, true, attrs)) + Some(sp( + loc, + match attribute_ { + PA::Name(n) => EA::Name(n), + PA::Assigned(n, v) => EA::Assigned(n, Box::new(attribute_value(context, *v)?)), + PA::Parameterized(n, sp!(_, pattrs_)) => { + let attrs = pattrs_ + .into_iter() + .map(|a| attribute(context, attr_position, a)) + .collect::>>()?; + EA::Parameterized(n, unique_attributes(context, attr_position, true, attrs)) + }, }, - })) + )) } fn check_module_name(context: &mut Context, ident_loc: &Loc, mident: &ModuleIdent) { @@ -849,45 +852,48 @@ fn attribute_value( ) -> Option { use E::AttributeValue_ as EV; use P::{AttributeValue_ as PV, LeadingNameAccess_ as LN, NameAccessChain_ as PN}; - Some(sp(loc, match avalue_ { - PV::Value(v) => EV::Value(value(context, v)?), - PV::ModuleAccess(sp!(ident_loc, PN::Two(sp!(aloc, LN::AnonymousAddress(a)), n))) => { - let addr = Address::Numerical(None, sp(aloc, a)); - let mident = sp(ident_loc, ModuleIdent_::new(addr, ModuleName(n))); - check_module_name(context, &ident_loc, &mident); - EV::Module(mident) - }, - // bit wonky, but this is the only spot currently where modules and expressions exist - // in the same namespace. - // TODO consider if we want to just force all of these checks into the well-known - // attribute setup - PV::ModuleAccess(sp!(ident_loc, PN::One(n))) - if context.aliases.module_alias_get(&n).is_some() => - { - let sp!(_, mident_) = context.aliases.module_alias_get(&n).unwrap(); - let mident = sp(ident_loc, mident_); - check_module_name(context, &ident_loc, &mident); - EV::Module(mident) - }, - PV::ModuleAccess(sp!(ident_loc, PN::Two(sp!(aloc, LN::Name(n1)), n2))) - if context - .named_address_mapping - .as_ref() - .map(|m| m.contains_key(&n1.value)) - .unwrap_or(false) => - { - let addr = address(context, false, sp(aloc, LN::Name(n1))); - let mident = sp(ident_loc, ModuleIdent_::new(addr, ModuleName(n2))); - check_module_name(context, &ident_loc, &mident); - EV::Module(mident) + Some(sp( + loc, + match avalue_ { + PV::Value(v) => EV::Value(value(context, v)?), + PV::ModuleAccess(sp!(ident_loc, PN::Two(sp!(aloc, LN::AnonymousAddress(a)), n))) => { + let addr = Address::Numerical(None, sp(aloc, a)); + let mident = sp(ident_loc, ModuleIdent_::new(addr, ModuleName(n))); + check_module_name(context, &ident_loc, &mident); + EV::Module(mident) + }, + // bit wonky, but this is the only spot currently where modules and expressions exist + // in the same namespace. + // TODO consider if we want to just force all of these checks into the well-known + // attribute setup + PV::ModuleAccess(sp!(ident_loc, PN::One(n))) + if context.aliases.module_alias_get(&n).is_some() => + { + let sp!(_, mident_) = context.aliases.module_alias_get(&n).unwrap(); + let mident = sp(ident_loc, mident_); + check_module_name(context, &ident_loc, &mident); + EV::Module(mident) + }, + PV::ModuleAccess(sp!(ident_loc, PN::Two(sp!(aloc, LN::Name(n1)), n2))) + if context + .named_address_mapping + .as_ref() + .map(|m| m.contains_key(&n1.value)) + .unwrap_or(false) => + { + let addr = address(context, false, sp(aloc, LN::Name(n1))); + let mident = sp(ident_loc, ModuleIdent_::new(addr, ModuleName(n2))); + check_module_name(context, &ident_loc, &mident); + EV::Module(mident) + }, + PV::ModuleAccess(ma) => EV::ModuleAccess(name_access_chain( + context, + Access::Type, + ma, + Some(DeprecatedItem::Module), + )?), }, - PV::ModuleAccess(ma) => EV::ModuleAccess(name_access_chain( - context, - Access::Type, - ma, - Some(DeprecatedItem::Module), - )?), - })) + )) } //************************************************************************************************** @@ -965,10 +971,13 @@ fn record_module_member_info( attributes: &[P::Attributes], member_kind: ModuleMemberKind, ) { - cur_members.insert(*name, ModuleMemberInfo { - kind: member_kind, - deprecation: deprecated_attribute_location(attributes), - }); + cur_members.insert( + *name, + ModuleMemberInfo { + kind: member_kind, + deprecation: deprecated_attribute_location(attributes), + }, + ); } /// Record ModuleMemberInfo about a specified member name, skipping @@ -978,10 +987,13 @@ fn record_module_member_info_without_deprecation( name: &Spanned, member_kind: ModuleMemberKind, ) { - cur_members.insert(*name, ModuleMemberInfo { - kind: member_kind, - deprecation: None, - }); + cur_members.insert( + *name, + ModuleMemberInfo { + kind: member_kind, + deprecation: None, + }, + ); } /// Specified module with identifier mident and definition m, @@ -1027,11 +1039,14 @@ fn module_members( ); }, P::ModuleMember::Spec( - sp!(_, SB { - target, - members, - .. - }), + sp!( + _, + SB { + target, + members, + .. + } + ), ) => match &target.value { SBT::Schema(n, _) => { record_module_member_info_without_deprecation( @@ -1109,11 +1124,14 @@ fn aliases_from_member( Some(P::ModuleMember::Struct(s)) }, P::ModuleMember::Spec(s) => { - let sp!(_, SB { - target, - members, - .. - }) = &s; + let sp!( + _, + SB { + target, + members, + .. + } + ) = &s; match &target.value { SBT::Schema(n, _) => { check_name_and_add_implicit_alias!(ModuleMemberKind::Schema, *n); @@ -1751,15 +1769,18 @@ fn access_specifier(context: &mut Context, specifier: P::AccessSpecifier) -> E:: access_specifier_name_access_chain(context, chain); let type_args = optional_types(context, type_args); let address = address_specifier(context, address); - sp(specifier.loc, E::AccessSpecifier_ { - kind, - negated, - module_address, - module_name, - resource_name, - type_args, - address, - }) + sp( + specifier.loc, + E::AccessSpecifier_ { + kind, + negated, + module_address, + module_name, + resource_name, + type_args, + address, + }, + ) } fn access_specifier_name_access_chain( @@ -1968,11 +1989,14 @@ fn spec(context: &mut Context, sp!(loc, pspec): P::SpecBlock) -> E::SpecBlock { context.set_to_outer_scope(old_aliases); context.in_spec_context = false; - sp(loc, E::SpecBlock_ { - attributes, - target: spec_target(context, target), - members, - }) + sp( + loc, + E::SpecBlock_ { + attributes, + target: spec_target(context, target), + members, + }, + ) } fn spec_target(context: &mut Context, sp!(loc, pt): P::SpecBlockTarget) -> E::SpecBlockTarget { @@ -2243,10 +2267,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 +2586,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, @@ -2614,11 +2644,12 @@ fn exp_(context: &mut Context, sp!(loc, pe_): P::Exp) -> E::Exp { PE::While(pb, ploop) => EE::While(exp(context, *pb), exp(context, *ploop)), PE::Loop(ploop) => EE::Loop(exp(context, *ploop)), PE::Block(seq) => EE::Block(sequence(context, loc, seq)), - PE::Lambda(pbs, pe) => { + PE::Lambda(pbs, pe, 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), abilities), None => { assert!(context.env.has_errors()); EE::UnresolvedError @@ -3317,6 +3348,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) => { @@ -3341,7 +3376,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, _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 640e235b3605d..1316d67a2871c 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, _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 34e4dba75570d..db696dc51a064 100644 --- a/third_party/move/move-compiler/src/parser/ast.rs +++ b/third_party/move/move-compiler/src/parser/ast.rs @@ -488,7 +488,7 @@ pub enum Type_ { // &mut t Ref(bool, Box), // (t1,...,tn):t - Fun(Vec, Box), + Fun(Vec, Box, Vec), // () Unit, // (t1, t2, ... , tn) @@ -665,6 +665,9 @@ pub enum Exp_ { Spanned>, ), + // e(earg,*) + ExpCall(Box, Spanned>), + // tn {f1: e1, ... , f_n: e_n } Pack(NameAccessChain, Option>, Vec<(Field, Exp)>), @@ -688,7 +691,7 @@ pub enum Exp_ { // { seq } Block(Sequence), // | x1 [: t1], ..., xn [: tn] | e - Lambda(TypedBindList, Box), + Lambda(TypedBindList, Box, Vec), // forall/exists x1 : e1, ..., xn [{ t1, .., tk } *] [where cond]: en. Quant( QuantKind, @@ -1053,24 +1056,32 @@ impl fmt::Display for BinOp_ { impl fmt::Display for Visibility { fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", match &self { - Visibility::Public(_) => Visibility::PUBLIC, - Visibility::Script(_) => Visibility::SCRIPT, - Visibility::Friend(_) => Visibility::FRIEND, - Visibility::Package(_) => Visibility::PACKAGE, - Visibility::Internal => Visibility::INTERNAL, - }) + write!( + f, + "{}", + match &self { + Visibility::Public(_) => Visibility::PUBLIC, + Visibility::Script(_) => Visibility::SCRIPT, + Visibility::Friend(_) => Visibility::FRIEND, + Visibility::Package(_) => Visibility::PACKAGE, + Visibility::Internal => Visibility::INTERNAL, + } + ) } } impl fmt::Display for Ability_ { fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", match &self { - Ability_::Copy => Ability_::COPY, - Ability_::Drop => Ability_::DROP, - Ability_::Store => Ability_::STORE, - Ability_::Key => Ability_::KEY, - }) + write!( + f, + "{}", + match &self { + Ability_::Copy => Ability_::COPY, + Ability_::Drop => Ability_::DROP, + Ability_::Store => Ability_::STORE, + Ability_::Key => Ability_::KEY, + } + ) } } @@ -1732,11 +1743,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); }, } } @@ -1833,6 +1845,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 { @@ -1893,11 +1911,18 @@ 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, abilities) => { w.write("|"); tbs.ast_debug(w); w.write("|"); e.ast_debug(w); + if !abilities.is_empty() { + w.write(" has "); + 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 07f6cf531246a..3e5f971168409 100644 --- a/third_party/move/move-compiler/src/parser/syntax.rs +++ b/third_party/move/move-compiler/src/parser/syntax.rs @@ -1515,10 +1515,10 @@ fn parse_for_loop(context: &mut Context) -> Result<(Exp, bool), Box> // To create the declaration "let flag = false", first create the variable flag, and then assign it to false let flag_symb = Symbol::from(FOR_LOOP_UPDATE_ITER_FLAG); - let flag = sp(for_loc, vec![sp( + let flag = sp( for_loc, - Bind_::Var(Var(sp(for_loc, flag_symb))), - )]); + vec![sp(for_loc, Bind_::Var(Var(sp(for_loc, flag_symb))))], + ); let false_exp = sp(for_loc, Exp_::Value(sp(for_loc, Value_::Bool(false)))); let decl_flag = sp( for_loc, @@ -1528,10 +1528,10 @@ fn parse_for_loop(context: &mut Context) -> Result<(Exp, bool), Box> // To create the declaration "let ub_value = upper_bound", first create the variable flag, and // then assign it to upper_bound let ub_value_symbol = Symbol::from(FOR_LOOP_UPPER_BOUND_VALUE); - let ub_value_bindlist = sp(for_loc, vec![sp( + let ub_value_bindlist = sp( for_loc, - Bind_::Var(Var(sp(for_loc, ub_value_symbol))), - )]); + vec![sp(for_loc, Bind_::Var(Var(sp(for_loc, ub_value_symbol))))], + ); let ub_value_assignment = sp( for_loc, SequenceItem_::Bind(ub_value_bindlist, None, Box::new(ub)), @@ -1886,7 +1886,8 @@ fn parse_exp(context: &mut Context) -> Result> { spanned(context.tokens.file_hash(), start_loc, start_loc + 1, vec![]) }; let body = Box::new(parse_exp(context)?); - Exp_::Lambda(bindings, body) + let abilities = parse_abilities(context)?; + Exp_::Lambda(bindings, body, abilities) }, Tok::Identifier if is_quant(context) => parse_quant(context)?, _ => { @@ -2133,6 +2134,7 @@ fn parse_unary_exp(context: &mut Context) -> Result> { // DotOrIndexChain = // "." [ ["::" "<" Comma ">"]? ]? // | "[" "]" +// | "(" Comma ")" // --> ExpCall // | fn parse_dot_or_index_chain(context: &mut Context) -> Result> { let start_loc = context.tokens.start_loc(); @@ -2173,6 +2175,10 @@ fn parse_dot_or_index_chain(context: &mut Context) -> Result { + let args = parse_call_args(context)?; + Exp_::ExpCall(Box::new(lhs), args) + }, _ => break, }; let end_loc = context.tokens.previous_end_loc(); @@ -2407,11 +2413,12 @@ fn parse_type(context: &mut Context) -> Result> { Type_::Unit, ) }; + let abilities = parse_type_constraints(context)?; 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), )); }, _ => { @@ -2486,15 +2493,11 @@ fn parse_ability(context: &mut Context) -> Result> { } } -// Parse a type parameter: -// TypeParameter = -// ? +// Parse an optional type constraint: // Constraint = -// ":" (+ )* -fn parse_type_parameter(context: &mut Context) -> Result<(Name, Vec), Box> { - let n = parse_identifier(context)?; - - let ability_constraints = if match_token(context.tokens, Tok::Colon)? { +// ( ":" (+ )* )? +fn parse_type_constraints(context: &mut Context) -> Result, Box> { + if match_token(context.tokens, Tok::Colon)? { parse_list( context, |context| match context.tokens.peek() { @@ -2502,22 +2505,24 @@ fn parse_type_parameter(context: &mut Context) -> Result<(Name, Vec), B 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 - ), - )), + _ => Ok(false), }, parse_ability, - )? + ) } else { - vec![] - }; + Ok(vec![]) + } +} + +// Parse a type parameter: +// TypeParameter = +// ? +// Constraint = +// ":" (+ )* +fn parse_type_parameter(context: &mut Context) -> Result<(Name, Vec), Box> { + let n = parse_identifier(context)?; + + let ability_constraints = parse_type_constraints(context)?; Ok((n, ability_constraints)) } 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
{' block or declare it with an address 'module
::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
{' block or declare it with an address 'module
::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
{' block or declare it with an address 'module
::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
{' block or declare it with an address 'module
::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() {} - │ ^ - │ │ - │ Unexpected '&' - │ Expected one of: '+', '>', or ',' + │ - ^ Expected '>' + │ │ + │ To match this '<' diff --git a/third_party/move/move-model/src/ast.rs b/third_party/move/move-model/src/ast.rs index 440abdd3ad23f..99c0cf4ef9268 100644 --- a/third_party/move/move-model/src/ast.rs +++ b/third_party/move/move-model/src/ast.rs @@ -18,7 +18,7 @@ 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; @@ -598,7 +598,7 @@ pub enum ExpData { /// Represents an invocation of a function value, as a lambda. Invoke(NodeId, Exp, Vec), /// Represents a lambda. - Lambda(NodeId, Pattern, Exp), + Lambda(NodeId, Pattern, Exp, AbilitySet), /// Represents a quantified formula over multiple variables and ranges. Quant( NodeId, @@ -889,12 +889,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); }, @@ -1352,7 +1352,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)?; @@ -3098,7 +3098,7 @@ impl<'a> fmt::Display for ExpDisplay<'a> { self.fmt_exps(args) ) }, - Lambda(id, pat, body) => { + Lambda(id, pat, body, abilities) => { if self.verbose { write!( f, @@ -3106,14 +3106,24 @@ impl<'a> fmt::Display for ExpDisplay<'a> { id.as_usize(), pat.display_for_exp(self), body.display_cont(self) - ) + )?; } else { write!( f, "|{}| {}", 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, " has {}", abilities_as_str) + } else { + Ok(()) } }, Block(id, pat, binding, body) => { 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 3082a062ebe9d..bb306fc6f5548 100644 --- a/third_party/move/move-model/src/builder/exp_builder.rs +++ b/third_party/move/move-model/src/builder/exp_builder.rs @@ -873,6 +873,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) => { @@ -1043,9 +1044,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)), + self.parent.translate_abilities(abilities), ), Unit => Type::Tuple(vec![]), Multiple(vst) => Type::Tuple(self.translate_types(vst.as_ref())), @@ -1171,10 +1173,13 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo if is_wildcard(resource) { ResourceSpecifier::DeclaredInModule(module_id) } else { - let mident = sp(specifier.loc, EA::ModuleIdent_ { - address: *address, - module: *module, - }); + let mident = sp( + specifier.loc, + EA::ModuleIdent_ { + address: *address, + module: *module, + }, + ); let maccess = sp( specifier.loc, EA::ModuleAccess_::ModuleAccess(mident, *resource, None), @@ -1493,6 +1498,20 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo ) } }, + EA::Exp_::ExpCall(efexp, args) => { + let (ftype, fexp) = self.translate_exp_free(efexp); + // Need to make a &[&Exp] out of args. + let args = args.value.iter().collect_vec(); + let (arg_types, args) = self.translate_exp_list(&args); + let fun_t = Type::Fun( + Box::new(Type::tuple(arg_types)), + Box::new(expected_type.clone()), + AbilitySet::FUNCTIONS, + ); + let fun_t = self.check_type(&loc, &ftype, &fun_t, context); + let id = self.new_node_id_with_type_loc(&fun_t, &loc); + return ExpData::Invoke(id, fexp.into(), args); + }, EA::Exp_::Pack(maccess, generics, fields) => self .translate_pack( &loc, @@ -1584,9 +1603,14 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo ExpData::LoopCont(id, 0, 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, abilities) => self.translate_lambda( + &loc, + bindings, + exp, + expected_type, + context, + self.parent.translate_abilities(abilities), + ), EA::Exp_::Quant(kind, ranges, triggers, condition, body) => self.translate_quant( &loc, *kind, @@ -1860,11 +1884,13 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo let id = self.new_node_id_with_type_loc(&rt, &loc); if self.mode == ExpTranslationMode::Impl { // Remember information about this spec block for deferred checking. - self.placeholder_map - .insert(id, ExpPlaceholder::SpecBlockInfo { + self.placeholder_map.insert( + id, + ExpPlaceholder::SpecBlockInfo { spec_id: *spec_id, locals: self.get_locals(), - }); + }, + ); } ExpData::Call(id, Operation::NoOp, vec![]) }, @@ -3108,6 +3134,7 @@ 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()), + AbilitySet::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)); @@ -3457,9 +3484,11 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo ); let global_id = self.new_node_id_with_type_loc(&ghost_mem_ty, loc); self.set_node_instantiation(global_id, vec![ghost_mem_ty]); - let global_access = ExpData::Call(global_id, Operation::Global(None), vec![ - zero_addr.into_exp() - ]); + let global_access = ExpData::Call( + global_id, + Operation::Global(None), + vec![zero_addr.into_exp()], + ); let select_id = self.new_node_id_with_type_loc(&ty, loc); self.set_node_instantiation(select_id, instantiation); return ExpData::Call( @@ -3668,10 +3697,11 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo ), ); self.set_node_instantiation(node_id, vec![inner_ty.clone()]); - let call = ExpData::Call(node_id, Operation::MoveFunction(mid, fid), vec![ - vec_exp_e.into_exp(), - idx_exp_e.clone().into_exp(), - ]); + let call = ExpData::Call( + node_id, + Operation::MoveFunction(mid, fid), + vec![vec_exp_e.into_exp(), idx_exp_e.clone().into_exp()], + ); return call; } ExpData::Invalid(self.env().new_node_id()) @@ -3845,11 +3875,13 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo self.create_select_oper(&loc, &mid.qualified_inst(sid, inst), field_name) } else { // Create a placeholder for later resolution. - self.placeholder_map - .insert(id, ExpPlaceholder::FieldSelectInfo { + self.placeholder_map.insert( + id, + ExpPlaceholder::FieldSelectInfo { struct_ty: ty, field_name, - }); + }, + ); Operation::NoOp }; ExpData::Call(id, oper, vec![exp.into_exp()]) @@ -4464,13 +4496,15 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo None, ); let id = self.new_node_id_with_type_loc(expected_type, loc); - self.placeholder_map - .insert(id, ExpPlaceholder::ReceiverCallInfo { + self.placeholder_map.insert( + id, + ExpPlaceholder::ReceiverCallInfo { name, generics: generics.map(|g| g.1.clone()), arg_types, result_type: expected_type.clone(), - }); + }, + ); ExpData::Call(id, Operation::NoOp, args) } @@ -4892,13 +4926,11 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo ) -> Option { let struct_entry = self.parent.parent.lookup_struct_entry(struct_id); match (&struct_entry.layout, variant) { - (StructLayout::Singleton(fields, _), None) => Some( - if struct_entry.is_empty_struct { - 0 - } else { - fields.len() - }, - ), + (StructLayout::Singleton(fields, _), None) => Some(if struct_entry.is_empty_struct { + 0 + } else { + fields.len() + }), (StructLayout::Variants(variants), Some(name)) => variants .iter() .find(|v| v.name == name) @@ -5025,6 +5057,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo body: &EA::Exp, expected_type: &Type, context: &ErrorMessageContext, + abilities: AbilitySet, ) -> ExpData { // Translate the argument list let arg_type = self.fresh_type_var(); @@ -5045,14 +5078,14 @@ 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), Box::new(ty.clone()), abilities.clone()), 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(), abilities) } fn translate_quant( @@ -5269,8 +5302,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/exp_rewriter.rs b/third_party/move/move-model/src/exp_rewriter.rs index d55b7842c3e1f..caa719645c26e 100644 --- a/third_party/move/move-model/src/exp_rewriter.rs +++ b/third_party/move/move-model/src/exp_rewriter.rs @@ -13,6 +13,7 @@ use crate::{ }; 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 @@ -194,7 +195,13 @@ pub trait ExpRewriterFunctions { fn rewrite_invoke(&mut self, id: NodeId, target: &Exp, args: &[Exp]) -> Option { None } - fn rewrite_lambda(&mut self, id: NodeId, pat: &Pattern, body: &Exp) -> Option { + fn rewrite_lambda( + &mut self, + id: NodeId, + pat: &Pattern, + body: &Exp, + abilities: AbilitySet, + ) -> Option { None } // Optionally can rewrite pat and return new value, otherwise is unchanged. @@ -351,16 +358,17 @@ pub trait ExpRewriterFunctions { exp } }, - Lambda(id, pat, body) => { + Lambda(id, pat, body, 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, *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, *abilities).into_exp() } else { exp } @@ -479,12 +487,15 @@ pub trait ExpRewriterFunctions { { (true, new_exp) } else { - (false, MatchArm { - loc: arm.loc.clone(), - pattern: newer_pat, - condition: new_cond, - body: new_body, - }) + ( + false, + MatchArm { + loc: arm.loc.clone(), + pattern: newer_pat, + condition: new_cond, + body: new_body, + }, + ) }; new_arms.push(new_arm); arms_changed = @@ -623,18 +634,24 @@ pub trait ExpRewriterFunctions { let new_exp = self.rewrite_exp(condition.exp.clone()); let maybe_new_additional_exps = self.internal_rewrite_vec(&condition.additional_exps); if let Some(new_additional_exps) = maybe_new_additional_exps { - (true, Condition { - exp: new_exp, - additional_exps: new_additional_exps, - ..condition - }) + ( + true, + Condition { + exp: new_exp, + additional_exps: new_additional_exps, + ..condition + }, + ) } else { let changed = !ExpData::ptr_eq(&condition.exp, &new_exp); if changed { - (true, Condition { - exp: new_exp, - ..condition - }) + ( + true, + Condition { + exp: new_exp, + ..condition + }, + ) } else { (false, condition) } diff --git a/third_party/move/move-model/src/ty.rs b/third_party/move/move-model/src/ty.rs index 07ee9d11abba8..70b78c77c2b12 100644 --- a/third_party/move/move-model/src/ty.rs +++ b/third_party/move/move-model/src/ty.rs @@ -39,7 +39,11 @@ pub enum Type { Vector(Box), Struct(ModuleId, StructId, /*type-params*/ Vec), TypeParameter(u16), - Fun(/*args*/ Box, /*result*/ Box), + Fun( + /*args*/ Box, + /*result*/ Box, + AbilitySet, + ), // Types only appearing in programs. Reference(ReferenceKind, Box), @@ -809,7 +813,7 @@ impl Type { ts.iter().any(|t| t.depends_from_type_parameter()) }, Vector(t) | Reference(_, t) | TypeDomain(t) => t.depends_from_type_parameter(), - Fun(t, r) => t.depends_from_type_parameter() || r.depends_from_type_parameter(), + Fun(t, r, _) => t.depends_from_type_parameter() || r.depends_from_type_parameter(), _ => false, } } @@ -928,7 +932,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()), @@ -1155,9 +1159,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))), @@ -1183,7 +1188,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, @@ -1197,7 +1202,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(), @@ -1218,7 +1223,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); }, @@ -1322,7 +1327,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); }, @@ -1345,7 +1350,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); }, @@ -1929,7 +1934,7 @@ impl Substitution { let tparam = context.type_param(*idx); check(tparam.1.abilities) }, - Fun(_, _) => check(AbilitySet::FUNCTIONS), + Fun(_, _, abilities) => check(AbilitySet::FUNCTIONS.union(*abilities)), Reference(_, _) => check(AbilitySet::REFERENCES), TypeDomain(_) | ResourceDomain(_, _, _) => check(AbilitySet::EMPTY), Error => Ok(()), @@ -2172,7 +2177,7 @@ 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 @@ -2188,6 +2193,7 @@ impl Substitution { self.unify(context, variance, order, r1, r2) .map_err(TypeUnificationError::lift(order, t1, t2))?, ), + abilities1.intersect(*abilities2), )); }, (Type::Struct(m1, s1, ts1), Type::Struct(m2, s2, ts2)) => { @@ -3406,12 +3412,21 @@ 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 + .iter() + .map(|a| a.to_string()) + .reduce(|l, r| format!("{}+{}", l, r)) + .unwrap_or_default(); + write!(f, ":{}", abilities_as_str) } else { Ok(()) } @@ -3583,7 +3598,8 @@ 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) }, } 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 661c782d8aac8..5f61f08c8ab01 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 @@ -1602,9 +1602,11 @@ impl<'env> FunctionTranslator<'env> { fun_name = boogie_function_bv_name(&callee_env, inst, &[bv_flag]); } else if module_env.is_table() { - fun_name = boogie_function_bv_name(&callee_env, inst, &[ - false, bv_flag, - ]); + fun_name = boogie_function_bv_name( + &callee_env, + inst, + &[false, bv_flag], + ); } emitln!(writer, "call {}({});", fun_name, args_str); } else { @@ -1613,9 +1615,11 @@ impl<'env> FunctionTranslator<'env> { // Handle the case where the return value of length is assigned to a bv int because // length always returns a non-bv result if module_env.is_std_vector() { - fun_name = boogie_function_bv_name(&callee_env, inst, &[ - bv_flag || dest_bv_flag, - ]); + fun_name = boogie_function_bv_name( + &callee_env, + inst, + &[bv_flag || dest_bv_flag], + ); // Handle the case where the return value of length is assigned to a bv int because // length always returns a non-bv result if callee_name.contains("length") && dest_bv_flag { @@ -1645,10 +1649,11 @@ impl<'env> FunctionTranslator<'env> { args_str = args_str_vec.iter().cloned().join(", "); } } else if module_env.is_table() { - fun_name = boogie_function_bv_name(&callee_env, inst, &[ - false, - bv_flag || dest_bv_flag, - ]); + fun_name = boogie_function_bv_name( + &callee_env, + inst, + &[false, bv_flag || dest_bv_flag], + ); if dest_bv_flag && callee_name.contains("length") { // Handle the case where the return value of length is assigned to a bv int because // length always returns a non-bv result @@ -2066,7 +2071,7 @@ impl<'env> FunctionTranslator<'env> { | Type::Struct(_, _, _) | Type::TypeParameter(_) | Type::Reference(_, _) - | Type::Fun(_, _) + | Type::Fun(..) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error @@ -2103,7 +2108,7 @@ impl<'env> FunctionTranslator<'env> { | Type::Struct(_, _, _) | Type::TypeParameter(_) | Type::Reference(_, _) - | Type::Fun(_, _) + | Type::Fun(..) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error @@ -2160,7 +2165,7 @@ impl<'env> FunctionTranslator<'env> { | Type::Struct(_, _, _) | Type::TypeParameter(_) | Type::Reference(_, _) - | Type::Fun(_, _) + | Type::Fun(..) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error @@ -2197,7 +2202,7 @@ impl<'env> FunctionTranslator<'env> { | Type::Struct(_, _, _) | Type::TypeParameter(_) | Type::Reference(_, _) - | Type::Fun(_, _) + | Type::Fun(..) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error @@ -2237,7 +2242,7 @@ impl<'env> FunctionTranslator<'env> { | Type::Struct(_, _, _) | Type::TypeParameter(_) | Type::Reference(_, _) - | Type::Fun(_, _) + | Type::Fun(..) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error @@ -2278,7 +2283,7 @@ impl<'env> FunctionTranslator<'env> { | Type::Struct(_, _, _) | Type::TypeParameter(_) | Type::Reference(_, _) - | Type::Fun(_, _) + | Type::Fun(..) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error @@ -2309,7 +2314,7 @@ impl<'env> FunctionTranslator<'env> { | Type::Struct(_, _, _) | Type::TypeParameter(_) | Type::Reference(_, _) - | Type::Fun(_, _) + | Type::Fun(..) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error @@ -2349,7 +2354,7 @@ impl<'env> FunctionTranslator<'env> { | Type::Struct(_, _, _) | Type::TypeParameter(_) | Type::Reference(_, _) - | Type::Fun(_, _) + | Type::Fun(..) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error @@ -2443,7 +2448,7 @@ impl<'env> FunctionTranslator<'env> { | Type::Struct(_, _, _) | Type::TypeParameter(_) | Type::Reference(_, _) - | Type::Fun(_, _) + | Type::Fun(..) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error @@ -3012,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 53235c65f1116..ce0b6dad583a3 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 @@ -1443,7 +1443,7 @@ impl<'env> SpecTranslator<'env> { | Type::Tuple(_) | Type::TypeParameter(_) | Type::Reference(_, _) - | Type::Fun(_, _) + | Type::Fun(..) | Type::TypeDomain(_) | Type::ResourceDomain(_, _, _) | Type::Error @@ -1606,7 +1606,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