diff --git a/third_party/move/evm/move-to-yul/tests/dispatcher_testsuite.rs b/third_party/move/evm/move-to-yul/tests/dispatcher_testsuite.rs index 903de4abd8cd9..7d24920cc87f1 100644 --- a/third_party/move/evm/move-to-yul/tests/dispatcher_testsuite.rs +++ b/third_party/move/evm/move-to-yul/tests/dispatcher_testsuite.rs @@ -3,6 +3,10 @@ // SPDX-License-Identifier: Apache-2.0 use anyhow::Result; +use codespan_reporting::{ + diagnostic::Severity, + term::termcolor::{ColorChoice, StandardStream}, +}; use evm::{backend::MemoryVicinity, ExitReason}; use evm_exec_utils::{compile, exec::Executor}; use move_compiler::{ @@ -83,6 +87,11 @@ fn compile_yul_to_bytecode_bytes(filename: &str) -> Result> { flags, &known_attributes, )?; + if env.has_errors() { + let mut error_writer = StandardStream::stderr(ColorChoice::Auto); + env.report_diag(&mut error_writer, Severity::Warning); + panic!("compilation failed"); + } let options = Options::default(); let (_, out, _) = Generator::run(&options, &env) .pop() diff --git a/third_party/move/move-compiler-v2/src/ast_simplifier.rs b/third_party/move/move-compiler-v2/src/ast_simplifier.rs index 968856cfede05..f60012a917544 100644 --- a/third_party/move/move-compiler-v2/src/ast_simplifier.rs +++ b/third_party/move/move-compiler-v2/src/ast_simplifier.rs @@ -407,6 +407,28 @@ fn find_possibly_modified_vars( _ => {}, }; }, + Match(node_id, _, arms) => { + match pos { + VisitorPosition::Pre => { + modifying_stack.push(modifying); + modifying = false; + } + VisitorPosition::BeforeMatchBody(idx) => { + let arm = &arms[idx]; + visiting_binding.enter_scope(); + for (_, sym) in arm.pattern.vars() { + visiting_binding.insert(sym, *node_id); + } + } + VisitorPosition::AfterMatchBody(_) => { + visiting_binding.exit_scope(); + } + VisitorPosition::Post => { + modifying = modifying_stack.pop().expect("unbalanced visit 8"); + } + _ => {} + } + } IfElse(..) | Sequence(..) => { match pos { VisitorPosition::Pre => { @@ -887,7 +909,7 @@ impl<'env> ExpRewriterFunctions for SimplifierRewriter<'env> { trace!( "Starting rewrite_block(id={}, pat={}, opt_binding={}, body={}, pat_type={}, exp_type={}, {})", id.as_usize(), - pat.to_string(self.env(), &type_display_context), + pat.to_string(self.func_env), exp.display_verbose(self.env()), body.display_verbose(self.env()), pat_type.display(&type_display_context), @@ -898,7 +920,7 @@ impl<'env> ExpRewriterFunctions for SimplifierRewriter<'env> { trace!( "Starting rewrite_block(id={}, pat={}, opt_binding={}, body={})", id.as_usize(), - pat.to_string(self.env(), &TypeDisplayContext::new(self.env())), + pat.to_string(self.func_env), "None", body.display_verbose(self.env()) ); 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 0b83dfe74af54..baaa2795fb59a 100644 --- a/third_party/move/move-compiler-v2/src/bytecode_generator.rs +++ b/third_party/move/move-compiler-v2/src/bytecode_generator.rs @@ -327,6 +327,7 @@ impl<'env> Generator<'env> { fn gen(&mut self, targets: Vec, exp: &Exp) { match exp.as_ref() { ExpData::Invalid(id) => self.internal_error(*id, "invalid expression"), + ExpData::Match(id, ..) => self.internal_error(*id, "match not yet implemented"), ExpData::Temporary(id, temp) => self.gen_temporary(targets, *id, *temp), ExpData::Value(id, val) => self.gen_value(targets, *id, val), ExpData::LocalVar(id, name) => self.gen_local(targets, *id, *name), @@ -596,7 +597,10 @@ impl<'env> Generator<'env> { } } }, - Operation::Pack(mid, sid) => { + Operation::Pack(_, _, Some(_)) => { + self.internal_error(id, "variants not yet implemented") + }, + Operation::Pack(mid, sid, None) => { let inst = self.env().get_node_instantiation(id); self.gen_op_call(targets, id, BytecodeOperation::Pack(*mid, *sid, inst), args) }, @@ -1281,7 +1285,10 @@ impl<'env> Generator<'env> { Bytecode::Assign(attr, local, arg, AssignKind::Inferred) }) }, - Pattern::Struct(id, str, args) => { + Pattern::Struct(id, _, Some(_), _) => { + self.internal_error(*id, "variants not yet implemented") + }, + Pattern::Struct(id, str, None, args) => { let (temps, cont_assigns) = self.flatten_patterns(args, next_scope); let ty = self.temp_type(arg); if ty.is_reference() { diff --git a/third_party/move/move-compiler-v2/src/flow_insensitive_checkers.rs b/third_party/move/move-compiler-v2/src/flow_insensitive_checkers.rs index cdb77eb0379ef..dd6dabec91723 100644 --- a/third_party/move/move-compiler-v2/src/flow_insensitive_checkers.rs +++ b/third_party/move/move-compiler-v2/src/flow_insensitive_checkers.rs @@ -132,9 +132,21 @@ impl<'env, 'params> SymbolVisitor<'env, 'params> { } self.seen_uses.exit_scope(); }, - Pre | MidMutate | BeforeThen | BeforeElse | PreSequenceValue => {}, + Pre | MidMutate | BeforeThen | BeforeElse | PreSequenceValue + | BeforeMatchBody(_) | AfterMatchBody(_) => {}, }; }, + Match(_, _, arms) => match position { + BeforeMatchBody(_) => self.seen_uses.enter_scope(), + AfterMatchBody(idx) => { + for (id, var) in arms[idx].pattern.vars() { + self.node_symbol_decl_visitor(true, &id, &var, UsageKind::LocalVar) + } + self.seen_uses.exit_scope(); + }, + Pre | Post | BeforeBody | MidMutate | BeforeThen | BeforeElse + | PreSequenceValue => {}, + }, Lambda(_, pat, _) => { match position { Pre => self.seen_uses.enter_scope(), @@ -144,7 +156,8 @@ impl<'env, 'params> SymbolVisitor<'env, 'params> { } self.seen_uses.exit_scope(); }, - BeforeBody | MidMutate | BeforeThen | BeforeElse | PreSequenceValue => {}, + BeforeBody | MidMutate | BeforeThen | BeforeElse | PreSequenceValue + | BeforeMatchBody(_) | AfterMatchBody(_) => {}, }; }, Quant(_, _, ranges, ..) => { @@ -161,7 +174,8 @@ impl<'env, 'params> SymbolVisitor<'env, 'params> { } self.seen_uses.exit_scope(); }, - BeforeBody | MidMutate | BeforeThen | BeforeElse | PreSequenceValue => {}, + BeforeBody | MidMutate | BeforeThen | BeforeElse | PreSequenceValue + | BeforeMatchBody(_) | AfterMatchBody(_) => {}, }; }, Assign(_, pat, _) => { diff --git a/third_party/move/move-compiler-v2/src/function_checker.rs b/third_party/move/move-compiler-v2/src/function_checker.rs index 3248c07fade94..cb3550eb5b4ac 100644 --- a/third_party/move/move-compiler-v2/src/function_checker.rs +++ b/third_party/move/move-compiler-v2/src/function_checker.rs @@ -127,7 +127,7 @@ fn check_privileged_operations_on_structs(env: &GlobalEnv, fun_env: &FunctionEnv &struct_env.module_env, ); }, - Operation::Pack(mid, sid) => { + Operation::Pack(mid, sid, _) => { if *mid != caller_module_id { let qualified_struct_id = mid.qualified(*sid); let struct_env = env.get_struct(qualified_struct_id); @@ -147,7 +147,7 @@ fn check_privileged_operations_on_structs(env: &GlobalEnv, fun_env: &FunctionEnv | ExpData::Block(_, pat, _, _) | ExpData::Lambda(_, pat, _) => { pat.visit_pre_post(&mut |_, pat| { - if let Pattern::Struct(id, str, _) = pat { + if let Pattern::Struct(id, str, _, _) = pat { let module_id = str.module_id; if module_id != caller_module_id { let struct_env = env.get_struct(str.to_qualified_id()); diff --git a/third_party/move/move-compiler-v2/src/inliner.rs b/third_party/move/move-compiler-v2/src/inliner.rs index eebb256cae61e..6047eae1a82ab 100644 --- a/third_party/move/move-compiler-v2/src/inliner.rs +++ b/third_party/move/move-compiler-v2/src/inliner.rs @@ -1191,9 +1191,14 @@ impl<'env, 'rewriter> ExpRewriterFunctions for InlinedRewriter<'env, 'rewriter> .map(|new_sym| Pattern::Var(new_id, new_sym)) .or_else(|| new_id_opt.map(|id| Pattern::Var(id, *sym))), Pattern::Tuple(_, pattern_vec) => Some(Pattern::Tuple(new_id, pattern_vec.clone())), - Pattern::Struct(_, struct_id, pattern_vec) => { + Pattern::Struct(_, struct_id, variant, pattern_vec) => { let new_struct_id = struct_id.clone().instantiate(self.type_args); - Some(Pattern::Struct(new_id, new_struct_id, pattern_vec.clone())) + Some(Pattern::Struct( + new_id, + new_struct_id, + *variant, + pattern_vec.clone(), + )) }, Pattern::Wildcard(_) => None, Pattern::Error(_) => None, diff --git a/third_party/move/move-compiler-v2/tests/ability-check/v1-typing/pack_constraint_not_satisfied.exp b/third_party/move/move-compiler-v2/tests/ability-check/v1-typing/pack_constraint_not_satisfied.exp index 167e609fa7334..bf7b9313a2289 100644 --- a/third_party/move/move-compiler-v2/tests/ability-check/v1-typing/pack_constraint_not_satisfied.exp +++ b/third_party/move/move-compiler-v2/tests/ability-check/v1-typing/pack_constraint_not_satisfied.exp @@ -18,7 +18,7 @@ error: type `R` is missing required ability `key` (type was inferred) │ - declaration of type parameter `T` · 12 │ R {r: R { r: _ } } = R { r: R { r: 0 }}; - │ ^ + │ ^^^^^^^^^^^^^^^^^^ │ = required by instantiating type parameter `T:key` of struct `R` diff --git a/third_party/move/move-compiler-v2/tests/bytecode-generator/assign.exp b/third_party/move/move-compiler-v2/tests/bytecode-generator/assign.exp index 9adcabd110f95..61a31095ee499 100644 --- a/third_party/move/move-compiler-v2/tests/bytecode-generator/assign.exp +++ b/third_party/move/move-compiler-v2/tests/bytecode-generator/assign.exp @@ -16,7 +16,7 @@ module 0x42::assign { Tuple() } private fun assign_pattern(s: assign::S,f: u64,h: u64): u64 { - assign::S{ f: f: u64, g: assign::T{ h: h: u64 } }: assign::S = s; + assign::S{ f, g: assign::T{ h } } = s; Add(f, h) } private fun assign_struct(s: &mut assign::S) { diff --git a/third_party/move/move-compiler-v2/tests/bytecode-generator/pack_unpack.exp b/third_party/move/move-compiler-v2/tests/bytecode-generator/pack_unpack.exp index aa74645f1e360..2bb77b7ee5e8e 100644 --- a/third_party/move/move-compiler-v2/tests/bytecode-generator/pack_unpack.exp +++ b/third_party/move/move-compiler-v2/tests/bytecode-generator/pack_unpack.exp @@ -12,7 +12,7 @@ module 0x42::pack_unpack { } private fun unpack(s: pack_unpack::S): (u64, u64) { { - let pack_unpack::S{ f: f: u64, g: pack_unpack::T{ h: h: u64 } }: pack_unpack::S = s; + let pack_unpack::S{ f, g: pack_unpack::T{ h } } = s; Tuple(f, h) } } diff --git a/third_party/move/move-compiler-v2/tests/bytecode-generator/wildcard1.exp b/third_party/move/move-compiler-v2/tests/bytecode-generator/wildcard1.exp index 413cd6c8f2ca3..52c1be1809af0 100644 --- a/third_party/move/move-compiler-v2/tests/bytecode-generator/wildcard1.exp +++ b/third_party/move/move-compiler-v2/tests/bytecode-generator/wildcard1.exp @@ -1,6 +1,6 @@ Diagnostics: -error: the left-hand side has 1 item but the right-hand side provided 2 +error: tuple type `(u64, u64)` is not allowed as a type argument ┌─ tests/bytecode-generator/wildcard1.move:7:13 │ 7 │ let _ = tup(); diff --git a/third_party/move/move-compiler-v2/tests/bytecode-generator/wildcard5.exp b/third_party/move/move-compiler-v2/tests/bytecode-generator/wildcard5.exp index 5964ecaf52dfd..1608427e72ff7 100644 --- a/third_party/move/move-compiler-v2/tests/bytecode-generator/wildcard5.exp +++ b/third_party/move/move-compiler-v2/tests/bytecode-generator/wildcard5.exp @@ -8,7 +8,7 @@ module 0xc0ffee::m { { let s: m::S = pack m::S(3, 4); { - let m::S{ x: _, y: _ }: m::S = s; + let m::S{ x: _, y: _ } = s; Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/bytecode-generator/wildcard6.exp b/third_party/move/move-compiler-v2/tests/bytecode-generator/wildcard6.exp index a2fcf0f8df3e3..5552e4decfe5a 100644 --- a/third_party/move/move-compiler-v2/tests/bytecode-generator/wildcard6.exp +++ b/third_party/move/move-compiler-v2/tests/bytecode-generator/wildcard6.exp @@ -4,7 +4,7 @@ module 0xc0ffee::m { { let x: u64 = 40; { - let (y: u64, _): (u64, u64) = Tuple(Move(x), x); + let (y: u64, _: u64): (u64, u64) = Tuple(Move(x), x); y } } diff --git a/third_party/move/move-compiler-v2/tests/bytecode-generator/wildcard7.exp b/third_party/move/move-compiler-v2/tests/bytecode-generator/wildcard7.exp index 1e6874b74166b..317269026392a 100644 --- a/third_party/move/move-compiler-v2/tests/bytecode-generator/wildcard7.exp +++ b/third_party/move/move-compiler-v2/tests/bytecode-generator/wildcard7.exp @@ -14,7 +14,7 @@ module 0xc0ffee::m { { let y: u8 = Move(x); { - let (_, q: u64): (u8, u64) = Tuple(x, 30); + let (_: u8, q: u64): (u8, u64) = Tuple(x, 30); y } } diff --git a/third_party/move/move-compiler-v2/tests/bytecode-generator/wildcard8.exp b/third_party/move/move-compiler-v2/tests/bytecode-generator/wildcard8.exp index effcb2e6745e9..65c184925046c 100644 --- a/third_party/move/move-compiler-v2/tests/bytecode-generator/wildcard8.exp +++ b/third_party/move/move-compiler-v2/tests/bytecode-generator/wildcard8.exp @@ -4,7 +4,7 @@ module 0xc0ffee::m { { let x: u64; { - let (_, _): (u64, u64) = Tuple(x, x); + let (_: u64, _: u64): (u64, u64) = Tuple(x, x); Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking-lang-v1/access_ok.exp b/third_party/move/move-compiler-v2/tests/checking-lang-v1/access_ok.exp index 87fdfa3004da6..c8a86116c1112 100644 --- a/third_party/move/move-compiler-v2/tests/checking-lang-v1/access_ok.exp +++ b/third_party/move/move-compiler-v2/tests/checking-lang-v1/access_ok.exp @@ -1,139 +1,49 @@ Diagnostics: -error: not supported before language version `2.0-unstable`: read/write access specifiers. Try `acquires` instead. - ┌─ tests/checking-lang-v1/access_ok.move:11:20 +error: unsupported language construct + ┌─ tests/checking-lang-v1/access_ok.move:11:14 │ 11 │ fun f2() reads S { - │ ^^ + │ ^^^^^ Move 2 language construct is not enabled: access specifiers -error: not supported before language version `2.0-unstable`: read/write access specifiers. Try `acquires` instead. - ┌─ tests/checking-lang-v1/access_ok.move:14:21 +error: unsupported language construct + ┌─ tests/checking-lang-v1/access_ok.move:14:14 │ 14 │ fun f3() writes S { - │ ^^ + │ ^^^^^^ Move 2 language construct is not enabled: access specifiers -error: not supported before language version `2.0-unstable`: wildcard address specifiers - ┌─ tests/checking-lang-v1/access_ok.move:17:24 - │ -17 │ fun f4() acquires S(*) { - │ ^^^ - -error: not supported before language version `2.0-unstable`: read/write access specifiers. Try `acquires` instead. - ┌─ tests/checking-lang-v1/access_ok.move:20:39 - │ -20 │ fun f_multiple() acquires R reads R writes T, S reads G { - │ ^^ - -error: not supported before language version `2.0-unstable`: read/write access specifiers. Try `acquires` instead. - ┌─ tests/checking-lang-v1/access_ok.move:20:48 +error: unsupported language construct + ┌─ tests/checking-lang-v1/access_ok.move:20:33 │ 20 │ fun f_multiple() acquires R reads R writes T, S reads G { - │ ^ + │ ^^^^^ Move 2 language construct is not enabled: access specifiers -error: not supported before language version `2.0-unstable`: read/write access specifiers. Try `acquires` instead. - ┌─ tests/checking-lang-v1/access_ok.move:20:51 +error: unsupported language construct + ┌─ tests/checking-lang-v1/access_ok.move:20:41 │ 20 │ fun f_multiple() acquires R reads R writes T, S reads G { - │ ^^ + │ ^^^^^^ Move 2 language construct is not enabled: access specifiers -error: not supported before language version `2.0-unstable`: read/write access specifiers. Try `acquires` instead. - ┌─ tests/checking-lang-v1/access_ok.move:20:59 +error: unsupported language construct + ┌─ tests/checking-lang-v1/access_ok.move:20:53 │ 20 │ fun f_multiple() acquires R reads R writes T, S reads G { - │ ^^^^^^^ - -error: not supported before language version `2.0-unstable`: address and wildcard access specifiers. Only resource type names can be provided. - ┌─ tests/checking-lang-v1/access_ok.move:23:23 - │ -23 │ fun f5() acquires 0x42::*::* { - │ ^^^^^^^^^^^ - -error: not supported before language version `2.0-unstable`: address and wildcard access specifiers. Only resource type names can be provided. - ┌─ tests/checking-lang-v1/access_ok.move:26:23 - │ -26 │ fun f6() acquires 0x42::m::* { - │ ^^^^^^^^^^^ + │ ^^^^^ Move 2 language construct is not enabled: access specifiers -error: not supported before language version `2.0-unstable`: wildcard address specifiers - ┌─ tests/checking-lang-v1/access_ok.move:29:24 - │ -29 │ fun f7() acquires *(*) { - │ ^^^ - -error: not supported before language version `2.0-unstable`: address and wildcard access specifiers. Only resource type names can be provided. - ┌─ tests/checking-lang-v1/access_ok.move:29:23 - │ -29 │ fun f7() acquires *(*) { - │ ^^^^ - -error: not supported before language version `2.0-unstable`: literal address specifiers - ┌─ tests/checking-lang-v1/access_ok.move:32:24 - │ -32 │ fun f8() acquires *(0x42) { - │ ^^^^^^ - -error: not supported before language version `2.0-unstable`: address and wildcard access specifiers. Only resource type names can be provided. - ┌─ tests/checking-lang-v1/access_ok.move:32:23 - │ -32 │ fun f8() acquires *(0x42) { - │ ^^^^^^^ - -error: not supported before language version `2.0-unstable`: named address specifiers - ┌─ tests/checking-lang-v1/access_ok.move:35:34 - │ -35 │ fun f9(a: address) acquires *(a) { - │ ^^^ - -error: not supported before language version `2.0-unstable`: address and wildcard access specifiers. Only resource type names can be provided. - ┌─ tests/checking-lang-v1/access_ok.move:35:33 - │ -35 │ fun f9(a: address) acquires *(a) { - │ ^^^^ - -error: not supported before language version `2.0-unstable`: derived address specifiers - ┌─ tests/checking-lang-v1/access_ok.move:38:31 - │ -38 │ fun f10(x: u64) acquires *(make_up_address(x)) { - │ ^^^^^^^^^^^^^^^^^^^^ - -error: not supported before language version `2.0-unstable`: address and wildcard access specifiers. Only resource type names can be provided. - ┌─ tests/checking-lang-v1/access_ok.move:38:30 - │ -38 │ fun f10(x: u64) acquires *(make_up_address(x)) { - │ ^^^^^^^^^^^^^^^^^^^^^ - -error: not supported before language version `2.0-unstable`: literal address specifiers - ┌─ tests/checking-lang-v1/access_ok.move:45:23 +error: unsupported language construct + ┌─ tests/checking-lang-v1/access_ok.move:45:15 │ 45 │ fun f11() !reads *(0x42), *(0x43) { - │ ^^^^^^ + │ ^ Move 2 language construct is not enabled: access specifiers -error: not supported before language version `2.0-unstable`: address and wildcard access specifiers. Only resource type names can be provided. - ┌─ tests/checking-lang-v1/access_ok.move:45:22 +error: unsupported language construct + ┌─ tests/checking-lang-v1/access_ok.move:45:16 │ 45 │ fun f11() !reads *(0x42), *(0x43) { - │ ^^^^^^^ + │ ^^^^^ Move 2 language construct is not enabled: access specifiers -error: not supported before language version `2.0-unstable`: read/write access specifiers. Try `acquires` instead. - ┌─ tests/checking-lang-v1/access_ok.move:45:22 +error: unsupported language construct + ┌─ tests/checking-lang-v1/access_ok.move:48:15 │ -45 │ fun f11() !reads *(0x42), *(0x43) { - │ ^^^^^^^ - -error: not supported before language version `2.0-unstable`: literal address specifiers - ┌─ tests/checking-lang-v1/access_ok.move:45:32 - │ -45 │ fun f11() !reads *(0x42), *(0x43) { - │ ^^^^^^ - -error: not supported before language version `2.0-unstable`: address and wildcard access specifiers. Only resource type names can be provided. - ┌─ tests/checking-lang-v1/access_ok.move:45:31 - │ -45 │ fun f11() !reads *(0x42), *(0x43) { - │ ^^^^^^^ - -error: not supported before language version `2.0-unstable`: read/write access specifiers. Try `acquires` instead. - ┌─ tests/checking-lang-v1/access_ok.move:45:31 - │ -45 │ fun f11() !reads *(0x42), *(0x43) { - │ ^^^^^^^ +48 │ fun f12() pure { + │ ^^^^ Move 2 language construct is not enabled: access specifiers diff --git a/third_party/move/move-compiler-v2/tests/checking-lang-v1/struct_variants.exp b/third_party/move/move-compiler-v2/tests/checking-lang-v1/struct_variants.exp new file mode 100644 index 0000000000000..ecff3bbff0926 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking-lang-v1/struct_variants.exp @@ -0,0 +1,13 @@ + +Diagnostics: +error: unsupported language construct + ┌─ tests/checking-lang-v1/struct_variants.move:3:5 + │ +3 │ enum S { None, Some{x: u64} } + │ ^^^^ Move 2 language construct is not enabled: struct variants + +error: unsupported language construct + ┌─ tests/checking-lang-v1/struct_variants.move:6:9 + │ +6 │ match (s) { + │ ^^^^^ Move 2 language construct is not enabled: match expression diff --git a/third_party/move/move-compiler-v2/tests/checking-lang-v1/struct_variants.move b/third_party/move/move-compiler-v2/tests/checking-lang-v1/struct_variants.move new file mode 100644 index 0000000000000..e26ed1ff792ac --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking-lang-v1/struct_variants.move @@ -0,0 +1,11 @@ +module 0x42::m { + + enum S { None, Some{x: u64} } + + fun f(s: S) { + match (s) { + None => {} + Some{x: _} => {} + } + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/abilities/tuple.exp b/third_party/move/move-compiler-v2/tests/checking/abilities/tuple.exp index 36f6a3a527412..132846113b36a 100644 --- a/third_party/move/move-compiler-v2/tests/checking/abilities/tuple.exp +++ b/third_party/move/move-compiler-v2/tests/checking/abilities/tuple.exp @@ -8,7 +8,7 @@ module 0x42::tuple { } private fun use_tuple(x: u64): u64 { { - let (x: u64, tuple::S{ f: y: u64 }): (u64, tuple::S) = tuple::tuple(x); + let (x: u64, tuple::S{ f: y }): (u64, tuple::S) = tuple::tuple(x); Add(x, y) } } diff --git a/third_party/move/move-compiler-v2/tests/checking/abilities/v1/ability_constraints.exp b/third_party/move/move-compiler-v2/tests/checking/abilities/v1/ability_constraints.exp index f5fdc5eaa7fd2..93bcfd12e634f 100644 --- a/third_party/move/move-compiler-v2/tests/checking/abilities/v1/ability_constraints.exp +++ b/third_party/move/move-compiler-v2/tests/checking/abilities/v1/ability_constraints.exp @@ -59,21 +59,21 @@ module 0x42::M { M::s>(); M::cds>(); { - let M::Sc{ dummy_field: _ }: M::Sc = pack M::Sc(false); + let M::Sc{ dummy_field: _ } = pack M::Sc(false); { - let M::Sd{ dummy_field: _ }: M::Sd = pack M::Sd(false); + let M::Sd{ dummy_field: _ } = pack M::Sd(false); { - let M::Ss{ dummy_field: _ }: M::Ss = pack M::Ss(false); + let M::Ss{ dummy_field: _ } = pack M::Ss(false); { - let M::Scds
{ dummy_field: _ }: M::Scds
= pack M::Scds
(false); + let M::Scds
{ dummy_field: _ } = pack M::Scds
(false); { - let M::Sc>{ dummy_field: _ }: M::Sc> = pack M::Sc>(false); + let M::Sc>{ dummy_field: _ } = pack M::Sc>(false); { - let M::Sd>{ dummy_field: _ }: M::Sd> = pack M::Sd>(false); + let M::Sd>{ dummy_field: _ } = pack M::Sd>(false); { - let M::Ss>{ dummy_field: _ }: M::Ss> = pack M::Ss>(false); + let M::Ss>{ dummy_field: _ } = pack M::Ss>(false); { - let M::Scds>{ dummy_field: _ }: M::Scds> = pack M::Scds>(false); + let M::Scds>{ dummy_field: _ } = pack M::Scds>(false); M::c(); M::c(); M::c(); @@ -92,39 +92,39 @@ module 0x42::M { M::sk(); M::cds(); { - let M::Sc{ dummy_field: _ }: M::Sc = pack M::Sc(false); + let M::Sc{ dummy_field: _ } = pack M::Sc(false); { - let M::Sc{ dummy_field: _ }: M::Sc = pack M::Sc(false); + let M::Sc{ dummy_field: _ } = pack M::Sc(false); { - let M::Sc{ dummy_field: _ }: M::Sc = pack M::Sc(false); + let M::Sc{ dummy_field: _ } = pack M::Sc(false); { - let M::Sc{ dummy_field: _ }: M::Sc = pack M::Sc(false); + let M::Sc{ dummy_field: _ } = pack M::Sc(false); { - let M::Sd{ dummy_field: _ }: M::Sd = pack M::Sd(false); + let M::Sd{ dummy_field: _ } = pack M::Sd(false); { - let M::Sd{ dummy_field: _ }: M::Sd = pack M::Sd(false); + let M::Sd{ dummy_field: _ } = pack M::Sd(false); { - let M::Sd{ dummy_field: _ }: M::Sd = pack M::Sd(false); + let M::Sd{ dummy_field: _ } = pack M::Sd(false); { - let M::Sd{ dummy_field: _ }: M::Sd = pack M::Sd(false); + let M::Sd{ dummy_field: _ } = pack M::Sd(false); { - let M::Ss{ dummy_field: _ }: M::Ss = pack M::Ss(false); + let M::Ss{ dummy_field: _ } = pack M::Ss(false); { - let M::Ss{ dummy_field: _ }: M::Ss = pack M::Ss(false); + let M::Ss{ dummy_field: _ } = pack M::Ss(false); { - let M::Ss{ dummy_field: _ }: M::Ss = pack M::Ss(false); + let M::Ss{ dummy_field: _ } = pack M::Ss(false); { - let M::Ss{ dummy_field: _ }: M::Ss = pack M::Ss(false); + let M::Ss{ dummy_field: _ } = pack M::Ss(false); { - let M::Ss{ dummy_field: _ }: M::Ss = pack M::Ss(false); + let M::Ss{ dummy_field: _ } = pack M::Ss(false); { - let M::Sk{ dummy_field: _ }: M::Sk = pack M::Sk(false); + let M::Sk{ dummy_field: _ } = pack M::Sk(false); { - let M::Sk{ dummy_field: _ }: M::Sk = pack M::Sk(false); + let M::Sk{ dummy_field: _ } = pack M::Sk(false); { - let M::Ssk{ dummy_field: _ }: M::Ssk = pack M::Ssk(false); + let M::Ssk{ dummy_field: _ } = pack M::Ssk(false); { - let M::Scds{ dummy_field: _ }: M::Scds = pack M::Scds(false); + let M::Scds{ dummy_field: _ } = pack M::Scds(false); M::c(); M::c>(); M::c, M::S>>(); @@ -149,51 +149,51 @@ module 0x42::M { M::cds>(); M::cds, M::S>>(); { - let M::Sc{ dummy_field: _ }: M::Sc = pack M::Sc(false); + let M::Sc{ dummy_field: _ } = pack M::Sc(false); { - let M::Sc>{ dummy_field: _ }: M::Sc> = pack M::Sc>(false); + let M::Sc>{ dummy_field: _ } = pack M::Sc>(false); { - let M::Sc, M::S>>{ dummy_field: _ }: M::Sc, M::S>> = pack M::Sc, M::S>>(false); + let M::Sc, M::S>>{ dummy_field: _ } = pack M::Sc, M::S>>(false); { - let M::Sd{ dummy_field: _ }: M::Sd = pack M::Sd(false); + let M::Sd{ dummy_field: _ } = pack M::Sd(false); { - let M::Sd>{ dummy_field: _ }: M::Sd> = pack M::Sd>(false); + let M::Sd>{ dummy_field: _ } = pack M::Sd>(false); { - let M::Sd, M::S>>{ dummy_field: _ }: M::Sd, M::S>> = pack M::Sd, M::S>>(false); + let M::Sd, M::S>>{ dummy_field: _ } = pack M::Sd, M::S>>(false); { - let M::Ss{ dummy_field: _ }: M::Ss = pack M::Ss(false); + let M::Ss{ dummy_field: _ } = pack M::Ss(false); { - let M::Ss{ dummy_field: _ }: M::Ss = pack M::Ss(false); + let M::Ss{ dummy_field: _ } = pack M::Ss(false); { - let M::Ss>{ dummy_field: _ }: M::Ss> = pack M::Ss>(false); + let M::Ss>{ dummy_field: _ } = pack M::Ss>(false); { - let M::Ss>{ dummy_field: _ }: M::Ss> = pack M::Ss>(false); + let M::Ss>{ dummy_field: _ } = pack M::Ss>(false); { - let M::Ss, M::S>>{ dummy_field: _ }: M::Ss, M::S>> = pack M::Ss, M::S>>(false); + let M::Ss, M::S>>{ dummy_field: _ } = pack M::Ss, M::S>>(false); { - let M::Ss>>>{ dummy_field: _ }: M::Ss>>> = pack M::Ss>>>(false); + let M::Ss>>>{ dummy_field: _ } = pack M::Ss>>>(false); { - let M::Sk{ dummy_field: _ }: M::Sk = pack M::Sk(false); + let M::Sk{ dummy_field: _ } = pack M::Sk(false); { - let M::Sk>{ dummy_field: _ }: M::Sk> = pack M::Sk>(false); + let M::Sk>{ dummy_field: _ } = pack M::Sk>(false); { - let M::Sk>>{ dummy_field: _ }: M::Sk>> = pack M::Sk>>(false); + let M::Sk>>{ dummy_field: _ } = pack M::Sk>>(false); { - let M::Sk>>>{ dummy_field: _ }: M::Sk>>> = pack M::Sk>>>(false); + let M::Sk>>>{ dummy_field: _ } = pack M::Sk>>>(false); { - let M::Ssk{ dummy_field: _ }: M::Ssk = pack M::Ssk(false); + let M::Ssk{ dummy_field: _ } = pack M::Ssk(false); { - let M::Ssk>{ dummy_field: _ }: M::Ssk> = pack M::Ssk>(false); + let M::Ssk>{ dummy_field: _ } = pack M::Ssk>(false); { - let M::Ssk>>{ dummy_field: _ }: M::Ssk>> = pack M::Ssk>>(false); + let M::Ssk>>{ dummy_field: _ } = pack M::Ssk>>(false); { - let M::Ssk>>>{ dummy_field: _ }: M::Ssk>>> = pack M::Ssk>>>(false); + let M::Ssk>>>{ dummy_field: _ } = pack M::Ssk>>>(false); { - let M::Scds{ dummy_field: _ }: M::Scds = pack M::Scds(false); + let M::Scds{ dummy_field: _ } = pack M::Scds(false); { - let M::Scds>{ dummy_field: _ }: M::Scds> = pack M::Scds>(false); + let M::Scds>{ dummy_field: _ } = pack M::Scds>(false); { - let M::Scds, M::S>>{ dummy_field: _ }: M::Scds, M::S>> = pack M::Scds, M::S>>(false); + let M::Scds, M::S>>{ dummy_field: _ } = pack M::Scds, M::S>>(false); Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking/naming/global_builtin_one_type_argument.exp b/third_party/move/move-compiler-v2/tests/checking/naming/global_builtin_one_type_argument.exp index 126eb1e9aaa6b..441e25f4f2b3b 100644 --- a/third_party/move/move-compiler-v2/tests/checking/naming/global_builtin_one_type_argument.exp +++ b/third_party/move/move-compiler-v2/tests/checking/naming/global_builtin_one_type_argument.exp @@ -15,7 +15,7 @@ module 0x8675309::M { { let _: &mut M::R = BorrowGlobal(Mutable)(0x0); { - let M::R{ dummy_field: _ }: M::R = MoveFrom(0x0); + let M::R{ dummy_field: _ } = MoveFrom(0x0); Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking/naming/struct_in_current_module.exp b/third_party/move/move-compiler-v2/tests/checking/naming/struct_in_current_module.exp index 93ba4b71e23df..8e0fcca2100b4 100644 --- a/third_party/move/move-compiler-v2/tests/checking/naming/struct_in_current_module.exp +++ b/third_party/move/move-compiler-v2/tests/checking/naming/struct_in_current_module.exp @@ -10,7 +10,7 @@ module 0x8675309::M { { let _: M::S = pack M::S(0); { - let M::R{ f: _ }: M::R = pack M::R(0); + let M::R{ f: _ } = pack M::R(0); Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking/naming/unbound_constant.exp b/third_party/move/move-compiler-v2/tests/checking/naming/unbound_constant.exp index 5588e782ccafe..5e3ee6617e204 100644 --- a/third_party/move/move-compiler-v2/tests/checking/naming/unbound_constant.exp +++ b/third_party/move/move-compiler-v2/tests/checking/naming/unbound_constant.exp @@ -4,10 +4,10 @@ error: unbound module ┌─ tests/checking/naming/unbound_constant.move:14:17 │ 14 │ let y = Self::CONSTANT; - │ ^^^^ Unbound module alias 'Self' + │ ^^^^ Unbound module or type alias 'Self' error: unbound module ┌─ tests/checking/naming/unbound_constant.move:15:24 │ 15 │ 0 + CONSTANT + Self::CONSTANT; - │ ^^^^ Unbound module alias 'Self' + │ ^^^^ Unbound module or type alias 'Self' diff --git a/third_party/move/move-compiler-v2/tests/checking/naming/unbound_module.exp b/third_party/move/move-compiler-v2/tests/checking/naming/unbound_module.exp index c884e4383b476..d435475cb10ba 100644 --- a/third_party/move/move-compiler-v2/tests/checking/naming/unbound_module.exp +++ b/third_party/move/move-compiler-v2/tests/checking/naming/unbound_module.exp @@ -10,4 +10,4 @@ error: unbound module ┌─ tests/checking/naming/unbound_module.move:4:9 │ 4 │ X::foo(); - │ ^ Unbound module alias 'X' + │ ^ Unbound module or type alias 'X' diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/annotated_types.exp b/third_party/move/move-compiler-v2/tests/checking/typing/annotated_types.exp index 7043502d05cac..7547136a5af2a 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/annotated_types.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/annotated_types.exp @@ -10,8 +10,8 @@ module 0x8675309::M { Tuple(); 0; pack M::S(false); - M::R{ dummy_field: _ }: M::R = pack M::R(false); - (_, _, M::R{ dummy_field: _ }): (u64, M::S, M::R) = Tuple(0, pack M::S(false), pack M::R(false)); + M::R{ dummy_field: _ } = pack M::R(false); + (_: u64, _: M::S, M::R{ dummy_field: _ }): (u64, M::S, M::R) = Tuple(0, pack M::S(false), pack M::R(false)); Tuple() } } // end 0x8675309::M diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/assign_unpack_references.exp b/third_party/move/move-compiler-v2/tests/checking/typing/assign_unpack_references.exp index 113c874445846..0013af0023a25 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/assign_unpack_references.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/assign_unpack_references.exp @@ -12,7 +12,7 @@ module 0x8675309::M { let f: u64; { let s2: M::S; - M::R{ s1: M::S{ f: f: u64 }, s2: s2: M::S }: M::R = pack M::R(pack M::S(0), pack M::S(1)); + M::R{ s1: M::S{ f }, s2 } = pack M::R(pack M::S(0), pack M::S(1)); f; s2; f: u64 = 0; @@ -28,7 +28,7 @@ module 0x8675309::M { let f: &u64; { let s2: &M::S; - M::R{ s1: M::S{ f: f: &u64 }, s2: s2: &M::S }: &M::R = Borrow(Immutable)(pack M::R(pack M::S(0), pack M::S(1))); + M::R{ s1: M::S{ f }, s2 } = Borrow(Immutable)(pack M::R(pack M::S(0), pack M::S(1))); f; s2; f: &u64 = Borrow(Immutable)(0); @@ -44,7 +44,7 @@ module 0x8675309::M { let f: &mut u64; { let s2: &mut M::S; - M::R{ s1: M::S{ f: f: &mut u64 }, s2: s2: &mut M::S }: &mut M::R = Borrow(Mutable)(pack M::R(pack M::S(0), pack M::S(1))); + M::R{ s1: M::S{ f }, s2 } = Borrow(Mutable)(pack M::R(pack M::S(0), pack M::S(1))); f; s2; f: &mut u64 = Borrow(Mutable)(0); diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/bad_type_argument_arity_struct_unpack.exp b/third_party/move/move-compiler-v2/tests/checking/typing/bad_type_argument_arity_struct_unpack.exp index dbc956ddccf4d..9593d670e3841 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/bad_type_argument_arity_struct_unpack.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/bad_type_argument_arity_struct_unpack.exp @@ -4,7 +4,7 @@ error: expected 1 type argument but 0 were provided ┌─ tests/checking/typing/bad_type_argument_arity_struct_unpack.move:7:13 │ 7 │ let S<> { f } = copy s; - │ ^ + │ ^^^^^^^^^ error: undeclared `f` ┌─ tests/checking/typing/bad_type_argument_arity_struct_unpack.move:8:9 @@ -16,7 +16,7 @@ error: expected 1 type argument but 2 were provided ┌─ tests/checking/typing/bad_type_argument_arity_struct_unpack.move:9:13 │ 9 │ let S { f } = copy s; - │ ^ + │ ^^^^^^^^^^^^^^^^^ error: undeclared `f` ┌─ tests/checking/typing/bad_type_argument_arity_struct_unpack.move:10:9 diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/binary_add.exp b/third_party/move/move-compiler-v2/tests/checking/typing/binary_add.exp index 9e087eb9543ed..499d07865f69a 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/binary_add.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/binary_add.exp @@ -16,7 +16,7 @@ module 0x8675309::M { Add(select M::R.f(r), select M::R.f(r)); Add(Add(Add(1, select M::R.f(r)), select M::R.f(r)), 0); { - let M::R{ f: _ }: M::R = r; + let M::R{ f: _ } = r; Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/binary_and.exp b/third_party/move/move-compiler-v2/tests/checking/typing/binary_and.exp index 32ca4b79ac6ea..dcc109892aa00 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/binary_and.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/binary_and.exp @@ -12,7 +12,7 @@ module 0x8675309::M { And(select M::R.f(r), select M::R.f(r)); false; { - let M::R{ f: _ }: M::R = r; + let M::R{ f: _ } = r; Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/binary_bit_and.exp b/third_party/move/move-compiler-v2/tests/checking/typing/binary_bit_and.exp index 2790687e71d0d..176d035a54ab7 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/binary_bit_and.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/binary_bit_and.exp @@ -16,7 +16,7 @@ module 0x8675309::M { BitAnd(select M::R.f(r), select M::R.f(r)); BitAnd(BitAnd(BitAnd(1, select M::R.f(r)), select M::R.f(r)), 0); { - let M::R{ f: _ }: M::R = r; + let M::R{ f: _ } = r; Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/binary_bit_or.exp b/third_party/move/move-compiler-v2/tests/checking/typing/binary_bit_or.exp index dbf054f66724d..a0dd5a3086d89 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/binary_bit_or.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/binary_bit_or.exp @@ -16,7 +16,7 @@ module 0x8675309::M { BitOr(select M::R.f(r), select M::R.f(r)); BitOr(BitOr(BitOr(1, select M::R.f(r)), select M::R.f(r)), 0); { - let M::R{ f: _ }: M::R = r; + let M::R{ f: _ } = r; Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/binary_div.exp b/third_party/move/move-compiler-v2/tests/checking/typing/binary_div.exp index ae44a168cf687..619ea3afb311a 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/binary_div.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/binary_div.exp @@ -16,7 +16,7 @@ module 0x8675309::M { Div(select M::R.f(r), select M::R.f(r)); Div(Div(Div(1, select M::R.f(r)), select M::R.f(r)), 0); { - let M::R{ f: _ }: M::R = r; + let M::R{ f: _ } = r; Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/binary_geq.exp b/third_party/move/move-compiler-v2/tests/checking/typing/binary_geq.exp index 7d908dce88634..1cb8410cde8ec 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/binary_geq.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/binary_geq.exp @@ -16,7 +16,7 @@ module 0x8675309::M { Ge(select M::R.f(r), select M::R.f(r)); And(Ge(1, select M::R.f(r)), Ge(select M::R.f(r), 0)); { - let M::R{ f: _ }: M::R = r; + let M::R{ f: _ } = r; Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/binary_gt.exp b/third_party/move/move-compiler-v2/tests/checking/typing/binary_gt.exp index d20902dce81f9..550c2c2a85560 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/binary_gt.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/binary_gt.exp @@ -16,7 +16,7 @@ module 0x8675309::M { Gt(select M::R.f(r), select M::R.f(r)); And(Gt(1, select M::R.f(r)), Gt(select M::R.f(r), 0)); { - let M::R{ f: _ }: M::R = r; + let M::R{ f: _ } = r; Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/binary_leq.exp b/third_party/move/move-compiler-v2/tests/checking/typing/binary_leq.exp index a638674bf270d..72c2b34c7462a 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/binary_leq.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/binary_leq.exp @@ -16,7 +16,7 @@ module 0x8675309::M { Le(select M::R.f(r), select M::R.f(r)); And(Le(1, select M::R.f(r)), Le(select M::R.f(r), 0)); { - let M::R{ f: _ }: M::R = r; + let M::R{ f: _ } = r; Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/binary_lt.exp b/third_party/move/move-compiler-v2/tests/checking/typing/binary_lt.exp index 2b114f9cb3ebb..39c7c05043c27 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/binary_lt.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/binary_lt.exp @@ -16,7 +16,7 @@ module 0x8675309::M { Lt(select M::R.f(r), select M::R.f(r)); And(Lt(1, select M::R.f(r)), Lt(select M::R.f(r), 0)); { - let M::R{ f: _ }: M::R = r; + let M::R{ f: _ } = r; Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/binary_mod.exp b/third_party/move/move-compiler-v2/tests/checking/typing/binary_mod.exp index 250074d80f316..354e15f5bb020 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/binary_mod.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/binary_mod.exp @@ -16,7 +16,7 @@ module 0x8675309::M { Mod(select M::R.f(r), select M::R.f(r)); Mod(Mod(Mod(1, select M::R.f(r)), select M::R.f(r)), 0); { - let M::R{ f: _ }: M::R = r; + let M::R{ f: _ } = r; Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/binary_mul.exp b/third_party/move/move-compiler-v2/tests/checking/typing/binary_mul.exp index 433d904698cde..061c338dc982b 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/binary_mul.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/binary_mul.exp @@ -16,7 +16,7 @@ module 0x8675309::M { Mul(select M::R.f(r), select M::R.f(r)); Mul(Mul(Mul(1, select M::R.f(r)), select M::R.f(r)), 0); { - let M::R{ f: _ }: M::R = r; + let M::R{ f: _ } = r; Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/binary_or.exp b/third_party/move/move-compiler-v2/tests/checking/typing/binary_or.exp index 454508a1be28d..ba12114e3fabb 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/binary_or.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/binary_or.exp @@ -12,7 +12,7 @@ module 0x8675309::M { Or(select M::R.f(r), select M::R.f(r)); true; { - let M::R{ f: _ }: M::R = r; + let M::R{ f: _ } = r; Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/binary_shl.exp b/third_party/move/move-compiler-v2/tests/checking/typing/binary_shl.exp index 5b13887916dc0..d5774d480eedc 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/binary_shl.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/binary_shl.exp @@ -15,6 +15,6 @@ module 0x8675309::M { Shl(Copy(x), Copy(b)); Shl(select M::R.f(r), select M::R.b(r)); Shl(Shl(Shl(1, select M::R.b(r)), select M::R.b(r)), 0); - M::R{ f: _, b: _ }: M::R = r + M::R{ f: _, b: _ } = r } } // end 0x8675309::M diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/binary_shr.exp b/third_party/move/move-compiler-v2/tests/checking/typing/binary_shr.exp index 0de2faf0e9406..9f84205f4b470 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/binary_shr.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/binary_shr.exp @@ -15,6 +15,6 @@ module 0x8675309::M { Shr(Copy(x), Copy(b)); Shr(select M::R.f(r), select M::R.b(r)); Shr(Shr(Shr(1, select M::R.b(r)), select M::R.b(r)), 0); - M::R{ f: _, b: _ }: M::R = r + M::R{ f: _, b: _ } = r } } // end 0x8675309::M diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/binary_sub.exp b/third_party/move/move-compiler-v2/tests/checking/typing/binary_sub.exp index 8389a80b3c605..7165eb499e522 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/binary_sub.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/binary_sub.exp @@ -16,7 +16,7 @@ module 0x8675309::M { Sub(select M::R.f(r), select M::R.f(r)); Sub(Sub(Sub(1, select M::R.f(r)), select M::R.f(r)), 0); { - let M::R{ f: _ }: M::R = r; + let M::R{ f: _ } = r; Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/binary_xor.exp b/third_party/move/move-compiler-v2/tests/checking/typing/binary_xor.exp index 254f493239fbf..e0ca221882df9 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/binary_xor.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/binary_xor.exp @@ -16,7 +16,7 @@ module 0x8675309::M { Xor(select M::R.f(r), select M::R.f(r)); Xor(Xor(Xor(1, select M::R.f(r)), select M::R.f(r)), 0); { - let M::R{ f: _ }: M::R = r; + let M::R{ f: _ } = r; Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/bind_unpack_references.exp b/third_party/move/move-compiler-v2/tests/checking/typing/bind_unpack_references.exp index db76d4d023d61..8a20a43e515fb 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/bind_unpack_references.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/bind_unpack_references.exp @@ -9,7 +9,7 @@ module 0x8675309::M { } private fun t0() { { - let M::R{ s1: M::S{ f: f: u64 }, s2: s2: M::S }: M::R = pack M::R(pack M::S(0), pack M::S(1)); + let M::R{ s1: M::S{ f }, s2 } = pack M::R(pack M::S(0), pack M::S(1)); f; s2; f: u64 = 0; @@ -21,7 +21,7 @@ module 0x8675309::M { } private fun t1() { { - let M::R{ s1: M::S{ f: f: &u64 }, s2: s2: &M::S }: &M::R = Borrow(Immutable)(pack M::R(pack M::S(0), pack M::S(1))); + let M::R{ s1: M::S{ f }, s2 } = Borrow(Immutable)(pack M::R(pack M::S(0), pack M::S(1))); f; s2; f: &u64 = Borrow(Immutable)(0); @@ -33,7 +33,7 @@ module 0x8675309::M { } private fun t2() { { - let M::R{ s1: M::S{ f: f: &mut u64 }, s2: s2: &mut M::S }: &mut M::R = Borrow(Mutable)(pack M::R(pack M::S(0), pack M::S(1))); + let M::R{ s1: M::S{ f }, s2 } = Borrow(Mutable)(pack M::R(pack M::S(0), pack M::S(1))); f; s2; f: &mut u64 = Borrow(Mutable)(0); diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/bind_with_type_annot.exp b/third_party/move/move-compiler-v2/tests/checking/typing/bind_with_type_annot.exp index b1f83a37dd8ff..76be5734e6def 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/bind_with_type_annot.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/bind_with_type_annot.exp @@ -6,7 +6,7 @@ module 0x8675309::M { private fun t0() { 0; { - let (x: u64, b: bool, M::R{ f: f: u64 }): (u64, bool, M::R) = Tuple(0, false, pack M::R(0)); + let (x: u64, b: bool, M::R{ f }): (u64, bool, M::R) = Tuple(0, false, pack M::R(0)); 0; false; 0; diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/block_single_expr.exp b/third_party/move/move-compiler-v2/tests/checking/typing/block_single_expr.exp index d95820b32500b..d443f1578d571 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/block_single_expr.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/block_single_expr.exp @@ -7,7 +7,7 @@ module 0x8675309::M { 0; Borrow(Immutable)(0); Borrow(Mutable)(0); - M::R{ dummy_field: _ }: M::R = pack M::R(false); + M::R{ dummy_field: _ } = pack M::R(false); Tuple(0, false); Tuple() } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/block_with_statements.exp b/third_party/move/move-compiler-v2/tests/checking/typing/block_with_statements.exp index 49da61a60044d..ab55de9be63c6 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/block_with_statements.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/block_with_statements.exp @@ -7,7 +7,7 @@ module 0x8675309::M { 0; Borrow(Immutable)(0); Borrow(Mutable)(1); - M::R{ dummy_field: _ }: M::R = { + M::R{ dummy_field: _ } = { let r: M::R = { let r: M::R = pack M::R(false); r diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/break_any_type.exp b/third_party/move/move-compiler-v2/tests/checking/typing/break_any_type.exp index 83c13df9c03f2..cd7b6720f3e26 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/break_any_type.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/break_any_type.exp @@ -4,7 +4,7 @@ module 0x8675309::M { dummy_field: bool, } private fun foo(c: M::Coin) { - M::Coin{ dummy_field: _ }: M::Coin = c; + M::Coin{ dummy_field: _ } = c; Tuple() } private fun t0() { diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/continue_any_type.exp b/third_party/move/move-compiler-v2/tests/checking/typing/continue_any_type.exp index cbe7dcef440a5..d24bcf657bd5c 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/continue_any_type.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/continue_any_type.exp @@ -4,7 +4,7 @@ module 0x8675309::M { dummy_field: bool, } private fun foo(c: M::Coin) { - M::Coin{ dummy_field: _ }: M::Coin = c; + M::Coin{ dummy_field: _ } = c; Tuple() } private fun t0() { diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/decl_unpack_references.exp b/third_party/move/move-compiler-v2/tests/checking/typing/decl_unpack_references.exp index 4ae85cde80802..9a0164bc1800c 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/decl_unpack_references.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/decl_unpack_references.exp @@ -9,7 +9,7 @@ module 0x8675309::M { } private fun t0() { { - let M::R{ s1: M::S{ f: f: u64 }, s2: s2: M::S }: M::R; + let M::R{ s1: M::S{ f }, s2 }; f: u64 = 0; f; s2: M::S = pack M::S(0); @@ -19,7 +19,7 @@ module 0x8675309::M { } private fun t1() { { - let M::R{ s1: M::S{ f: f: &u64 }, s2: s2: &M::S }: &M::R; + let M::R{ s1: M::S{ f }, s2 }; f: &u64 = Borrow(Immutable)(0); f; s2: &M::S = Borrow(Immutable)(pack M::S(0)); @@ -29,7 +29,7 @@ module 0x8675309::M { } private fun t2() { { - let M::R{ s1: M::S{ f: f: &mut u64 }, s2: s2: &mut M::S }: &mut M::R; + let M::R{ s1: M::S{ f }, s2 }; f: &mut u64 = Borrow(Mutable)(0); f; s2: &mut M::S = Borrow(Mutable)(pack M::S(0)); diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/declare_with_type_annot.exp b/third_party/move/move-compiler-v2/tests/checking/typing/declare_with_type_annot.exp index 5cd9dba7c12ef..1963ff3280348 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/declare_with_type_annot.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/declare_with_type_annot.exp @@ -31,7 +31,7 @@ module 0x8675309::M { } private fun t0() { { - let (x: u64, b: bool, M::R{ f: f: u64 }): (u64, bool, M::R); + let (x: u64, b: bool, M::R{ f }): (u64, bool, M::R); Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/derefrence_reference.exp b/third_party/move/move-compiler-v2/tests/checking/typing/derefrence_reference.exp index 08e7e8e5752fb..23c269a5f9e30 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/derefrence_reference.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/derefrence_reference.exp @@ -7,16 +7,16 @@ module 0x8675309::M { dummy_field: bool, } private fun t0(r: &M::R,b: &M::B) { - M::R{ dummy_field: _ }: M::R = Deref(r); - M::B{ r: M::R{ dummy_field: _ } }: M::B = Deref(b); - M::R{ dummy_field: _ }: M::R = Deref(Borrow(Immutable)(select M::B.r<&M::B>(b))); + M::R{ dummy_field: _ } = Deref(r); + M::B{ r: M::R{ dummy_field: _ } } = Deref(b); + M::R{ dummy_field: _ } = Deref(Borrow(Immutable)(select M::B.r<&M::B>(b))); Tuple() } private fun t1(r: &mut M::R,b: &mut M::B) { - M::R{ dummy_field: _ }: M::R = Deref(r); - M::B{ r: M::R{ dummy_field: _ } }: M::B = Deref(b); - M::R{ dummy_field: _ }: M::R = Deref(Borrow(Immutable)(select M::B.r<&mut M::B>(b))); - M::R{ dummy_field: _ }: M::R = Deref(Borrow(Mutable)(select M::B.r<&mut M::B>(b))); + M::R{ dummy_field: _ } = Deref(r); + M::B{ r: M::R{ dummy_field: _ } } = Deref(b); + M::R{ dummy_field: _ } = Deref(Borrow(Immutable)(select M::B.r<&mut M::B>(b))); + M::R{ dummy_field: _ } = Deref(Borrow(Mutable)(select M::B.r<&mut M::B>(b))); Tuple() } } // end 0x8675309::M diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/explicit_move.exp b/third_party/move/move-compiler-v2/tests/checking/typing/explicit_move.exp index fca6d43199aa7..27cbe3d3c17ea 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/explicit_move.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/explicit_move.exp @@ -15,7 +15,7 @@ module 0x8675309::M { let r: M::R = pack M::R(false); Move(u); Move(s); - M::R{ dummy_field: _ }: M::R = Move(r); + M::R{ dummy_field: _ } = Move(r); Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/global_builtins.exp b/third_party/move/move-compiler-v2/tests/checking/typing/global_builtins.exp index 49fea56f30c37..90546524be56a 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/global_builtins.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/global_builtins.exp @@ -15,7 +15,7 @@ module 0x8675309::M { { let _: &mut M::R = BorrowGlobal(Mutable)(0x0); { - let M::R{ dummy_field: _ }: M::R = MoveFrom(0x0); + let M::R{ dummy_field: _ } = MoveFrom(0x0); Tuple() } } @@ -35,7 +35,7 @@ module 0x8675309::M { { let _: &mut M::R = BorrowGlobal(Mutable)(0x0); { - let M::R{ dummy_field: _ }: M::R = MoveFrom(0x0); + let M::R{ dummy_field: _ } = MoveFrom(0x0); Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/global_builtins_inferred.exp b/third_party/move/move-compiler-v2/tests/checking/typing/global_builtins_inferred.exp index 7d309300ae608..8e154566ebee7 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/global_builtins_inferred.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/global_builtins_inferred.exp @@ -9,7 +9,7 @@ module 0x42::m { { let a: m::A = MoveFrom(input); { - let m::A{ addr: addr: address }: m::A = a; + let m::A{ addr } = a; addr } } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/if_branches_subtype.exp b/third_party/move/move-compiler-v2/tests/checking/typing/if_branches_subtype.exp index 890936aec05ac..9d0e1d8462b55 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/if_branches_subtype.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/if_branches_subtype.exp @@ -26,19 +26,19 @@ module 0x8675309::M { } private fun t1(cond: bool,u: &u64,u_mut: &mut u64) { { - let (_, _): (&u64, &u64) = if cond { + let (_: &u64, _: &u64): (&u64, &u64) = if cond { Tuple(u, u) } else { Tuple(Freeze(false)(u_mut), Freeze(false)(u_mut)) }; { - let (_, _): (&u64, &u64) = if cond { + let (_: &u64, _: &u64): (&u64, &u64) = if cond { Tuple(Freeze(false)(u_mut), u) } else { Tuple(u, Freeze(false)(u_mut)) }; { - let (_, _): (&u64, &u64) = if cond { + let (_: &u64, _: &u64): (&u64, &u64) = if cond { Tuple(u, Freeze(false)(u_mut)) } else { Tuple(Freeze(false)(u_mut), u) diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/if_matched_branches.exp b/third_party/move/move-compiler-v2/tests/checking/typing/if_matched_branches.exp index dde6ad390175b..780bf81624ba8 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/if_matched_branches.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/if_matched_branches.exp @@ -22,7 +22,7 @@ module 0x8675309::M { } else { false }; - M::R{ dummy_field: _ }: M::R = if cond { + M::R{ dummy_field: _ } = if cond { pack M::R(false) } else { pack M::R(false) @@ -45,7 +45,7 @@ module 0x8675309::M { } else { Tuple(1, true) }; - (_, _, _, M::R{ dummy_field: _ }): (u64, u64, &u64, M::R) = if cond { + (_: u64, _: u64, _: &u64, M::R{ dummy_field: _ }): (u64, u64, &u64, M::R) = if cond { Tuple(0, 0, Borrow(Immutable)(0), pack M::R(false)) } else { Tuple(1, 1, Borrow(Immutable)(1), pack M::R(false)) diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/main_arguments_various_caes.exp b/third_party/move/move-compiler-v2/tests/checking/typing/main_arguments_various_caes.exp index 4506397b17329..a729ac9e9d988 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/main_arguments_various_caes.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/main_arguments_various_caes.exp @@ -10,7 +10,7 @@ module 0x42::M { dummy_field: bool, } public fun eat(r: M::R) { - M::R{ dummy_field: _ }: M::R = r + M::R{ dummy_field: _ } = r } } // end 0x42::M module _0 { diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/move_from_type_argument.exp b/third_party/move/move-compiler-v2/tests/checking/typing/move_from_type_argument.exp index 7d309300ae608..8e154566ebee7 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/move_from_type_argument.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/move_from_type_argument.exp @@ -9,7 +9,7 @@ module 0x42::m { { let a: m::A = MoveFrom(input); { - let m::A{ addr: addr: address }: m::A = a; + let m::A{ addr } = a; addr } } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/native_structs_pack_unpack.exp b/third_party/move/move-compiler-v2/tests/checking/typing/native_structs_pack_unpack.exp index de0895bc5f938..a612877c96823 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/native_structs_pack_unpack.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/native_structs_pack_unpack.exp @@ -1,17 +1,23 @@ Diagnostics: -error: native struct `C::T` cannot be packed or unpacked +bug: inconsistent struct definition ┌─ tests/checking/typing/native_structs_pack_unpack.move:9:9 │ 9 │ C::T {} │ ^^^^ -error: native struct `C::T` cannot be packed or unpacked +bug: inconsistent struct definition ┌─ tests/checking/typing/native_structs_pack_unpack.move:12:13 │ 12 │ let C::T {} = c; │ ^^^^ +error: unable to infer instantiation of type `_` (consider providing type arguments or annotating the type) + ┌─ tests/checking/typing/native_structs_pack_unpack.move:12:13 + │ +12 │ let C::T {} = c; + │ ^^^^^^^ + error: field `f` not declared in struct `C::T` ┌─ tests/checking/typing/native_structs_pack_unpack.move:15:17 │ diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/pack.exp b/third_party/move/move-compiler-v2/tests/checking/typing/pack.exp index 0f3dc465a790b..ce3eca24ab5c2 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/pack.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/pack.exp @@ -16,7 +16,7 @@ module 0x8675309::M { pack M::S(0); { let s: M::S = pack M::S(0); - M::R{ s: _, f: _, n1: _, n2: _ }: M::R = { + M::R{ s: _, f: _, n1: _, n2: _ } = { let $s: M::S = pack M::S(0); { let $n2: M::Nat = pack M::Nat(s); @@ -32,7 +32,7 @@ module 0x8675309::M { let n1: M::Nat = pack M::Nat(0); { let n2: M::Nat = pack M::Nat(Deref(Borrow(Immutable)(s))); - M::R{ s: _, f: _, n1: _, n2: _ }: M::R = { + M::R{ s: _, f: _, n1: _, n2: _ } = { let $s: M::S = s; { let $n2: M::Nat = n2; diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/pack_missing_field.exp b/third_party/move/move-compiler-v2/tests/checking/typing/pack_missing_field.exp index 40af2c08e76f8..f202b4166347c 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/pack_missing_field.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/pack_missing_field.exp @@ -1,24 +1,24 @@ Diagnostics: -error: missing fields `f` +error: missing field `f` ┌─ tests/checking/typing/pack_missing_field.move:7:10 │ 7 │ (S { } : S); │ ^^^^^ -error: missing fields `n2` +error: missing field `n2` ┌─ tests/checking/typing/pack_missing_field.move:8:37 │ 8 │ R {s:_, f:_, n1:_, n2:_} = (R { s: S{f: 0}, n1: Nat{f: 0}, f: 0, } : R); │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: missing fields `f` +error: missing field `f` ┌─ tests/checking/typing/pack_missing_field.move:14:37 │ 14 │ R {s:_, f:_, n1:_, n2:_} = (R { s, n2, n1 }: R); │ ^^^^^^^^^^^^^^^ -error: missing fields `f` +error: missing field `f` ┌─ tests/checking/typing/pack_missing_field.move:16:28 │ 16 │ (Nat { f: Nat { f: Nat { }}}: Nat>>); diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/return_any_type.exp b/third_party/move/move-compiler-v2/tests/checking/typing/return_any_type.exp index aaa4fa5685abc..bdaaf2919cd70 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/return_any_type.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/return_any_type.exp @@ -4,7 +4,7 @@ module 0x8675309::M { dummy_field: bool, } private fun foo(c: M::Coin) { - M::Coin{ dummy_field: _ }: M::Coin = c; + M::Coin{ dummy_field: _ } = c; Tuple() } private fun t0() { diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/shadowing.exp b/third_party/move/move-compiler-v2/tests/checking/typing/shadowing.exp index 68a67cb66924f..7c470644e168e 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/shadowing.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/shadowing.exp @@ -32,7 +32,7 @@ module 0x8675309::M { private fun t2() { loop { { - let M::S{ f: _, b: x: bool }: M::S = pack M::S(0, false); + let M::S{ f: _, b: x } = pack M::S(0, false); false; break } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/tuple.exp b/third_party/move/move-compiler-v2/tests/checking/typing/tuple.exp index 36f6a3a527412..132846113b36a 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/tuple.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/tuple.exp @@ -8,7 +8,7 @@ module 0x42::tuple { } private fun use_tuple(x: u64): u64 { { - let (x: u64, tuple::S{ f: y: u64 }): (u64, tuple::S) = tuple::tuple(x); + let (x: u64, tuple::S{ f: y }): (u64, tuple::S) = tuple::tuple(x); Add(x, y) } } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_single_unpack.exp b/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_single_unpack.exp index ad69dde0ab356..63252d1509136 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_single_unpack.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_single_unpack.exp @@ -9,11 +9,11 @@ module 0x8675309::M { } private fun t0() { { - let M::Box{ f1: f1: u64, f2: f2: u64 }: M::Box = M::new(); + let M::Box{ f1, f2 } = M::new(); f1; f2; { - let M::Box>{ f1: f1: M::Box, f2: f2: M::Box }: M::Box> = M::new>(); + let M::Box>{ f1, f2 } = M::new>(); f1; f2; Tuple() diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_single_unpack_assign.exp b/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_single_unpack_assign.exp index 8d92a003aa660..141500cd03452 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_single_unpack_assign.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_single_unpack_assign.exp @@ -12,14 +12,14 @@ module 0x8675309::M { let f1: u64; { let f2: u64; - M::Box{ f1: f1: u64, f2: f2: u64 }: M::Box = M::new(); + M::Box{ f1, f2 } = M::new(); f1; f2; { let f1: M::Box; { let f2: M::Box; - M::Box>{ f1: f1: M::Box, f2: f2: M::Box }: M::Box> = M::new>(); + M::Box>{ f1, f2 } = M::new>(); f1; f2; Tuple() diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_threaded_unpack.exp b/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_threaded_unpack.exp index 7cd966403489e..867745d67f570 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_threaded_unpack.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_threaded_unpack.exp @@ -26,7 +26,7 @@ module 0x2::M { { let v: Container::T> = Container::new>(); { - let M::Box{ f1: f1: u64, f2: f2: u64 }: M::Box = Container::get>(Borrow(Immutable)(v)); + let M::Box{ f1, f2 } = Container::get>(Borrow(Immutable)(v)); f2; Container::put>(Borrow(Mutable)(v), pack M::Box(0, 0)); f1 @@ -37,7 +37,7 @@ module 0x2::M { { let v: Container::T>>> = Container::new>>>(); { - let M::Box>>{ f1: f1: M::Box>, f2: f2: M::Box> }: M::Box>> = Container::get>>>(Borrow(Immutable)(v)); + let M::Box>>{ f1, f2 } = Container::get>>>(Borrow(Immutable)(v)); Container::put>>>(Borrow(Mutable)(v), pack M::Box>>(Deref(Borrow(Immutable)(f1)), f2)); f1 } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_threaded_unpack_assign.exp b/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_threaded_unpack_assign.exp index 85dc36f23ede4..0638a9144b677 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_threaded_unpack_assign.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/type_variable_join_threaded_unpack_assign.exp @@ -29,7 +29,7 @@ module 0x2::M { let f1: u64; { let f2: u64; - M::Box{ f1: f1: u64, f2: f2: u64 }: M::Box = Container::get>(Borrow(Immutable)(v)); + M::Box{ f1, f2 } = Container::get>(Borrow(Immutable)(v)); f2; Container::put>(Borrow(Mutable)(v), pack M::Box(0, 0)); f1 @@ -44,7 +44,7 @@ module 0x2::M { let f1: M::Box>; { let f2: M::Box>; - M::Box>>{ f1: f1: M::Box>, f2: f2: M::Box> }: M::Box>> = Container::get>>>(Borrow(Immutable)(v)); + M::Box>>{ f1, f2 } = Container::get>>>(Borrow(Immutable)(v)); Container::put>>>(Borrow(Mutable)(v), pack M::Box>>(Deref(Borrow(Immutable)(f1)), f2)); f1 } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/unary_not.exp b/third_party/move/move-compiler-v2/tests/checking/typing/unary_not.exp index 25bc49cbbf818..da126c647eb2c 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/unary_not.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/unary_not.exp @@ -11,7 +11,7 @@ module 0x8675309::M { Not(Move(x)); Not(select M::R.f(r)); { - let M::R{ f: _ }: M::R = r; + let M::R{ f: _ } = r; Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/unused_local.exp b/third_party/move/move-compiler-v2/tests/checking/typing/unused_local.exp index 49b636efbf57e..0e221c884baf1 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/unused_local.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/unused_local.exp @@ -74,7 +74,7 @@ module 0x8675309::M { } private fun t2() { { - let M::S{ f: f: u64, g: g: bool }: M::S; + let M::S{ f, g }; Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/use_local.exp b/third_party/move/move-compiler-v2/tests/checking/typing/use_local.exp index 5cc996e832f89..d211b57c21a2e 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/use_local.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/use_local.exp @@ -13,7 +13,7 @@ module 0x8675309::M { let r: M::R = pack M::R(false); 0; s; - M::R{ dummy_field: _ }: M::R = r; + M::R{ dummy_field: _ } = r; Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/v1-commands/pop_weird.exp b/third_party/move/move-compiler-v2/tests/checking/typing/v1-commands/pop_weird.exp index b79b50668a2bd..9a62cda269e10 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/v1-commands/pop_weird.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/v1-commands/pop_weird.exp @@ -6,7 +6,7 @@ error: the left-hand side has 2 items but the right-hand side provided 0 13 │ (_, _) = (); │ ^^^^^^ -error: the left-hand side has 1 item but the right-hand side provided 0 +error: tuple type `()` is not allowed as a type argument ┌─ tests/checking/typing/v1-commands/pop_weird.move:14:9 │ 14 │ (_) = (); diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/v1-commands/unpack_extra_binding.exp b/third_party/move/move-compiler-v2/tests/checking/typing/v1-commands/unpack_extra_binding.exp index a528311281808..97786b5bd24ad 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/v1-commands/unpack_extra_binding.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/v1-commands/unpack_extra_binding.exp @@ -1,6 +1,6 @@ Diagnostics: -error: field `b` not declared in struct `Test::T` +error: field `b` not declared in `Test::T` ┌─ tests/checking/typing/v1-commands/unpack_extra_binding.move:11:23 │ 11 │ let T { i, x, b: flag } = t; diff --git a/third_party/move/move-compiler-v2/tests/checking/typing/v1-commands/unpack_missing_binding.exp b/third_party/move/move-compiler-v2/tests/checking/typing/v1-commands/unpack_missing_binding.exp index 003300161680d..4504d9a106fc9 100644 --- a/third_party/move/move-compiler-v2/tests/checking/typing/v1-commands/unpack_missing_binding.exp +++ b/third_party/move/move-compiler-v2/tests/checking/typing/v1-commands/unpack_missing_binding.exp @@ -1,6 +1,6 @@ Diagnostics: -error: missing fields `y` +error: missing field `y` ┌─ tests/checking/typing/v1-commands/unpack_missing_binding.move:11:13 │ 11 │ let T { i, x, b: flag } = t; diff --git a/third_party/move/move-compiler-v2/tests/checking/variants/variants_check_duplicate_variant_err.exp b/third_party/move/move-compiler-v2/tests/checking/variants/variants_check_duplicate_variant_err.exp new file mode 100644 index 0000000000000..c881a619e805c --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/variants/variants_check_duplicate_variant_err.exp @@ -0,0 +1,10 @@ + +Diagnostics: +error: duplicate declaration, item, or annotation + ┌─ tests/checking/variants/variants_check_duplicate_variant_err.move:7:9 + │ +4 │ RGB{red: u64, green: u64, blue: u64}, + │ ------------------------------------ Variant previously defined here + · +7 │ RGB{red: u64, green: u64, blue: u64}, + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Duplicate definition for variant 'RGB' diff --git a/third_party/move/move-compiler-v2/tests/checking/variants/variants_check_duplicate_variant_err.move b/third_party/move/move-compiler-v2/tests/checking/variants/variants_check_duplicate_variant_err.move new file mode 100644 index 0000000000000..e015ff9635a45 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/variants/variants_check_duplicate_variant_err.move @@ -0,0 +1,9 @@ +module 0x815::m { + + enum ColorDuplicateVariant { + RGB{red: u64, green: u64, blue: u64}, + Red, + Blue, + RGB{red: u64, green: u64, blue: u64}, + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/variants/variants_check_err.exp b/third_party/move/move-compiler-v2/tests/checking/variants/variants_check_err.exp new file mode 100644 index 0000000000000..9f045298f286f --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/variants/variants_check_err.exp @@ -0,0 +1,45 @@ + +Diagnostics: +error: variant `Rgb` not declared in `m::Color` + ┌─ tests/checking/variants/variants_check_err.move:15:13 + │ +15 │ Color::Rgb{red, green, blue} => false, + │ ^^^^^^^^^^ + +error: variants not allowed in this context + ┌─ tests/checking/variants/variants_check_err.move:21:41 + │ +21 │ fun missplaced_variant(self: Color::Red): bool { + │ ^^^ + +error: variants not allowed in this context + ┌─ tests/checking/variants/variants_check_err.move:22:39 + │ +22 │ 0x815::m::missplaced_variant::Red(); + │ ^^^ + +error: variants not allowed in this context + ┌─ tests/checking/variants/variants_check_err.move:26:36 + │ +26 │ fun missing_field(self: Color::Red): bool { + │ ^^^ + +error: missing field `blue` + ┌─ tests/checking/variants/variants_check_err.move:28:13 + │ +28 │ Color::RGB{red, green} => false, + │ ^^^^^^^^^^^^^^^^^^^^^^ + +error: field `black` not declared in `m::Color` + ┌─ tests/checking/variants/variants_check_err.move:34:42 + │ +34 │ Color::RGB{red, green, blue, black} => false, + │ ^^^^^ + +error: field `red` not declared in all variants of `Color` + ┌─ tests/checking/variants/variants_check_err.move:39:9 + │ +39 │ self.red + │ ^^^^ + │ + = field must be declared in all variants of `Color` to be accessible without match expression diff --git a/third_party/move/move-compiler-v2/tests/checking/variants/variants_check_err.move b/third_party/move/move-compiler-v2/tests/checking/variants/variants_check_err.move new file mode 100644 index 0000000000000..e9bc1e87ff6f0 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/variants/variants_check_err.move @@ -0,0 +1,41 @@ +module 0x815::m { + + enum Color { + RGB{red: u64, green: u64, blue: u64}, + Red, + Blue, + } + + struct NoColor { + red: u64 + } + + fun misspelled_variant(self: Color): bool { + match (self) { + Color::Rgb{red, green, blue} => false, + Color::Red => true, + Color::Blue => false, + } + } + + fun missplaced_variant(self: Color::Red): bool { + 0x815::m::missplaced_variant::Red(); + false + } + + fun missing_field(self: Color::Red): bool { + match (self) { + Color::RGB{red, green} => false, + } + } + + fun extra_field(self: Color): bool { + match (self) { + Color::RGB{red, green, blue, black} => false, + } + } + + fun select_variant_field(self: Color): u64 { + self.red + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/variants/variants_check_wrongly_named_variant_err.exp b/third_party/move/move-compiler-v2/tests/checking/variants/variants_check_wrongly_named_variant_err.exp new file mode 100644 index 0000000000000..2fff281b5257b --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/variants/variants_check_wrongly_named_variant_err.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: invalid name + ┌─ tests/checking/variants/variants_check_wrongly_named_variant_err.move:4:9 + │ +4 │ rgb{red: u64, green: u64, blue: u64}, + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Invalid variant name 'rgb'. variant names must start with 'A'..'Z' diff --git a/third_party/move/move-compiler-v2/tests/checking/variants/variants_check_wrongly_named_variant_err.move b/third_party/move/move-compiler-v2/tests/checking/variants/variants_check_wrongly_named_variant_err.move new file mode 100644 index 0000000000000..9f71495d329d7 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/variants/variants_check_wrongly_named_variant_err.move @@ -0,0 +1,8 @@ +module 0x815::m { + + enum ColorDuplicateVariant { + rgb{red: u64, green: u64, blue: u64}, + Red, + Blue, + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/variants/variants_ok.exp b/third_party/move/move-compiler-v2/tests/checking/variants/variants_ok.exp new file mode 100644 index 0000000000000..e974c8d0aee11 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/variants/variants_ok.exp @@ -0,0 +1,207 @@ +// -- Model dump before bytecode pipeline +module 0x815::m { + use 0x815::m; // resolved as: 0x815::m + enum Color { + RGB { + red: u64, + green: u64, + blue: u64, + } + Red, + Blue, + } + enum ColorUsesBlockNoComma { + RGB { + red: u64, + green: u64, + blue: u64, + } + Red, + Blue, + } + enum CommonFields { + Foo { + x: u64, + y: u8, + } + Bar { + x: u64, + z: u32, + } + } + private fun t1(self: m::Color): bool { + match (self) { + m::Color::RGB{ red, green, blue } => { + Gt(Add(Add(red, green), blue), 0) + } + m::Color::Red{ } => { + true + } + m::Color::Blue{ } => { + false + } + } + + } + private fun t1_address_qualified(self: m::Color): bool { + match (self) { + m::Color::RGB{ red, green, blue } => { + Gt(Add(Add(red, green), blue), 0) + } + m::Color::Red{ } => { + true + } + m::Color::Blue{ } => { + false + } + } + + } + private fun t1_field_named(self: m::Color): bool { + match (self) { + m::Color::RGB{ red: r, green: g, blue } => { + Gt(Add(Add(r, g), blue), 0) + } + m::Color::Red{ } => { + true + } + m::Color::Blue{ } => { + false + } + } + + } + private fun t1_module_qualified(self: m::Color): bool { + match (self) { + m::Color::RGB{ red, green, blue } => { + Gt(Add(Add(red, green), blue), 0) + } + m::Color::Red{ } => { + true + } + m::Color::Blue{ } => { + false + } + } + + } + private fun t1_uses_block(self: m::Color): bool { + match (self) { + m::Color::RGB{ red, green, blue } => { + Gt(Add(Add(red, green), blue), 0) + } + m::Color::Red{ } => { + true + } + m::Color::Blue{ } => { + false + } + } + + } + private fun t1_uses_block_no_comma(self: m::Color): bool { + match (self) { + m::Color::RGB{ red, green, blue } => { + Gt(Add(Add(red, green), blue), 0) + } + m::Color::Red{ } => { + true + } + m::Color::Blue{ } => { + false + } + } + + } + private fun t2(self: m::Color): bool { + match (self) { + m::Color::RGB{ red, green, blue } => { + Gt(Add(Add(red, green), blue), 0) + } + _: m::Color => { + true + } + } + + } + private fun t3(self: m::Color): bool { + match (Borrow(Immutable)(self)) { + m::Color::RGB{ red, green, blue } => { + Gt(Add(Add(Deref(red), Deref(green)), Deref(blue)), 0) + } + _: &m::Color => { + true + } + } + + } + private fun t4(self: m::Color): m::Color { + match (Borrow(Mutable)(self)) { + m::Color::RGB{ red, green: _, blue: _ } => { + red = 2 + } + _: &mut m::Color => { + Tuple() + } + } + ; + self + } + private fun t5_freeze(self: m::Color): u64 { + { + let x: u64 = 1; + { + let r: &u64 = match (Borrow(Mutable)(self)) { + m::Color::Red{ } => { + Borrow(Immutable)(x) + } + m::Color::Blue{ } => { + Freeze(false)(Borrow(Mutable)(x)) + } + _: &mut m::Color => { + Freeze(false)(Borrow(Mutable)(x)) + } + } + ; + Deref(r) + } + } + } + private fun t6_construct(self: m::Color): m::Color { + match (self) { + m::Color::RGB{ red, green, blue } => { + pack m::Color::RGB(Add(red, 1), Sub(green, 1), blue) + } + _: m::Color => { + self + } + } + + } + private fun t7_let_unpack(self: m::Color): u64 { + { + let m::Color::RGB{ red, green, blue } = self; + Add(Add(red, green), blue) + } + } + private fun t8_unqualified_variant(self: m::Color): bool { + match (self) { + m::Color::RGB{ red, green, blue } => { + And(Neq(red, green), Neq(green, blue)) + } + m::Color::Red{ } => { + true + } + m::Color::Blue{ } => { + false + } + } + + } + private fun t9_common_field(self: m::CommonFields): u64 { + select m::CommonFields.x(self) + } + private fun t9_common_field_ref(self: &m::CommonFields): &u64 { + Borrow(Immutable)(select m::CommonFields.x<&m::CommonFields>(self)) + } +} // end 0x815::m diff --git a/third_party/move/move-compiler-v2/tests/checking/variants/variants_ok.move b/third_party/move/move-compiler-v2/tests/checking/variants/variants_ok.move new file mode 100644 index 0000000000000..126806ec9fdbc --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/variants/variants_ok.move @@ -0,0 +1,129 @@ +module 0x815::m { + use 0x815::m; + + enum Color { + RGB{red: u64, green: u64, blue: u64}, + Red, + Blue, + } + + enum ColorUsesBlockNoComma { + RGB{red: u64, green: u64, blue: u64} + Red, + Blue, + } + + enum CommonFields { + Foo{x: u64, y: u8}, + Bar{x: u64, z: u32} + } + + fun t1(self: Color): bool { + match (self) { + Color::RGB{red, green, blue} => red + green + blue > 0, + Color::Red => true, + Color::Blue => false, + } + } + + fun t1_field_named(self: Color): bool { + match (self) { + Color::RGB{red: r, green: g, blue} => r + g + blue > 0, + Color::Red => true, + Color::Blue => false, + } + } + + fun t1_uses_block(self: Color): bool { + match (self) { + Color::RGB{red, green, blue} => { red + green + blue > 0 }, + Color::Red => true, + Color::Blue => false, + } + } + + fun t1_uses_block_no_comma(self: Color): bool { + match (self) { + Color::RGB{red, green, blue} => { red + green + blue > 0 } + Color::Red => true, + Color::Blue => false, + } + } + + fun t1_module_qualified(self: m::Color): bool { + match (self) { + m::Color::RGB{red, green, blue} => red + green + blue > 0, + m::Color::Red => true, + m::Color::Blue => false, + } + } + + fun t1_address_qualified(self: m::Color): bool { + match (self) { + 0x815::m::Color::RGB{red, green, blue} => red + green + blue > 0, + 0x815::m::Color::Red => true, + Color::Blue => false, + } + } + + fun t2(self: Color): bool { + match (self) { + Color::RGB{red, green, blue} => red + green + blue > 0, + _ => true, + } + } + + fun t3(self: Color): bool { + match (&self) { + Color::RGB{red, green, blue} => *red + *green + *blue > 0, + _ => true, + } + } + + fun t4(self: Color): Color { + match (&mut self) { + Color::RGB{red, green: _, blue: _} => *red = 2, + _ => {}, + }; + self + } + + fun t5_freeze(self: Color): u64 { + let x = 1; + let r = match (&mut self) { + Color::Red => &x, + Color::Blue => &mut x, + _ => &mut x, + }; + *r + } + + fun t6_construct(self: Color): Color { + match (self) { + Color::RGB{red, green, blue} => Color::RGB{red: red + 1, green: green - 1, blue}, + _ => self + } + } + + fun t7_let_unpack(self: Color): u64 { + // This is allowed by the checker -- bytecode generator will decide if its valid + let Color::RGB{red, green, blue} = self; + red + green + blue + } + + fun t8_unqualified_variant(self: Color): bool { + match (self) { + RGB{red, green, blue} => red != green && green != blue, + Red => true, + Blue => false, + } + } + + fun t9_common_field(self: CommonFields): u64 { + self.x + } + + fun t9_common_field_ref(self: &CommonFields): &u64 { + &self.x + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/variants/variants_parse_err1.exp b/third_party/move/move-compiler-v2/tests/checking/variants/variants_parse_err1.exp new file mode 100644 index 0000000000000..5d8542d6650d6 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/variants/variants_parse_err1.exp @@ -0,0 +1,10 @@ + +Diagnostics: +error: unexpected token + ┌─ tests/checking/variants/variants_parse_err1.move:7:9 + │ +7 │ Blue, + │ ^^^^ + │ │ + │ Unexpected 'Blue' + │ Expected ',' diff --git a/third_party/move/move-compiler-v2/tests/checking/variants/variants_parse_err1.move b/third_party/move/move-compiler-v2/tests/checking/variants/variants_parse_err1.move new file mode 100644 index 0000000000000..a083d82ec0db2 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/variants/variants_parse_err1.move @@ -0,0 +1,9 @@ +module 0x815::m { + use 0x815::m; + + enum ColorMissingComma { + RGB{red: u64, green: u64, blue: u64} + Red // , missing + Blue, + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/variants/variants_parse_err2.exp b/third_party/move/move-compiler-v2/tests/checking/variants/variants_parse_err2.exp new file mode 100644 index 0000000000000..726bcf634ceb8 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/variants/variants_parse_err2.exp @@ -0,0 +1,10 @@ + +Diagnostics: +error: unexpected token + ┌─ tests/checking/variants/variants_parse_err2.move:5:12 + │ +5 │ red: u64 + │ ^ + │ │ + │ Unexpected ':' + │ Expected ',' diff --git a/third_party/move/move-compiler-v2/tests/checking/variants/variants_parse_err2.move b/third_party/move/move-compiler-v2/tests/checking/variants/variants_parse_err2.move new file mode 100644 index 0000000000000..ffdbca30e6184 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/variants/variants_parse_err2.move @@ -0,0 +1,7 @@ +module 0x815::m { + use 0x815::m; + + enum ColorMissingVariants { + red: u64 + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/variants/variants_parse_err3.exp b/third_party/move/move-compiler-v2/tests/checking/variants/variants_parse_err3.exp new file mode 100644 index 0000000000000..abc3bf80b42ce --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/variants/variants_parse_err3.exp @@ -0,0 +1,10 @@ + +Diagnostics: +error: unexpected token + ┌─ tests/checking/variants/variants_parse_err3.move:13:13 + │ +13 │ Color::Blue => false, + │ ^^^^^ + │ │ + │ Unexpected 'Color' + │ Expected ',' diff --git a/third_party/move/move-compiler-v2/tests/checking/variants/variants_parse_err3.move b/third_party/move/move-compiler-v2/tests/checking/variants/variants_parse_err3.move new file mode 100644 index 0000000000000..dd3bfeb39d4cc --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/variants/variants_parse_err3.move @@ -0,0 +1,17 @@ +module 0x815::m { + use 0x815::m; + + enum Color { + RGB{red: u64, green: u64, blue: u64}, + Red, + Blue, + } + + fun match_no_comma(self: Color): bool { + match (self) { + Color::Red => true + Color::Blue => false, + } + } + +} diff --git a/third_party/move/move-compiler-v2/tests/checking/variants/variants_parse_err4.exp b/third_party/move/move-compiler-v2/tests/checking/variants/variants_parse_err4.exp new file mode 100644 index 0000000000000..4ef2b2eaa3e03 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/variants/variants_parse_err4.exp @@ -0,0 +1,10 @@ + +Diagnostics: +error: unexpected token + ┌─ tests/checking/variants/variants_parse_err4.move:11:15 + │ +11 │ match self { + │ ^^^^ + │ │ + │ Unexpected 'self' + │ Expected '(' diff --git a/third_party/move/move-compiler-v2/tests/checking/variants/variants_parse_err4.move b/third_party/move/move-compiler-v2/tests/checking/variants/variants_parse_err4.move new file mode 100644 index 0000000000000..8e38602e89129 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/variants/variants_parse_err4.move @@ -0,0 +1,17 @@ +module 0x815::m { + use 0x815::m; + + enum Color { + RGB{red: u64, green: u64, blue: u64}, + Red, + Blue, + } + + fun match_no_parenthesis(self: Color): bool { + match self { + Color::Red => true + Color::Blue => false, + } + } + +} diff --git a/third_party/move/move-compiler-v2/tests/lambda-lifting/pattern.exp b/third_party/move/move-compiler-v2/tests/lambda-lifting/pattern.exp index ef4ec3980fdd8..c61dde92a484d 100644 --- a/third_party/move/move-compiler-v2/tests/lambda-lifting/pattern.exp +++ b/third_party/move/move-compiler-v2/tests/lambda-lifting/pattern.exp @@ -7,7 +7,7 @@ module 0xcafe::m { (f)(s, x) } private fun pattern(s: m::S,x: u64): u64 { - m::consume(s, x, |(m::S{ x: x: u64 }, _y: u64): (m::S, u64)| { + m::consume(s, x, |(m::S{ x }, _y: u64): (m::S, u64)| { let y: u64 = x; Add(x, y) }) @@ -28,7 +28,7 @@ module 0xcafe::m { } private fun pattern$lambda$1(param$0: m::S,_y: u64): u64 { { - let m::S{ x: x: u64 }: m::S = param$0; + let m::S{ x } = param$0; { let y: u64 = x; Add(x, y) diff --git a/third_party/move/move-compiler-v2/tests/simplifier-elimination/assign_unpack_references.exp b/third_party/move/move-compiler-v2/tests/simplifier-elimination/assign_unpack_references.exp index b8c218e6fa304..338b267835624 100644 --- a/third_party/move/move-compiler-v2/tests/simplifier-elimination/assign_unpack_references.exp +++ b/third_party/move/move-compiler-v2/tests/simplifier-elimination/assign_unpack_references.exp @@ -12,7 +12,7 @@ module 0x8675309::M { let f: u64; { let s2: M::S; - M::R{ s1: M::S{ f: f: u64 }, s2: s2: M::S }: M::R = pack M::R(pack M::S(0), pack M::S(1)); + M::R{ s1: M::S{ f }, s2 } = pack M::R(pack M::S(0), pack M::S(1)); f; s2; f: u64 = 0; @@ -28,7 +28,7 @@ module 0x8675309::M { let f: &u64; { let s2: &M::S; - M::R{ s1: M::S{ f: f: &u64 }, s2: s2: &M::S }: &M::R = Borrow(Immutable)(pack M::R(pack M::S(0), pack M::S(1))); + M::R{ s1: M::S{ f }, s2 } = Borrow(Immutable)(pack M::R(pack M::S(0), pack M::S(1))); f; s2; f: &u64 = Borrow(Immutable)(0); @@ -44,7 +44,7 @@ module 0x8675309::M { let f: &mut u64; { let s2: &mut M::S; - M::R{ s1: M::S{ f: f: &mut u64 }, s2: s2: &mut M::S }: &mut M::R = Borrow(Mutable)(pack M::R(pack M::S(0), pack M::S(1))); + M::R{ s1: M::S{ f }, s2 } = Borrow(Mutable)(pack M::R(pack M::S(0), pack M::S(1))); f; s2; f: &mut u64 = Borrow(Mutable)(0); diff --git a/third_party/move/move-compiler-v2/tests/simplifier-elimination/binary_add.exp b/third_party/move/move-compiler-v2/tests/simplifier-elimination/binary_add.exp index 4d22f28e939cd..2cf7745cb0aa4 100644 --- a/third_party/move/move-compiler-v2/tests/simplifier-elimination/binary_add.exp +++ b/third_party/move/move-compiler-v2/tests/simplifier-elimination/binary_add.exp @@ -58,7 +58,7 @@ module 0x8675309::M { Add(select M::R.f(r), select M::R.f(r)); Add(Add(Add(1, select M::R.f(r)), select M::R.f(r)), 0); { - let M::R{ f: _ }: M::R = r; + let M::R{ f: _ } = r; Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/simplifier-elimination/bind_with_type_annot.exp b/third_party/move/move-compiler-v2/tests/simplifier-elimination/bind_with_type_annot.exp index bd47ab1047bbe..0ddea02275090 100644 --- a/third_party/move/move-compiler-v2/tests/simplifier-elimination/bind_with_type_annot.exp +++ b/third_party/move/move-compiler-v2/tests/simplifier-elimination/bind_with_type_annot.exp @@ -31,7 +31,7 @@ module 0x8675309::M { } private fun t0() { { - let (x: u64, b: bool, M::R{ f: f: u64 }): (u64, bool, M::R) = Tuple(0, false, pack M::R(0)); + let (x: u64, b: bool, M::R{ f }): (u64, bool, M::R) = Tuple(0, false, pack M::R(0)); Tuple() } } diff --git a/third_party/move/move-compiler-v2/tests/unit_test/notest/cross_module_members_non_test_function.exp b/third_party/move/move-compiler-v2/tests/unit_test/notest/cross_module_members_non_test_function.exp index c0e6aba44b631..5b42e54a2628a 100644 --- a/third_party/move/move-compiler-v2/tests/unit_test/notest/cross_module_members_non_test_function.exp +++ b/third_party/move/move-compiler-v2/tests/unit_test/notest/cross_module_members_non_test_function.exp @@ -4,4 +4,4 @@ error: unbound module ┌─ tests/unit_test/notest/cross_module_members_non_test_function.move:24:9 │ 24 │ A::build_foo() - │ ^ Unbound module alias 'A' + │ ^ Unbound module or type alias 'A' diff --git a/third_party/move/move-compiler-v2/tests/unit_test/notest/cross_module_test_only_module.exp b/third_party/move/move-compiler-v2/tests/unit_test/notest/cross_module_test_only_module.exp index 9921e6e56d93d..ea783b0a7336c 100644 --- a/third_party/move/move-compiler-v2/tests/unit_test/notest/cross_module_test_only_module.exp +++ b/third_party/move/move-compiler-v2/tests/unit_test/notest/cross_module_test_only_module.exp @@ -10,4 +10,4 @@ error: unbound module ┌─ tests/unit_test/notest/cross_module_test_only_module.move:13:9 │ 13 │ M::foo() - │ ^ Unbound module alias 'M' + │ ^ Unbound module or type alias 'M' diff --git a/third_party/move/move-compiler/src/attr_derivation/async_deriver.rs b/third_party/move/move-compiler/src/attr_derivation/async_deriver.rs index c565d56e3d90e..e68ec07e39f10 100644 --- a/third_party/move/move-compiler/src/attr_derivation/async_deriver.rs +++ b/third_party/move/move-compiler/src/attr_derivation/async_deriver.rs @@ -10,7 +10,7 @@ use crate::{ diag, parser::ast::{ Definition, Exp, Exp_, Field, Function, FunctionName, LeadingNameAccess_, ModuleDefinition, - ModuleMember, NameAccessChain_, StructFields, StructName, Type, Type_, Visibility, + ModuleMember, NameAccessChain_, StructLayout, StructName, Type, Type_, Visibility, }, shared::{CompilationEnv, NamedAddressMap}, }; @@ -164,7 +164,7 @@ fn derive_module_for_async( new_structs.push(new_struct( loc, StructName(sp(loc, Symbol::from(struct_name))), - StructFields::Defined(fields), + StructLayout::Singleton(fields), )); } } diff --git a/third_party/move/move-compiler/src/attr_derivation/mod.rs b/third_party/move/move-compiler/src/attr_derivation/mod.rs index 75bb8f6627970..b007e2356d1a1 100644 --- a/third_party/move/move-compiler/src/attr_derivation/mod.rs +++ b/third_party/move/move-compiler/src/attr_derivation/mod.rs @@ -10,7 +10,7 @@ use crate::{ parser::ast::{ Attribute, AttributeValue, Attribute_, Attributes, CallKind, Definition, Exp, Exp_, Function, FunctionBody_, FunctionName, FunctionSignature, LeadingNameAccess_, - NameAccessChain, NameAccessChain_, StructDefinition, StructFields, StructName, Type, Type_, + NameAccessChain, NameAccessChain_, StructDefinition, StructLayout, StructName, Type, Type_, Value_, Var, Visibility, }, shared::{ @@ -163,7 +163,7 @@ pub(crate) fn new_fun( } /// Helper to create a new struct declaration. -pub(crate) fn new_struct(loc: Loc, name: StructName, fields: StructFields) -> StructDefinition { +pub(crate) fn new_struct(loc: Loc, name: StructName, layout: StructLayout) -> StructDefinition { StructDefinition { attributes: vec![sp( // #[event] @@ -174,7 +174,7 @@ pub(crate) fn new_struct(loc: Loc, name: StructName, fields: StructFields) -> St abilities: vec![], name, type_parameters: vec![], - fields, + layout, } } diff --git a/third_party/move/move-compiler/src/command_line/mod.rs b/third_party/move/move-compiler/src/command_line/mod.rs index c5fe374abe3b3..4439856d1ab52 100644 --- a/third_party/move/move-compiler/src/command_line/mod.rs +++ b/third_party/move/move-compiler/src/command_line/mod.rs @@ -64,7 +64,8 @@ pub const WARN_OF_DEPRECATION_USE_IN_APTOS_LIBS_FLAG: &str = "Wdeprecation-aptos pub const WARN_UNUSED_FLAG: &str = "Wunused"; -pub const V2_FLAG: &str = "v2"; +pub const LANG_V2_FLAG: &str = "lang_v2"; +pub const COMPILER_V2_FLAG: &str = "compiler_v2"; // Flag to dump a stacktrace on a compiler error, for users who like // to keep RUST_BACKTRACE always enabled. diff --git a/third_party/move/move-compiler/src/diagnostics/codes.rs b/third_party/move/move-compiler/src/diagnostics/codes.rs index 8d6c41d33eb69..3b4b7bdee649d 100644 --- a/third_party/move/move-compiler/src/diagnostics/codes.rs +++ b/third_party/move/move-compiler/src/diagnostics/codes.rs @@ -116,6 +116,7 @@ codes!( InvalidSpecBlockMember: { msg: "invalid spec block member", severity: NonblockingError }, InvalidAccessSpecifier: { msg: "invalid access specifier", severity: NonblockingError }, UnsupportedLanguageItem: { msg: "unsupported language construct", severity: BlockingError }, + InvalidVariantAccess: { msg: "invalid variant name", severity: BlockingError }, ], // errors for any rules around declaration items Declarations: [ diff --git a/third_party/move/move-compiler/src/expansion/ast.rs b/third_party/move/move-compiler/src/expansion/ast.rs index 865148c7155e8..eb4a2457e659d 100644 --- a/third_party/move/move-compiler/src/expansion/ast.rs +++ b/third_party/move/move-compiler/src/expansion/ast.rs @@ -5,7 +5,8 @@ use crate::{ parser::ast::{ self as P, Ability, Ability_, BinOp, CallKind, ConstantName, Field, FunctionName, - ModuleName, QuantKind, SpecApplyPattern, StructName, UnaryOp, UseDecl, Var, ENTRY_MODIFIER, + ModuleName, QuantKind, SpecApplyPattern, StructName, UnaryOp, UseDecl, Var, VariantName, + ENTRY_MODIFIER, }, shared::{ ast_debug::*, @@ -165,15 +166,24 @@ pub struct StructDefinition { pub loc: Loc, pub abilities: AbilitySet, pub type_parameters: Vec, - pub fields: StructFields, + pub layout: StructLayout, } #[derive(Debug, Clone, PartialEq)] -pub enum StructFields { - Defined(Fields), +pub enum StructLayout { + Singleton(Fields), + Variants(Vec), Native(Loc), } +#[derive(Debug, PartialEq, Clone)] +pub struct StructVariant { + pub attributes: Attributes, + pub loc: Loc, + pub name: VariantName, + pub fields: Fields, +} + //************************************************************************************************** // Functions //************************************************************************************************** @@ -363,7 +373,8 @@ pub struct AbilitySet(UniqueSet); #[allow(clippy::large_enum_variant)] pub enum ModuleAccess_ { Name(Name), - ModuleAccess(ModuleIdent, Name), + // ModuleAccess(module_ident, member_ident, optional_variant_ident) + ModuleAccess(ModuleIdent, Name, Option), } pub type ModuleAccess = Spanned; @@ -443,6 +454,7 @@ pub enum Exp_ { Vector(Loc, Option>, Spanned>), IfElse(Box, Box, Box), + Match(Box, Vec, Exp)>>), While(Box, Box), Loop(Box), Block(Sequence), @@ -818,7 +830,17 @@ impl fmt::Display for ModuleAccess_ { use ModuleAccess_::*; match self { Name(n) => write!(f, "{}", n), - ModuleAccess(m, n) => write!(f, "{}::{}", m, n), + ModuleAccess(m, n, opt_v) => write!( + f, + "{}::{}{}", + m, + n, + if let Some(v) = opt_v { + format!("::{}", v) + } else { + "".to_string() + } + ), } } } @@ -1046,20 +1068,20 @@ impl AstDebug for (StructName, &StructDefinition) { loc: _loc, abilities, type_parameters, - fields, + layout: fields, }, ) = self; attributes.ast_debug(w); - if let StructFields::Native(_) = fields { + if let StructLayout::Native(_) = fields { w.write("native "); } w.write(&format!("struct {}", name)); type_parameters.ast_debug(w); ability_modifiers_ast_debug(w, abilities); - if let StructFields::Defined(fields) = fields { + if let StructLayout::Singleton(fields) = fields { w.block(|w| { w.list(fields, ",", |w, (_, f, idx_st)| { let (idx, st) = idx_st; @@ -1443,7 +1465,16 @@ impl AstDebug for ModuleAccess_ { fn ast_debug(&self, w: &mut AstWriter) { w.write(&match self { ModuleAccess_::Name(n) => format!("{}", n), - ModuleAccess_::ModuleAccess(m, n) => format!("{}::{}", m, n), + ModuleAccess_::ModuleAccess(m, n, opt_v) => format!( + "{}::{}{}", + m, + n, + if let Some(v) = opt_v { + format!("::{}", v) + } else { + "".to_string() + } + ), }) } } @@ -1569,6 +1600,20 @@ impl AstDebug for Exp_ { w.write("loop "); e.ast_debug(w); }, + E::Match(e, arms) => { + w.write("match ("); + e.ast_debug(w); + w.write(") {"); + for arm in arms { + arm.value.0.ast_debug(w); + if let Some(cond) = &arm.value.1 { + w.write(" if "); + cond.ast_debug(w); + } + w.write(" => "); + arm.value.2.ast_debug(w) + } + }, E::Block(seq) => w.block(|w| seq.ast_debug(w)), E::Lambda(sp!(_, bs), e) => { w.write("|"); 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 f38178875ace7..0e48f69bd01b6 100644 --- a/third_party/move/move-compiler/src/expansion/dependency_ordering.rs +++ b/third_party/move/move-compiler/src/expansion/dependency_ordering.rs @@ -335,7 +335,7 @@ fn function_acquires(context: &mut Context, acqs: &[E::ModuleAccess]) { //************************************************************************************************** fn struct_def(context: &mut Context, sdef: &E::StructDefinition) { - if let E::StructFields::Defined(fields) = &sdef.fields { + if let E::StructLayout::Singleton(fields) = &sdef.layout { fields.iter().for_each(|(_, _, (_, bt))| type_(context, bt)); } } @@ -345,7 +345,7 @@ fn struct_def(context: &mut Context, sdef: &E::StructDefinition) { //************************************************************************************************** fn module_access(context: &mut Context, sp!(loc, ma_): &E::ModuleAccess) { - if let E::ModuleAccess_::ModuleAccess(m, _) = ma_ { + if let E::ModuleAccess_::ModuleAccess(m, _, _) = ma_ { context.add_usage(*m, *loc) } } @@ -460,6 +460,17 @@ fn exp(context: &mut Context, sp!(_loc, e_): &E::Exp) { exp(context, ef) }, + E::Match(ed, arms) => { + exp(context, ed); + for arm in arms { + lvalues(context, &arm.value.0.value); + if let Some(e) = &arm.value.1 { + exp(context, e) + } + exp(context, &arm.value.2) + } + }, + E::BinopExp(e1, _, e2) | E::Mutate(e1, e2) | E::While(e1, e2) | E::Index(e1, e2) => { exp(context, e1); exp(context, e2) @@ -568,7 +579,7 @@ fn spec_block_member(context: &mut Context, sp!(_, sbm_): &E::SpecBlockMember) { Some(E::PragmaValue::Literal(_)) => (), Some(E::PragmaValue::Ident(maccess)) => match &maccess.value { E::ModuleAccess_::Name(_) => (), - E::ModuleAccess_::ModuleAccess(mident, _) => { + E::ModuleAccess_::ModuleAccess(mident, _, _) => { context.add_friend(*mident, maccess.loc); }, }, diff --git a/third_party/move/move-compiler/src/expansion/translate.rs b/third_party/move/move-compiler/src/expansion/translate.rs index 8449077eaf5f5..72556b0b65583 100644 --- a/third_party/move/move-compiler/src/expansion/translate.rs +++ b/third_party/move/move-compiler/src/expansion/translate.rs @@ -9,7 +9,7 @@ use crate::{ diagnostics::{codes::DeprecatedItem, Diagnostic}, expansion::{ aliases::{AliasMap, AliasSet}, - ast::{self as E, Address, Fields, ModuleIdent, ModuleIdent_, SpecId}, + ast::{self as E, Address, Fields, ModuleAccess_, ModuleIdent, ModuleIdent_, SpecId}, byte_string, hex_string, }, parser::ast::{ @@ -1395,7 +1395,7 @@ fn struct_def_( name, abilities: abilities_vec, type_parameters: pty_params, - fields: pfields, + layout: pfields, } = pstruct; let was_in_deprecated_code = context.enter_possibly_deprecated_member(&name.0); let attributes = flatten_attributes(context, AttributePosition::Struct, attributes); @@ -1404,46 +1404,87 @@ fn struct_def_( .aliases .shadow_for_type_parameters(type_parameters.iter().map(|tp| &tp.name)); let abilities = ability_set(context, "modifier", abilities_vec); - let fields = struct_fields(context, &name, pfields); + let fields = struct_layout(context, &name, pfields); let sdef = E::StructDefinition { attributes, loc, abilities, type_parameters, - fields, + layout: fields, }; context.set_to_outer_scope(old_aliases); context.set_in_deprecated_code(was_in_deprecated_code); (name, sdef) } -fn struct_fields( +fn struct_layout( context: &mut Context, - sname: &StructName, - pfields: P::StructFields, -) -> E::StructFields { - let pfields_vec = match pfields { - P::StructFields::Native(loc) => return E::StructFields::Native(loc), - P::StructFields::Defined(v) => v, - }; + _sname: &StructName, + parsed_layout: P::StructLayout, +) -> E::StructLayout { + match parsed_layout { + P::StructLayout::Native(loc) => E::StructLayout::Native(loc), + P::StructLayout::Singleton(fields) => { + E::StructLayout::Singleton(struct_fields(context, fields)) + }, + P::StructLayout::Variants(variants) => { + let mut previous_variants = BTreeMap::new(); + E::StructLayout::Variants( + variants + .into_iter() + .map(|v| { + if !is_valid_struct_constant_or_schema_name(v.name.0.value.as_str()) { + let msg = format!( + "Invalid variant name '{}'. variant names must start with 'A'..'Z'", + v.name + ); + context + .env + .add_diag(diag!(Declarations::InvalidName, (v.loc, msg))); + } + if let Some(old_loc) = previous_variants.insert(v.name, v.loc) { + context.env.add_diag(diag!( + Declarations::DuplicateItem, + ( + v.loc, + format!("Duplicate definition for variant '{}'", v.name), + ), + (old_loc, "Variant previously defined here"), + )); + } + E::StructVariant { + attributes: flatten_attributes( + context, + AttributePosition::Struct, + v.attributes, + ), + loc: v.loc, + name: v.name, + fields: struct_fields(context, v.fields), + } + }) + .collect(), + ) + }, + } +} + +fn struct_fields(context: &mut Context, fields: Vec<(P::Field, P::Type)>) -> Fields { let mut field_map = UniqueMap::new(); - for (idx, (field, pt)) in pfields_vec.into_iter().enumerate() { + for (idx, (field, pt)) in fields.into_iter().enumerate() { let t = type_(context, pt); if let Err((field, old_loc)) = field_map.add(field, (idx, t)) { context.env.add_diag(diag!( Declarations::DuplicateItem, ( field.loc(), - format!( - "Duplicate definition for field '{}' in struct '{}'", - field, sname - ), + format!("Duplicate definition for field '{}'", field), ), (old_loc, "Field previously defined here"), )); } } - E::StructFields::Defined(field_map) + field_map } //************************************************************************************************** @@ -1558,7 +1599,7 @@ fn function_(context: &mut Context, pfunction: P::Function) -> (FunctionName, E: let attributes = flatten_attributes(context, AttributePosition::Function, pattributes); let visibility = visibility(pvisibility); let (old_aliases, signature) = function_signature(context, psignature); - let (acquires, access_specifiers) = if context.env.flags().v2() { + let (acquires, access_specifiers) = if context.env.flags().compiler_v2() { (vec![], access_specifier_list(context, access_specifiers)) } else { ( @@ -1607,7 +1648,7 @@ fn access_specifier_list_as_acquires( Syntax::InvalidAccessSpecifier, ( loc, - "compiler version 1 only supports simple 'acquires ' clauses" + "language version 1 only supports simple 'acquires ' clauses" .to_owned() ) )); @@ -1648,6 +1689,10 @@ fn access_specifier_list_as_acquires( && check_wildcard(context, second) && check_wildcard(context, third) }, + NameAccessChain_::Four(..) => { + invalid_variant_access(context, specifier.loc); + false + }, }; if ok { if let Some(maccess) = name_access_chain( @@ -1667,6 +1712,13 @@ fn access_specifier_list_as_acquires( acquires } +fn invalid_variant_access(context: &mut Context, loc: Loc) { + context.env.add_diag(diag!( + Syntax::InvalidVariantAccess, + (loc, "variant name not expected in this context".to_owned()) + )); +} + fn access_specifier(context: &mut Context, specifier: P::AccessSpecifier) -> E::AccessSpecifier { let (negated, kind, chain, type_args, address) = match specifier.value { AccessSpecifier_::Acquires(negated, chain, type_args, address) => ( @@ -1711,6 +1763,10 @@ fn access_specifier_name_access_chain( chain: NameAccessChain, ) -> (Option
, Option, Option) { match chain.value { + NameAccessChain_::Four(..) => { + invalid_variant_access(context, chain.loc); + (None, None, None) + }, NameAccessChain_::One(name) if name.value.as_str() == "*" => { // A single wildcard means any resource at the specified address, e.g. `*(0x2)` (None, None, None) @@ -2224,12 +2280,15 @@ fn name_access_chain( (Access::ApplyPositional, PN::One(n)) | (Access::ApplyNamed, PN::One(n)) | (Access::Type, PN::One(n)) => match context.aliases.member_alias_get(&n) { - Some((mident, mem)) => EN::ModuleAccess(mident, mem), - None => EN::Name(n), + Some((mident, mem)) => EN::ModuleAccess(mident, mem, None), + None => { + // left unresolved + EN::Name(n) + }, }, (Access::Term, PN::One(n)) if is_valid_struct_constant_or_schema_name(n.value.as_str()) => { match context.aliases.member_alias_get(&n) { - Some((mident, mem)) => EN::ModuleAccess(mident, mem), + Some((mident, mem)) => EN::ModuleAccess(mident, mem, None), None => EN::Name(n), } }, @@ -2240,27 +2299,55 @@ fn name_access_chain( .add_diag(unexpected_address_module_error(loc, nloc, access)); return None; }, - - (_, PN::Two(sp!(_, LN::Name(n1)), n2)) => match context.aliases.module_alias_get(&n1) { - None => { + (_, PN::Two(sp!(_, LN::Name(n1)), n2)) => { + if let Some((mident, mem)) = context.aliases.member_alias_get(&n1).filter(|_| { + is_valid_struct_constant_or_schema_name(n1.value.as_str()) + && is_valid_struct_constant_or_schema_name(n2.value.as_str()) + }) { + // n1 is interpreted as a type and n2 as a variant in the type + EN::ModuleAccess(mident, mem, Some(n2)) + } else if let Some(mident) = context.aliases.module_alias_get(&n1) { + // n1 is interpreted as a module and n2 as type. + EN::ModuleAccess(mident, n2, None) + } else { context.env.add_diag(diag!( NameResolution::UnboundModule, - (n1.loc, format!("Unbound module alias '{}'", n1)) + (n1.loc, format!("Unbound module or type alias '{}'", n1)) )); return None; - }, - Some(mident) => EN::ModuleAccess(mident, n2), + } }, (_, PN::Three(sp!(ident_loc, (ln, n2)), n3)) => { + let default_interpretation = |context: &mut Context| { + let addr = address(context, /* suggest_declaration */ false, ln); + let mident = sp(ident_loc, ModuleIdent_::new(addr, ModuleName(n2))); + EN::ModuleAccess(mident, n3, None) + }; + match &ln.value { + LeadingNameAccess_::Name(n1) + if is_valid_struct_constant_or_schema_name(n2.value.as_str()) => + { + // Attempt to interpret n1 as module alias. This is for + // reaching struct variants as in `module::Struct::Variant`. + if let Some(mident) = context.aliases.module_alias_get(n1) { + EN::ModuleAccess(mident, n2, Some(n3)) + } else { + default_interpretation(context) + } + }, + _ => default_interpretation(context), + } + }, + (_, PN::Four(sp!(ident_loc, (ln, n2)), n3, n4)) => { let addr = address(context, /* suggest_declaration */ false, ln); let mident = sp(ident_loc, ModuleIdent_::new(addr, ModuleName(n2))); - EN::ModuleAccess(mident, n3) + EN::ModuleAccess(mident, n3, Some(n4)) }, }; if let Some(deprecated_item_kind) = deprecated_item_kind { match &tn_ { - EN::ModuleAccess(mident, n) => { + EN::ModuleAccess(mident, n, _) => { check_for_deprecated_member_use(context, Some(mident), n, deprecated_item_kind); }, EN::Name(n) => { @@ -2298,7 +2385,7 @@ fn name_access_chain_to_module_ident( }; Some(module_ident(context, sp(loc, pmident_))) }, - PN::Three(sp!(ident_loc, (ln, n)), mem) => { + PN::Three(sp!(ident_loc, (ln, n)), mem) | PN::Four(sp!(ident_loc, (ln, n)), mem, _) => { // Process the module ident just for errors let pmident_ = P::ModuleIdent_ { address: ln, @@ -2503,6 +2590,21 @@ fn exp_(context: &mut Context, sp!(loc, pe_): P::Exp) -> E::Exp { }; EE::IfElse(eb, et, ef) }, + PE::Match(pd, parms) => { + let discriminator = exp(context, *pd); + let match_arms = parms + .into_iter() + .map(|parm| { + let loc = parm.loc; + let (pbl, pc, pb) = parm.value; + let bind_list = bind_list(context, pbl).expect("bind list always present"); + let opt_cond = pc.map(|e| *exp(context, e)); + let body = *exp(context, pb); + sp(loc, (bind_list, opt_cond, body)) + }) + .collect::>(); + EE::Match(discriminator, match_arms) + }, 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)), @@ -2791,8 +2893,15 @@ fn bind(context: &mut Context, sp!(loc, pb_): P::Bind) -> Option { use P::Bind_ as PB; let b_ = match pb_ { PB::Var(v) => { - check_valid_local_name(context, &v); - EL::Var(sp(loc, E::ModuleAccess_::Name(v.0)), None) + if context.env.flags().lang_v2() + && is_valid_struct_constant_or_schema_name(v.value().as_str()) + { + // Interpret as an unqualified module access + EL::Unpack(sp(v.loc(), ModuleAccess_::Name(v.0)), None, Fields::new()) + } else { + check_valid_local_name(context, &v); + EL::Var(sp(loc, E::ModuleAccess_::Name(v.0)), None) + } }, PB::Unpack(ptn, ptys_opt, pfields) => { // check for type use @@ -2865,6 +2974,10 @@ fn assign(context: &mut Context, sp!(loc, e_): P::Exp) -> Option { return None; }, + PE::Name(sp!(_, P::NameAccessChain_::Four(_, _, _)), _) => { + invalid_variant_access(context, loc); + return None; + }, PE::Name(n, Some(_)) if !context.in_spec_context => { let msg = format!( "Unexpected assignment of instantiated type without fields outside of a spec \ @@ -2883,7 +2996,7 @@ fn assign(context: &mut Context, sp!(loc, e_): P::Exp) -> Option { PE::Name(pn, ptys_opt) => { let en = name_access_chain(context, Access::Term, pn, Some(DeprecatedItem::Struct))?; match &en.value { - E::ModuleAccess_::ModuleAccess(m, n) if !context.in_spec_context => { + E::ModuleAccess_::ModuleAccess(m, n, _) if !context.in_spec_context => { let msg = format!( "Unexpected assignment of module access without fields outside of a spec \ context.\nIf you are trying to unpack a struct, try adding fields, e.g. \ @@ -3022,6 +3135,16 @@ fn unbound_names_exp(unbound: &mut UnboundNames, sp!(_, e_): &E::Exp) { unbound_names_exp(unbound, et); unbound_names_exp(unbound, econd) }, + EE::Match(ed, arms) => { + unbound_names_exp(unbound, ed); + for arm in arms { + unbound_names_binds(unbound, &arm.value.0); + if let Some(c) = &arm.value.1 { + unbound_names_exp(unbound, c) + } + unbound_names_exp(unbound, &arm.value.2) + } + }, EE::While(econd, eloop) => { unbound_names_exp(unbound, eloop); unbound_names_exp(unbound, econd) diff --git a/third_party/move/move-compiler/src/naming/translate.rs b/third_party/move/move-compiler/src/naming/translate.rs index 901e284483e3b..5a5246bd01af4 100644 --- a/third_party/move/move-compiler/src/naming/translate.rs +++ b/third_party/move/move-compiler/src/naming/translate.rs @@ -279,7 +279,7 @@ impl<'env> Context<'env> { None }, }, - EA::ModuleAccess(m, n) => match self.resolve_module_type(nloc, &m, &n) { + EA::ModuleAccess(m, n, _) => match self.resolve_module_type(nloc, &m, &n) { None => { assert!(self.env.has_errors()); None @@ -312,7 +312,7 @@ impl<'env> Context<'env> { }, Some(_) => Some((None, ConstantName(n))), }, - EA::ModuleAccess(m, n) => match self.resolve_module_constant(loc, &m, &n) { + EA::ModuleAccess(m, n, _) => match self.resolve_module_constant(loc, &m, &n) { None => { assert!(self.env.has_errors()); None @@ -597,7 +597,7 @@ fn acquires_type(context: &mut Context, sp!(loc, en_): E::ModuleAccess) -> Optio .add_diag(diag!(NameResolution::NamePositionMismatch, (loc, msg))); None }, - EN::ModuleAccess(m, n) => { + EN::ModuleAccess(m, n, _) => { let (decl_loc, _, abilities, _) = context.resolve_module_type(loc, &m, &n)?; acquires_type_struct(context, loc, decl_loc, m, StructName(n), &abilities) }, @@ -666,7 +666,7 @@ fn struct_def( let attributes = sdef.attributes; let abilities = sdef.abilities; let type_parameters = struct_type_parameters(context, sdef.type_parameters); - let fields = struct_fields(context, sdef.fields); + let fields = struct_fields(context, sdef.loc, sdef.layout); N::StructDefinition { attributes, abilities, @@ -675,12 +675,15 @@ fn struct_def( } } -fn struct_fields(context: &mut Context, efields: E::StructFields) -> N::StructFields { - match efields { - E::StructFields::Native(loc) => N::StructFields::Native(loc), - E::StructFields::Defined(em) => { +fn struct_fields(context: &mut Context, _loc: Loc, elayout: E::StructLayout) -> N::StructFields { + match elayout { + E::StructLayout::Native(loc) => N::StructFields::Native(loc), + E::StructLayout::Singleton(em) => { N::StructFields::Defined(em.map(|_f, (idx, t)| (idx, type_(context, t)))) }, + E::StructLayout::Variants(_) => { + panic!("ICE unexpected Move 2 struct layout") + }, } } @@ -809,7 +812,7 @@ fn type_(context: &mut Context, sp!(loc, ety_): E::Type) -> N::Type { args.push(type_(context, *result)); NT::builtin_(sp(loc, N::BuiltinTypeName_::Fun), args) }, - ET::Apply(sp!(nloc, EN::ModuleAccess(m, n)), tys) => { + ET::Apply(sp!(nloc, EN::ModuleAccess(m, n, _)), tys) => { match context.resolve_module_type(nloc, &m, &n) { None => { assert!(context.env.has_errors()); @@ -1065,7 +1068,7 @@ fn exp_(context: &mut Context, e: E::Exp) -> N::Exp { }, EA::Name(n) => NE::VarCall(Var(n), nes), - EA::ModuleAccess(m, n) => match context.resolve_module_function(mloc, &m, &n) { + EA::ModuleAccess(m, n, _) => match context.resolve_module_function(mloc, &m, &n) { None => { assert!(context.env.has_errors()); NE::UnresolvedError @@ -1104,6 +1107,10 @@ fn exp_(context: &mut Context, e: E::Exp) -> N::Exp { assert!(context.env.has_errors()); NE::UnresolvedError }, + // Matches variants only allowed in Move 2 + EE::Match(..) => { + panic!("ICE unexpected Move 2 construct") + }, // Matches variants only allowed in specs (we handle the allowed ones above) EE::Index(..) | EE::Quant(..) | EE::Name(_, Some(_)) => { panic!("ICE unexpected specification construct") diff --git a/third_party/move/move-compiler/src/parser/ast.rs b/third_party/move/move-compiler/src/parser/ast.rs index de516ecf5780a..a5ae8ab98fb6e 100644 --- a/third_party/move/move-compiler/src/parser/ast.rs +++ b/third_party/move/move-compiler/src/parser/ast.rs @@ -199,6 +199,7 @@ pub struct FriendDecl { new_name!(Field); new_name!(StructName); +new_name!(VariantName); pub type ResourceLoc = Option; @@ -216,15 +217,24 @@ pub struct StructDefinition { pub abilities: Vec, pub name: StructName, pub type_parameters: Vec, - pub fields: StructFields, + pub layout: StructLayout, } #[derive(Debug, PartialEq, Clone)] -pub enum StructFields { - Defined(Vec<(Field, Type)>), +pub enum StructLayout { + Singleton(Vec<(Field, Type)>), + Variants(Vec), Native(Loc), } +#[derive(Debug, PartialEq, Clone)] +pub struct StructVariant { + pub attributes: Vec, + pub loc: Loc, + pub name: VariantName, + pub fields: Vec<(Field, Type)>, +} + //************************************************************************************************** // Functions //************************************************************************************************** @@ -452,6 +462,8 @@ pub enum NameAccessChain_ { Two(LeadingNameAccess, Name), // (|):::: Three(Spanned<(LeadingNameAccess, Name)>, Name), + // (|):::::: + Four(Spanned<(LeadingNameAccess, Name)>, Name, Name), } pub type NameAccessChain = Spanned; @@ -634,6 +646,8 @@ pub enum Exp_ { While(Box, Box), // loop eloop Loop(Box), + // match (e) { b1 [ if c_1] => e1, ... } + Match(Box, Vec, Exp)>>), // { seq } Block(Sequence), @@ -717,6 +731,16 @@ pub enum SequenceItem_ { } pub type SequenceItem = Spanned; +pub type MatchArm = Spanned; + +#[derive(Debug, Clone, PartialEq)] +pub struct MatchArm_ { + bind: Bind, + variant_name: NameAccessChain, + type_args: Option>, + bindings: Vec<(Field, Bind)>, +} + //************************************************************************************************** // Traits //************************************************************************************************** @@ -967,6 +991,9 @@ impl fmt::Display for NameAccessChain_ { NameAccessChain_::One(n) => write!(f, "{}", n), NameAccessChain_::Two(ln, n2) => write!(f, "{}::{}", ln, n2), NameAccessChain_::Three(sp!(_, (ln, n2)), n3) => write!(f, "{}::{}::{}", ln, n2, n3), + NameAccessChain_::Four(sp!(_, (ln, n2)), n3, n4) => { + write!(f, "{}::{}::{}::{}", ln, n2, n3, n4) + }, } } } @@ -1265,7 +1292,7 @@ impl AstDebug for StructDefinition { abilities, name, type_parameters, - fields, + layout, } = self; attributes.ast_debug(w); @@ -1274,19 +1301,21 @@ impl AstDebug for StructDefinition { false }); - if let StructFields::Native(_) = fields { + if let StructLayout::Native(_) = layout { w.write("native "); } w.write(&format!("struct {}", name)); type_parameters.ast_debug(w); - if let StructFields::Defined(fields) = fields { - w.block(|w| { + match layout { + StructLayout::Singleton(fields) => w.block(|w| { w.semicolon(fields, |w, (f, st)| { w.write(&format!("{}: ", f)); st.ast_debug(w); }); - }) + }), + StructLayout::Variants(_) => w.writeln("variant printing NYI"), + StructLayout::Native(_) => {}, } } } @@ -1795,6 +1824,20 @@ impl AstDebug for Exp_ { f.ast_debug(w); } }, + E::Match(e, arms) => { + w.write("match ("); + e.ast_debug(w); + w.write(") {"); + for arm in arms { + arm.value.0.ast_debug(w); + if let Some(cond) = &arm.value.1 { + w.write(" if "); + cond.ast_debug(w); + } + w.write(" => "); + arm.value.2.ast_debug(w) + } + }, E::While(b, e) => { w.write("while ("); b.ast_debug(w); diff --git a/third_party/move/move-compiler/src/parser/lexer.rs b/third_party/move/move-compiler/src/parser/lexer.rs index 6ad463d63abe0..71bfd10c28daa 100644 --- a/third_party/move/move-compiler/src/parser/lexer.rs +++ b/third_party/move/move-compiler/src/parser/lexer.rs @@ -42,6 +42,7 @@ pub enum Tok { LessLess, Equal, EqualEqual, + EqualGreater, EqualEqualGreater, LessEqualEqualGreater, Greater, @@ -117,6 +118,7 @@ impl fmt::Display for Tok { LessLess => "<<", Equal => "=", EqualEqual => "==", + EqualGreater => "=>", EqualEqualGreater => "==>", LessEqualEqualGreater => "<==>", Greater => ">", @@ -495,6 +497,8 @@ fn find_token( '=' => { if text.starts_with("==>") { (Tok::EqualEqualGreater, 3) + } else if text.starts_with("=>") { + (Tok::EqualGreater, 2) } else if text.starts_with("==") { (Tok::EqualEqual, 2) } else { diff --git a/third_party/move/move-compiler/src/parser/syntax.rs b/third_party/move/move-compiler/src/parser/syntax.rs index a3e303b8cba62..189a6c7c0fdf2 100644 --- a/third_party/move/move-compiler/src/parser/syntax.rs +++ b/third_party/move/move-compiler/src/parser/syntax.rs @@ -77,6 +77,30 @@ fn add_type_args_ambiguity_label(loc: Loc, mut diag: Box) -> Box bool { + if !context.env.flags().lang_v2() { + context.env.add_diag(diag!( + Syntax::UnsupportedLanguageItem, + ( + loc, + format!("Move 2 language construct is not enabled: {}", description) + ) + )); + false + } else { + true + } +} + +fn require_move_2_and_advance( + context: &mut Context, + description: &str, +) -> Result> { + let loc = current_token_loc(context.tokens); + context.tokens.advance()?; + Ok(require_move_2(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) } @@ -434,7 +458,13 @@ fn parse_name_access_chain_<'a, F: FnOnce() -> &'a str>( ); consume_token(context.tokens, Tok::ColonColon)?; let n3 = parse_identifier_or_possibly_wildcard(context, allow_wildcard)?; - Ok(NameAccessChain_::Three(sp(ln_n2_loc, (ln, n2)), n3)) + if context.tokens.peek() != Tok::ColonColon { + return Ok(NameAccessChain_::Three(sp(ln_n2_loc, (ln, n2)), n3)); + } + consume_token(context.tokens, Tok::ColonColon)?; + let n4 = parse_identifier_or_possibly_wildcard(context, allow_wildcard)?; + require_move_2(context, n4.loc, "fully qualified variant name"); + Ok(NameAccessChain_::Four(sp(ln_n2_loc, (ln, n2)), n3, n4)) } fn parse_identifier_or_possibly_wildcard( @@ -700,15 +730,19 @@ fn parse_bind(context: &mut Context) -> Result> { // The item description specified here should include the special case above for // variable names, because if the current context cannot be parsed as a struct name // it is possible that the user intention was to use a variable name. - let ty = parse_name_access_chain(context, false, || "a variable or struct name")?; + let ty = parse_name_access_chain(context, false, || "a variable or struct or variant name")?; let ty_args = parse_optional_type_args(context)?; - let args = parse_comma_list( - context, - Tok::LBrace, - Tok::RBrace, - parse_bind_field, - "a field binding", - )?; + let args = if !context.env.flags().lang_v2() || context.tokens.peek() == Tok::LBrace { + parse_comma_list( + context, + Tok::LBrace, + Tok::RBrace, + parse_bind_field, + "a field binding", + )? + } else { + vec![] + }; let end_loc = context.tokens.previous_end_loc(); let unpack = Bind_::Unpack(Box::new(ty), ty_args, args); Ok(spanned( @@ -935,6 +969,7 @@ fn parse_sequence(context: &mut Context) -> Result> { // | "while" "(" ")" (SpecBlock)? // | "loop" // | "loop" "{" "}" +// | // | "return" "{" "}" // | "return" ? // | "abort" "{" "}" @@ -953,6 +988,14 @@ fn parse_term(context: &mut Context) -> Result> { } return parse_binop_exp(context, control_exp, /* min_prec */ 1); }, + Tok::Identifier if context.tokens.content() == "match" => { + // Match always ends in block (see above case for comparison) + let match_exp = parse_match_exp(context)?; + if at_end_of_exp(context) { + return Ok(match_exp); + } + return parse_binop_exp(context, match_exp, 1); + }, Tok::Identifier if context.tokens.content() == FOR_IDENT && matches!(context.tokens.lookahead_nth(0), Ok(Tok::LParen)) @@ -1413,6 +1456,55 @@ fn parse_for_loop(context: &mut Context) -> Result<(Exp, bool), Box> Ok((parsed_for_loop, ends_in_block)) } +// Match = "match" "(" ")" "{" ( ","? )* "}" +// MatchArm = ( "if" )? "=>" +fn parse_match_exp(context: &mut Context) -> Result> { + let start_loc = context.tokens.start_loc(); + require_move_2_and_advance(context, "match expression")?; + consume_token(context.tokens, Tok::LParen)?; + let exp = parse_exp(context)?; + consume_token(context.tokens, Tok::RParen)?; + consume_token(context.tokens, Tok::LBrace)?; + let arms = parse_match_arms(context)?; + consume_token(context.tokens, Tok::RBrace)?; + Ok(spanned( + context.tokens.file_hash(), + start_loc, + context.tokens.previous_end_loc(), + Exp_::Match(Box::new(exp), arms), + )) +} + +fn parse_match_arms( + context: &mut Context, +) -> Result, Exp)>>, Box> { + let mut arms = vec![]; + while context.tokens.peek() != Tok::RBrace { + let start_loc = context.tokens.start_loc(); + let bind_list = parse_bind_list(context)?; + let cond = if match_token(context.tokens, Tok::If)? { + Some(parse_exp(context)?) + } else { + None + }; + consume_token(context.tokens, Tok::EqualGreater)?; + let (body, body_is_block) = parse_exp_or_control_sequence(context)?; + let next = context.tokens.peek(); + // Block based arms are optionally separated by comma, otherwise + // a comma is required if not at end of the list. + if (!body_is_block && next != Tok::RBrace) || next == Tok::Comma { + consume_token(context.tokens, Tok::Comma)? + } + arms.push(spanned( + context.tokens.file_hash(), + start_loc, + context.tokens.previous_end_loc(), + (bind_list, cond, body), + )) + } + Ok(arms) +} + // Parse a pack, call, or other reference to a name: // NameExp = // "{" Comma "}" @@ -1500,7 +1592,6 @@ fn at_end_of_exp(context: &mut Context) -> bool { fn at_start_of_exp(context: &mut Context) -> bool { matches!( context.tokens.peek(), - // value Tok::NumValue | Tok::NumTypedValue | Tok::ByteStringValue @@ -2249,7 +2340,7 @@ fn parse_function_decl( let mut pure_loc = None; loop { let negated = if context.tokens.peek() == Tok::Exclaim { - context.tokens.advance()?; + require_move_2_and_advance(context, "access specifiers")?; true } else { false @@ -2264,7 +2355,7 @@ fn parse_function_decl( )?) }, Tok::Identifier if context.tokens.content() == "reads" => { - context.tokens.advance()?; + require_move_2_and_advance(context, "access specifiers")?; access_specifiers.extend(parse_access_specifier_list( context, negated, @@ -2272,7 +2363,7 @@ fn parse_function_decl( )?) }, Tok::Identifier if context.tokens.content() == "writes" => { - context.tokens.advance()?; + require_move_2_and_advance(context, "access specifiers")?; access_specifiers.extend(parse_access_specifier_list( context, negated, @@ -2281,13 +2372,13 @@ fn parse_function_decl( }, Tok::Identifier if context.tokens.content() == "pure" => { pure_loc = Some(current_token_loc(context.tokens)); + require_move_2_and_advance(context, "access specifiers")?; if negated { return Err(Box::new(diag!( Syntax::InvalidAccessSpecifier, (pure_loc.unwrap(), "'pure' cannot be negated") ))); } - context.tokens.advance()?; }, _ => break, } @@ -2460,11 +2551,17 @@ fn parse_address_specifier(context: &mut Context) -> Result ("has" (, )+)? -// ("{" Comma "}" | ";") +// native struct ? ";" +// | "struct" ? "{" Comma "}" +// | "enum" ? "{" Comma "}" // StructDefName = // +// EnumVariant = +// "{" Comma "}" +// Abilities = +// "has" (, )+ fn parse_struct_decl( + is_enum: bool, attributes: Vec, start_loc: usize, modifiers: Modifiers, @@ -2475,19 +2572,22 @@ fn parse_struct_decl( entry, native, } = modifiers; - if let Some(vis) = visibility { - let msg = format!( - "Invalid struct declaration. Structs cannot have visibility modifiers as they are \ + match visibility { + Some(vis) if !context.env.flags().lang_v2() => { + let msg = format!( + "Invalid struct declaration. Structs cannot have visibility modifiers as they are \ always '{}'", - Visibility::PUBLIC - ); - context - .env - .add_diag(diag!(Syntax::InvalidModifier, (vis.loc().unwrap(), msg))); + Visibility::PUBLIC + ); + context + .env + .add_diag(diag!(Syntax::InvalidModifier, (vis.loc().unwrap(), msg))); + }, + _ => {}, } if let Some(loc) = entry { let msg = format!( - "Invalid constant declaration. '{}' is used only on functions", + "Invalid type declaration. '{}' is used only on functions", ENTRY_MODIFIER ); context @@ -2495,7 +2595,11 @@ fn parse_struct_decl( .add_diag(diag!(Syntax::InvalidModifier, (loc, msg))); } - consume_token(context.tokens, Tok::Struct)?; + if is_enum { + require_move_2_and_advance(context, "struct variants")?; + } else { + consume_token(context.tokens, Tok::Struct)?; + } // let name = StructName(parse_identifier(context)?); @@ -2528,20 +2632,37 @@ fn parse_struct_decl( vec![] }; - let fields = match native { + let layout = match native { Some(loc) => { consume_token(context.tokens, Tok::Semicolon)?; - StructFields::Native(loc) + StructLayout::Native(loc) }, - _ => { - let list = parse_comma_list( - context, - Tok::LBrace, - Tok::RBrace, - parse_field_annot, - "a field", - )?; - StructFields::Defined(list) + None => { + if is_enum { + let mut list = vec![]; + consume_token(context.tokens, Tok::LBrace)?; + while context.tokens.peek() != Tok::RBrace { + // If the variant is based on a block, we allow but do not require + // a `,`. Otherwise, a comma is required. + let (variant, has_block) = parse_struct_variant(context)?; + let next = context.tokens.peek(); + if (!has_block && next != Tok::RBrace) || next == Tok::Comma { + consume_token(context.tokens, Tok::Comma)?; + } + list.push(variant) + } + consume_token(context.tokens, Tok::RBrace)?; + StructLayout::Variants(list) + } else { + let list = parse_comma_list( + context, + Tok::LBrace, + Tok::RBrace, + parse_field_annot, + "a field", + )?; + StructLayout::Singleton(list) + } }, }; @@ -2556,10 +2677,47 @@ fn parse_struct_decl( abilities, name, type_parameters, - fields, + layout, }) } +// Parse a struct variant. The returned boolean indicates whether the variant has a braced (`{..}`) +// field list. +fn parse_struct_variant(context: &mut Context) -> Result<(StructVariant, bool), Box> { + let start_loc = context.tokens.start_loc(); + let attributes = parse_attributes(context)?; + context.tokens.match_doc_comments(); + let name = VariantName(parse_identifier(context)?); + let (fields, has_block) = if context.tokens.peek() == Tok::LBrace { + ( + parse_comma_list( + context, + Tok::LBrace, + Tok::RBrace, + parse_field_annot, + "a field", + )?, + true, + ) + } else { + (vec![], false) + }; + let loc = make_loc( + context.tokens.file_hash(), + start_loc, + context.tokens.previous_end_loc(), + ); + Ok(( + StructVariant { + attributes, + loc, + name, + fields, + }, + has_block, + )) +} + // Parse a field annotated with a type: // FieldAnnot = ":" fn parse_field_annot(context: &mut Context) -> Result<(Field, Type), Box> { @@ -2867,8 +3025,13 @@ fn parse_module( attributes, start_loc, modifiers, context, )?), Tok::Struct => ModuleMember::Struct(parse_struct_decl( - attributes, start_loc, modifiers, context, + false, attributes, start_loc, modifiers, context, )?), + Tok::Identifier if context.tokens.content() == "enum" => { + ModuleMember::Struct(parse_struct_decl( + true, attributes, start_loc, modifiers, context, + )?) + }, _ => { return Err(unexpected_token_error( context.tokens, diff --git a/third_party/move/move-compiler/src/shared/mod.rs b/third_party/move/move-compiler/src/shared/mod.rs index 361f6de189bb9..c14b9ce386ac9 100644 --- a/third_party/move/move-compiler/src/shared/mod.rs +++ b/third_party/move/move-compiler/src/shared/mod.rs @@ -406,9 +406,13 @@ pub struct Flags { #[clap(long = cli::WARN_UNUSED_FLAG, default_value="false")] warn_unused: bool, - /// Support v2 syntax (up to expansion phase) - #[clap(long = cli::V2_FLAG)] - v2: bool, + /// Support Move 2 language features (up to expansion phase) + #[clap(long = cli::LANG_V2_FLAG)] + lang_v2: bool, + + /// Support compiler v2 (up to expansion phase) + #[clap(long = cli::COMPILER_V2_FLAG)] + compiler_v2: bool, /// Block v1 runs past expansion phase #[clap(long = MOVE_COMPILER_BLOCK_V1_FLAG, default_value=bool_to_str(get_move_compiler_block_v1_from_env()))] @@ -429,7 +433,8 @@ impl Flags { warn_of_deprecation_use: move_compiler_warn_of_deprecation_use_env_var(), warn_of_deprecation_use_in_aptos_libs: warn_of_deprecation_use_in_aptos_libs_env_var(), warn_unused: false, - v2: false, + lang_v2: false, + compiler_v2: false, block_v1_compiler: get_move_compiler_block_v1_from_env(), } } @@ -464,7 +469,7 @@ impl Flags { verify: true, shadow: true, // allows overlapping between sources and deps keep_testing_functions: true, - v2: true, + lang_v2: true, ..Self::empty() } } @@ -577,12 +582,26 @@ impl Flags { self.debug } - pub fn v2(&self) -> bool { - self.v2 + pub fn lang_v2(&self) -> bool { + self.lang_v2 + } + + pub fn set_lang_v2(self, v2: bool) -> Self { + Self { + lang_v2: v2, + ..self + } } - pub fn set_v2(self, v2: bool) -> Self { - Self { v2, ..self } + pub fn compiler_v2(&self) -> bool { + self.compiler_v2 + } + + pub fn set_compiler_v2(self, v2: bool) -> Self { + Self { + compiler_v2: v2, + ..self + } } } diff --git a/third_party/move/move-compiler/src/unit_test/plan_builder.rs b/third_party/move/move-compiler/src/unit_test/plan_builder.rs index d70235765350d..c53926366cbd9 100644 --- a/third_party/move/move-compiler/src/unit_test/plan_builder.rs +++ b/third_party/move/move-compiler/src/unit_test/plan_builder.rs @@ -565,7 +565,7 @@ fn convert_constant_value_u64_constant_or_value( let (vloc, module, member) = match value { sp!( vloc, - EAV::ModuleAccess(sp!(_, ModuleAccess_::ModuleAccess(m, n))) + EAV::ModuleAccess(sp!(_, ModuleAccess_::ModuleAccess(m, n, _))) ) => (*vloc, m, n), _ => { let (vloc, u) = convert_attribute_value_u64(context, loc, value)?; diff --git a/third_party/move/move-compiler/tests/move_check/expansion/access_specifier_not_supported.exp b/third_party/move/move-compiler/tests/move_check/expansion/access_specifier_not_supported.exp index 58cf800109a42..277f6d3ff2e41 100644 --- a/third_party/move/move-compiler/tests/move_check/expansion/access_specifier_not_supported.exp +++ b/third_party/move/move-compiler/tests/move_check/expansion/access_specifier_not_supported.exp @@ -1,24 +1,12 @@ -error[E01012]: invalid access specifier - ┌─ tests/move_check/expansion/access_specifier_not_supported.move:14:23 - │ -14 │ fun f4() acquires S(*) { - │ ^^^^ compiler version 1 only supports simple 'acquires ' clauses - -error[E01012]: invalid access specifier - ┌─ tests/move_check/expansion/access_specifier_not_supported.move:23:23 - │ -23 │ fun f7() acquires *(*) { - │ ^^^^ compiler version 1 only supports simple 'acquires ' clauses - -error[E01012]: invalid access specifier - ┌─ tests/move_check/expansion/access_specifier_not_supported.move:26:23 - │ -26 │ fun f8() acquires *(0x42) { - │ ^^^^^^^ compiler version 1 only supports simple 'acquires ' clauses +error[E01013]: unsupported language construct + ┌─ tests/move_check/expansion/access_specifier_not_supported.move:8:14 + │ +8 │ fun f2() reads S { + │ ^^^^^ Move 2 language construct is not enabled: access specifiers -error[E01012]: invalid access specifier - ┌─ tests/move_check/expansion/access_specifier_not_supported.move:29:34 +error[E01013]: unsupported language construct + ┌─ tests/move_check/expansion/access_specifier_not_supported.move:11:14 │ -29 │ fun f9(_a: address) acquires *(_a) { - │ ^^^^^ compiler version 1 only supports simple 'acquires ' clauses +11 │ fun f3() writes S { + │ ^^^^^^ Move 2 language construct is not enabled: access specifiers diff --git a/third_party/move/move-compiler/tests/move_check/expansion/assign_non_simple_name.exp b/third_party/move/move-compiler/tests/move_check/expansion/assign_non_simple_name.exp index f9b6ea6214f35..e934bfe6bea7a 100644 --- a/third_party/move/move-compiler/tests/move_check/expansion/assign_non_simple_name.exp +++ b/third_party/move/move-compiler/tests/move_check/expansion/assign_non_simple_name.exp @@ -1,3 +1,9 @@ +warning[W09001]: unused alias + ┌─ tests/move_check/expansion/assign_non_simple_name.move:6:15 + │ +6 │ use 0x42::X; + │ ^ Unused 'use' of alias 'X'. Consider removing it + error[E01010]: syntax item restricted to spec contexts ┌─ tests/move_check/expansion/assign_non_simple_name.move:16:9 │ diff --git a/third_party/move/move-compiler/tests/move_check/expansion/duplicate_field.exp b/third_party/move/move-compiler/tests/move_check/expansion/duplicate_field.exp index ff609e65f0de8..00bc94c64791a 100644 --- a/third_party/move/move-compiler/tests/move_check/expansion/duplicate_field.exp +++ b/third_party/move/move-compiler/tests/move_check/expansion/duplicate_field.exp @@ -4,5 +4,5 @@ error[E02001]: duplicate declaration, item, or annotation 3 │ f: u64, │ - Field previously defined here 4 │ f: u64, - │ ^ Duplicate definition for field 'f' in struct 'S' + │ ^ Duplicate definition for field 'f' diff --git a/third_party/move/move-compiler/tests/move_check/expansion/unbound_module_alias_in_type.exp b/third_party/move/move-compiler/tests/move_check/expansion/unbound_module_alias_in_type.exp index c40ba886dd0e4..8cb8a822705ef 100644 --- a/third_party/move/move-compiler/tests/move_check/expansion/unbound_module_alias_in_type.exp +++ b/third_party/move/move-compiler/tests/move_check/expansion/unbound_module_alias_in_type.exp @@ -2,5 +2,5 @@ error[E03002]: unbound module ┌─ tests/move_check/expansion/unbound_module_alias_in_type.move:2:16 │ 2 │ fun foo(x: X::T) {} - │ ^ Unbound module alias 'X' + │ ^ Unbound module or type alias 'X' diff --git a/third_party/move/move-compiler/tests/move_check/expansion/use_nested_self_as_invalid.exp b/third_party/move/move-compiler/tests/move_check/expansion/use_nested_self_as_invalid.exp index 5901c05a81ffe..9bc25401d56e3 100644 --- a/third_party/move/move-compiler/tests/move_check/expansion/use_nested_self_as_invalid.exp +++ b/third_party/move/move-compiler/tests/move_check/expansion/use_nested_self_as_invalid.exp @@ -4,15 +4,18 @@ warning[W09001]: unused alias 8 │ use 0x2::X::{Self as B, foo, S}; │ ^ Unused 'use' of alias 'B'. Consider removing it -error[E03002]: unbound module +error[E04018]: cyclic data ┌─ tests/move_check/expansion/use_nested_self_as_invalid.move:10:19 │ 10 │ struct X { f: X::S, f2: S } - │ ^ Unbound module alias 'X' + │ ^^^^ + │ │ + │ Invalid field containing 'X' in struct 'X'. + │ Using this struct creates a cycle: 'X' contains 'X' error[E03002]: unbound module ┌─ tests/move_check/expansion/use_nested_self_as_invalid.move:12:9 │ 12 │ X::foo(); - │ ^ Unbound module alias 'X' + │ ^ Unbound module or type alias 'X' diff --git a/third_party/move/move-compiler/tests/move_check/expansion/use_struct_overlap_with_module.exp b/third_party/move/move-compiler/tests/move_check/expansion/use_struct_overlap_with_module.exp new file mode 100644 index 0000000000000..52ae870bd8507 --- /dev/null +++ b/third_party/move/move-compiler/tests/move_check/expansion/use_struct_overlap_with_module.exp @@ -0,0 +1,6 @@ +warning[W09001]: unused alias + ┌─ tests/move_check/expansion/use_struct_overlap_with_module.move:7:14 + │ +7 │ use 0x2::X::{Self, S as X}; + │ ^ Unused 'use' of alias 'X'. Consider removing it + diff --git a/third_party/move/move-compiler/tests/move_check/naming/unbound_constant.exp b/third_party/move/move-compiler/tests/move_check/naming/unbound_constant.exp index be6d2cd10119b..14d11c2b715e9 100644 --- a/third_party/move/move-compiler/tests/move_check/naming/unbound_constant.exp +++ b/third_party/move/move-compiler/tests/move_check/naming/unbound_constant.exp @@ -32,7 +32,7 @@ error[E03002]: unbound module ┌─ tests/move_check/naming/unbound_constant.move:14:17 │ 14 │ let y = Self::CONSTANT; - │ ^^^^ Unbound module alias 'Self' + │ ^^^^ Unbound module or type alias 'Self' error[E03005]: unbound unscoped name ┌─ tests/move_check/naming/unbound_constant.move:15:13 @@ -44,5 +44,5 @@ error[E03002]: unbound module ┌─ tests/move_check/naming/unbound_constant.move:15:24 │ 15 │ 0 + CONSTANT + Self::CONSTANT; - │ ^^^^ Unbound module alias 'Self' + │ ^^^^ Unbound module or type alias 'Self' diff --git a/third_party/move/move-compiler/tests/move_check/naming/unbound_module.exp b/third_party/move/move-compiler/tests/move_check/naming/unbound_module.exp index 094aaa515f5c1..4dee5e0464933 100644 --- a/third_party/move/move-compiler/tests/move_check/naming/unbound_module.exp +++ b/third_party/move/move-compiler/tests/move_check/naming/unbound_module.exp @@ -8,5 +8,5 @@ error[E03002]: unbound module ┌─ tests/move_check/naming/unbound_module.move:4:9 │ 4 │ X::foo(); - │ ^ Unbound module alias 'X' + │ ^ Unbound module or type alias 'X' diff --git a/third_party/move/move-compiler/tests/move_check/parser/acquires_list_generic.exp b/third_party/move/move-compiler/tests/move_check/parser/acquires_list_generic.exp index 5bf3f0bedf569..efd50e83d1e51 100644 --- a/third_party/move/move-compiler/tests/move_check/parser/acquires_list_generic.exp +++ b/third_party/move/move-compiler/tests/move_check/parser/acquires_list_generic.exp @@ -2,5 +2,5 @@ error[E01012]: invalid access specifier ┌─ tests/move_check/parser/acquires_list_generic.move:6:24 │ 6 │ fun foo() acquires B> { - │ ^^^^^^^^^^^ compiler version 1 only supports simple 'acquires ' clauses + │ ^^^^^^^^^^^ language version 1 only supports simple 'acquires ' clauses diff --git a/third_party/move/move-compiler/tests/move_check/parser/entry_struct.exp b/third_party/move/move-compiler/tests/move_check/parser/entry_struct.exp index db53d092459da..20f301db84752 100644 --- a/third_party/move/move-compiler/tests/move_check/parser/entry_struct.exp +++ b/third_party/move/move-compiler/tests/move_check/parser/entry_struct.exp @@ -2,5 +2,5 @@ error[E01003]: invalid modifier ┌─ tests/move_check/parser/entry_struct.move:3:5 │ 3 │ entry struct S {} - │ ^^^^^ Invalid constant declaration. 'entry' is used only on functions + │ ^^^^^ Invalid type declaration. 'entry' is used only on functions diff --git a/third_party/move/move-compiler/tests/move_check/parser/let_binding_bad_name.exp b/third_party/move/move-compiler/tests/move_check/parser/let_binding_bad_name.exp index c318d5bd8c099..7de3584e3c4ba 100644 --- a/third_party/move/move-compiler/tests/move_check/parser/let_binding_bad_name.exp +++ b/third_party/move/move-compiler/tests/move_check/parser/let_binding_bad_name.exp @@ -5,5 +5,5 @@ error[E01002]: unexpected token │ ^ │ │ │ Unexpected '{' - │ Expected a variable or struct name + │ Expected a variable or struct or variant name diff --git a/third_party/move/move-compiler/tests/move_check/unit_test/cross_module_members_non_test_function.exp b/third_party/move/move-compiler/tests/move_check/unit_test/cross_module_members_non_test_function.exp index 416d8f009c0c2..2dd487bebe569 100644 --- a/third_party/move/move-compiler/tests/move_check/unit_test/cross_module_members_non_test_function.exp +++ b/third_party/move/move-compiler/tests/move_check/unit_test/cross_module_members_non_test_function.exp @@ -8,5 +8,5 @@ error[E03002]: unbound module ┌─ tests/move_check/unit_test/cross_module_members_non_test_function.move:24:9 │ 24 │ A::build_foo() - │ ^ Unbound module alias 'A' + │ ^ Unbound module or type alias 'A' diff --git a/third_party/move/move-compiler/tests/move_check/unit_test/cross_module_test_only_module.exp b/third_party/move/move-compiler/tests/move_check/unit_test/cross_module_test_only_module.exp index d1d5dd6fcbab2..409d1b7d3d820 100644 --- a/third_party/move/move-compiler/tests/move_check/unit_test/cross_module_test_only_module.exp +++ b/third_party/move/move-compiler/tests/move_check/unit_test/cross_module_test_only_module.exp @@ -8,5 +8,5 @@ error[E03002]: unbound module ┌─ tests/move_check/unit_test/cross_module_test_only_module.move:13:9 │ 13 │ M::foo() - │ ^ Unbound module alias 'M' + │ ^ Unbound module or type alias 'M' diff --git a/third_party/move/move-compiler/tests/move_check/verification/cross_module_invalid.exp b/third_party/move/move-compiler/tests/move_check/verification/cross_module_invalid.exp index b2f6304e5b896..1a882635fbf38 100644 --- a/third_party/move/move-compiler/tests/move_check/verification/cross_module_invalid.exp +++ b/third_party/move/move-compiler/tests/move_check/verification/cross_module_invalid.exp @@ -8,5 +8,5 @@ error[E03002]: unbound module ┌─ tests/move_check/verification/cross_module_invalid.move:23:9 │ 23 │ A::build_foo() - │ ^ Unbound module alias 'A' + │ ^ Unbound module or type alias 'A' diff --git a/third_party/move/move-compiler/transactional-tests/tests/generics/global_invalid.exp b/third_party/move/move-compiler/transactional-tests/tests/generics/global_invalid.exp index aea203752bf00..39f173075a42a 100644 --- a/third_party/move/move-compiler/transactional-tests/tests/generics/global_invalid.exp +++ b/third_party/move/move-compiler/transactional-tests/tests/generics/global_invalid.exp @@ -68,6 +68,6 @@ error[E03002]: unbound module ┌─ TEMPFILE2:28:9 │ 28 │ M::test_resource(&account) - │ ^ Unbound module alias 'M' + │ ^ Unbound module or type alias 'M' diff --git a/third_party/move/move-model/src/ast.rs b/third_party/move/move-model/src/ast.rs index f56405ae35124..8e7dc521115b4 100644 --- a/third_party/move/move-model/src/ast.rs +++ b/third_party/move/move-model/src/ast.rs @@ -27,7 +27,7 @@ use std::{ cell::RefCell, collections::{BTreeMap, BTreeSet, HashSet}, fmt, - fmt::{Debug, Display, Error, Formatter}, + fmt::{Debug, Error, Formatter}, hash::Hash, iter, ops::Deref, @@ -182,7 +182,7 @@ impl ConditionKind { } } -impl std::fmt::Display for ConditionKind { +impl fmt::Display for ConditionKind { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn display_ty_params( f: &mut Formatter<'_>, @@ -251,7 +251,7 @@ impl QuantKind { } } -impl std::fmt::Display for QuantKind { +impl fmt::Display for QuantKind { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { use QuantKind::*; match self { @@ -596,6 +596,8 @@ pub enum ExpData { Block(NodeId, Pattern, Option, Exp), /// Represents a conditional. IfElse(NodeId, Exp, Exp, Exp), + /// Represents a variant match + Match(NodeId, Exp, Vec), // --------------------------------------------------------- // Subsequent expressions only appear in imperative context @@ -618,6 +620,14 @@ pub enum ExpData { SpecBlock(NodeId, Spec), } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct MatchArm { + pub loc: Loc, + pub pattern: Pattern, + pub condition: Option, + pub body: Exp, +} + /// An internalized expression. We do use a wrapper around the underlying internement implementation /// variant to ensure a unique API (LocalIntern and ArcIntern e.g. differ in the presence of /// the Copy trait, and by wrapping we effectively remove the Copy from LocalIntern). @@ -680,13 +690,15 @@ pub enum RewriteResult { /// Visitor position #[derive(Clone)] pub enum VisitorPosition { - Pre, // before visiting any subexpressions - MidMutate, // after RHS and before LHS of Mutate expression. - BeforeBody, // Before body of Block expression. - BeforeThen, // Before then clause of IfElse expression. - BeforeElse, // Before else clause of IfElse expression. - PreSequenceValue, // Before final expr in a Sequence (or before Post, if seq is empty) - Post, // after visiting all subexpressions + Pre, // before visiting any subexpressions + MidMutate, // after RHS and before LHS of Mutate expression. + BeforeBody, // Before body of Block expression. + BeforeMatchBody(usize), // Before the ith body of a Match arm. + AfterMatchBody(usize), // After the ith body of a Match arm. + BeforeThen, // Before then clause of IfElse expression. + BeforeElse, // Before else clause of IfElse expression. + PreSequenceValue, // Before final expr in a Sequence (or before Post, if seq is empty) + Post, // after visiting all subexpressions } impl ExpData { @@ -733,6 +745,7 @@ impl ExpData { | Quant(node_id, ..) | Block(node_id, ..) | IfElse(node_id, ..) + | Match(node_id, ..) | Sequence(node_id, ..) | Loop(node_id, ..) | LoopCont(node_id, ..) @@ -848,6 +861,13 @@ impl ExpData { // Remove declared variables from shadow for_syms_in_pat_shadow_or_unshadow(pat, false, &mut shadow_map); }, + (Match(_, _, arms), BeforeMatchBody(idx)) => { + // Add declared variables to shadow + for_syms_in_pat_shadow_or_unshadow(&arms[idx].pattern, true, &mut shadow_map) + }, + (Match(_, _, arms), AfterMatchBody(idx)) => { + for_syms_in_pat_shadow_or_unshadow(&arms[idx].pattern, false, &mut shadow_map) + }, (Quant(_, _, ranges, ..), Pre) => { for_syms_in_ranges_shadow_or_unshadow(ranges, true, &mut shadow_map); }, @@ -1161,7 +1181,8 @@ impl ExpData { let should_continue = match x { Pre => visitor(false, e), Post => visitor(true, e), - MidMutate | BeforeBody | BeforeThen | BeforeElse | PreSequenceValue => true, + MidMutate | BeforeBody | BeforeThen | BeforeElse | BeforeMatchBody(_) + | AfterMatchBody(_) | PreSequenceValue => true, }; if should_continue { Some(()) @@ -1259,6 +1280,17 @@ impl ExpData { visitor(VisitorPosition::BeforeElse, self)?; e.visit_positions_impl(visitor)?; }, + Match(_, d, arms) => { + d.visit_positions_impl(visitor)?; + for (i, arm) in arms.iter().enumerate() { + visitor(VisitorPosition::BeforeMatchBody(i), self)?; + if let Some(c) = &arm.condition { + c.visit_positions_impl(visitor)?; + } + arm.body.visit_positions_impl(visitor)?; + visitor(VisitorPosition::AfterMatchBody(i), self)?; + } + }, Loop(_, e) => e.visit_positions_impl(visitor)?, Return(_, e) => e.visit_positions_impl(visitor)?, Sequence(_, es) => { @@ -1483,7 +1515,7 @@ impl ExpData { if let ExpData::Call(_, oper, _) = e { use Operation::*; match oper { - Select(mid, sid, ..) | UpdateField(mid, sid, ..) | Pack(mid, sid) => { + Select(mid, sid, ..) | UpdateField(mid, sid, ..) | Pack(mid, sid, _) => { usage.insert(mid.qualified(*sid)); }, _ => {}, @@ -1564,7 +1596,7 @@ impl<'a> ExpRewriterFunctions for ExpRewriter<'a> { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Operation { MoveFunction(ModuleId, FunId), - Pack(ModuleId, StructId), + Pack(ModuleId, StructId, /*variant*/ Option), Tuple, // Specification specific @@ -1674,7 +1706,13 @@ pub enum Pattern { Var(NodeId, Symbol), Wildcard(NodeId), Tuple(NodeId, Vec), - Struct(NodeId, QualifiedInstId, Vec), + Struct( + // Struct(_, struct_id, optional_variant, patterns) + NodeId, + QualifiedInstId, + Option, + Vec, + ), Error(NodeId), } @@ -1685,7 +1723,7 @@ impl Pattern { Pattern::Var(id, _) | Pattern::Wildcard(id) | Pattern::Tuple(id, _) - | Pattern::Struct(id, _, _) + | Pattern::Struct(id, _, _, _) | Pattern::Error(id) => *id, } } @@ -1729,7 +1767,7 @@ impl Pattern { fn collect_vars(r: &mut Vec<(NodeId, Symbol)>, p: &Pattern) { use Pattern::*; match p { - Struct(_, _, args) | Tuple(_, args) => { + Struct(_, _, _, args) | Tuple(_, args) => { for arg in args { Self::collect_vars(r, arg) } @@ -1764,9 +1802,10 @@ impl Pattern { ) -> bool { use Pattern::*; match p { - Struct(_nodeid, qsid, args) => { + Struct(_nodeid, qsid, _, args) => { if let Some(exp) = opt_exp { - if let ExpData::Call(_, Operation::Pack(modid, sid), actuals) = exp.as_ref() { + if let ExpData::Call(_, Operation::Pack(modid, sid, _), actuals) = exp.as_ref() + { if *sid == qsid.id && *modid == qsid.module_id { Self::collect_vars_exprs_from_vector_exprs(r, args, actuals) } else { @@ -1824,7 +1863,9 @@ impl Pattern { ) -> bool { use Pattern::*; match p { - Struct(_nodeid, _qsid, args) => Self::collect_vars_exprs_from_vector_none(r, args), + Struct(_nodeid, _qsid, _variant, args) => { + Self::collect_vars_exprs_from_vector_none(r, args) + }, Tuple(_, args) => { if let Some(value) = opt_v { match value { @@ -1942,9 +1983,10 @@ impl Pattern { .map(|pat| pat.remove_vars(vars)) .collect(), ), - Pattern::Struct(id, qsid, patvec) => Pattern::Struct( + Pattern::Struct(id, qsid, variant, patvec) => Pattern::Struct( id, qsid, + variant, patvec .into_iter() .map(|pat| pat.remove_vars(vars)) @@ -1976,7 +2018,7 @@ impl Pattern { None } }, - Pattern::Tuple(_, patvec) | Pattern::Struct(_, _, patvec) => { + Pattern::Tuple(_, patvec) | Pattern::Struct(_, _, _, patvec) => { let pat_out: Vec<_> = patvec.iter().map(|pat| pat.replace_vars(var_map)).collect(); if pat_out.iter().any(|opt_pat| opt_pat.is_some()) { // Need to build a new vec. @@ -1988,8 +2030,8 @@ impl Pattern { .collect(); match self { Pattern::Tuple(id, _) => Some(Pattern::Tuple(*id, new_vec)), - Pattern::Struct(id, qsid, _) => { - Some(Pattern::Struct(*id, qsid.clone(), new_vec)) + Pattern::Struct(id, qsid, variant, _) => { + Some(Pattern::Struct(*id, qsid.clone(), *variant, new_vec)) }, _ => None, } @@ -2017,7 +2059,7 @@ impl Pattern { pat.visit_pre_post(visitor); } }, - Struct(_, _, patvec) => { + Struct(_, _, _, patvec) => { for pat in patvec { pat.visit_pre_post(visitor); } @@ -2026,50 +2068,14 @@ impl Pattern { visitor(true, self); } - pub fn to_string<'a>(&self, env: &GlobalEnv, tctx: &'a TypeDisplayContext<'a>) -> String { - match self { - Pattern::Var(id, name) => { - let ty = env.get_node_type(*id); - format!("{}: {}", name.display(env.symbol_pool()), ty.display(tctx)) - }, - Pattern::Tuple(_, args) => format!( - "({})", - args.iter().map(|pat| pat.to_string(env, tctx)).join(", ") - ), - Pattern::Struct(_, struct_id, args) => { - let inst_str = if !struct_id.inst.is_empty() { - format!( - "<{}>", - struct_id.inst.iter().map(|ty| ty.display(tctx)).join(", ") - ) - } else { - "".to_string() - }; - let struct_env = env.get_struct(struct_id.to_qualified_id()); - let field_names = struct_env.get_fields().map(|f| f.get_name()); - let args_str = args - .iter() - .zip(field_names) - .map(|(pat, sym)| { - let field_name = env.symbol_pool().string(sym); - let pattern_str = pat.to_string(env, tctx); - if &pattern_str != field_name.as_ref() { - format!("{}: {}", field_name.as_ref(), pat.to_string(env, tctx)) - } else { - pattern_str - } - }) - .join(", "); - format!( - "{}{}{{ {} }}", - struct_env.get_full_name_str(), - inst_str, - args_str - ) - }, - Pattern::Wildcard(_) => "_".to_string(), - Pattern::Error(_) => "".to_string(), + pub fn to_string(&self, fun_env: &FunctionEnv) -> String { + PatDisplay { + env: fun_env.module_env.env, + pat: self, + fun_env: Some(fun_env.clone()), + show_type: false, } + .to_string() } pub fn display<'a>(&'a self, env: &'a GlobalEnv) -> PatDisplay<'a> { @@ -2077,7 +2083,7 @@ impl Pattern { env, pat: self, fun_env: None, - verbose: true, + show_type: true, } } @@ -2086,7 +2092,7 @@ impl Pattern { env: other.env, pat: self, fun_env: other.fun_env.clone(), - verbose: other.verbose, + show_type: other.show_type, } } @@ -2095,19 +2101,24 @@ impl Pattern { env: other.env, pat: self, fun_env: other.fun_env.clone(), - verbose: other.verbose, + show_type: true, } } } +#[derive(Clone)] pub struct PatDisplay<'a> { env: &'a GlobalEnv, pat: &'a Pattern, fun_env: Option>, - verbose: bool, + show_type: bool, } impl<'a> PatDisplay<'a> { + fn set_show_type(self, show_type: bool) -> Self { + Self { show_type, ..self } + } + fn type_ctx(&self) -> TypeDisplayContext<'a> { if let Some(fe) = &self.fun_env { fe.get_type_display_ctx() @@ -2118,16 +2129,16 @@ impl<'a> PatDisplay<'a> { fn fmt_patterns(&self, f: &mut Formatter<'_>, patterns: &[Pattern]) -> Result<(), Error> { if let Some(first) = patterns.first() { - first.display_cont(self).fmt_pattern(f, false)?; + first.display_cont(self).fmt_pattern(f)?; for pat in patterns.iter().skip(1) { write!(f, ", ")?; - pat.display_cont(self).fmt_pattern(f, false)?; + pat.display_cont(self).fmt_pattern(f)?; } } Ok(()) } - fn fmt_pattern(&self, f: &mut Formatter<'_>, show_type: bool) -> Result<(), Error> { + fn fmt_pattern(&self, f: &mut Formatter<'_>) -> Result<(), Error> { use Pattern::*; let node_id = self.pat.node_id(); let node_type = self.env.get_node_type(node_id); @@ -2135,13 +2146,7 @@ impl<'a> PatDisplay<'a> { let mut showed_type = false; match self.pat { Var(_, sym) => { - write!( - f, - "{}: {}", - sym.display(self.env.symbol_pool()), - node_type.display(type_ctx) - )?; - showed_type = true; + write!(f, "{}", sym.display(self.env.symbol_pool()))?; }, Wildcard(_) => write!(f, "_")?, Tuple(_, pattern_vec) => { @@ -2149,7 +2154,7 @@ impl<'a> PatDisplay<'a> { self.fmt_patterns(f, pattern_vec)?; write!(f, ")")? }, - Struct(_, struct_qfid, pattern_vec) => { + Struct(_, struct_qfid, variant, pattern_vec) => { let inst_str = if !struct_qfid.inst.is_empty() { format!( "<{}>", @@ -2164,18 +2169,15 @@ impl<'a> PatDisplay<'a> { }; let struct_env = self.env.get_struct(struct_qfid.to_qualified_id()); let field_names = struct_env.get_fields().map(|f| f.get_name()); + let pool = self.env.symbol_pool(); let args_str = pattern_vec .iter() .zip(field_names) .map(|(pat, sym)| { - let field_name = self.env.symbol_pool().string(sym); - let pattern_str = pat.to_string(self.env, type_ctx); + let field_name = pool.string(sym); + let pattern_str = pat.display_cont(self).set_show_type(false).to_string(); if &pattern_str != field_name.as_ref() { - format!( - "{}: {}", - field_name.as_ref(), - pat.to_string(self.env, type_ctx) - ) + format!("{}: {}", field_name.as_ref(), pattern_str) } else { pattern_str } @@ -2183,15 +2185,17 @@ impl<'a> PatDisplay<'a> { .join(", "); write!( f, - "{}{}{{ {} }}", + "{}{}{}{{ {} }}", struct_env.get_full_name_str(), + optional_variant_suffix(pool, variant), inst_str, args_str - )? + )?; + showed_type = true }, Error(_) => write!(f, "Pattern::Error")?, } - if show_type && !showed_type { + if self.show_type && !showed_type { write!(f, ": {}", node_type.display(type_ctx)) } else { Ok(()) @@ -2199,9 +2203,9 @@ impl<'a> PatDisplay<'a> { } } -impl<'a> Display for PatDisplay<'a> { +impl<'a> fmt::Display for PatDisplay<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { - self.fmt_pattern(f, true) + self.fmt_pattern(f) } } @@ -2644,7 +2648,7 @@ impl ExpData { // Technically pure, but we don't want to eliminate it. is_pure = false; }, - Block(..) | IfElse(..) => {}, // depends on contents + Block(..) | IfElse(..) | Match(..) => {}, // depends on contents Return(..) => { is_pure = false; }, @@ -3022,6 +3026,19 @@ impl<'a> fmt::Display for ExpDisplay<'a> { indent(else_exp.display_cont(self)) ) }, + Match(_, discriminator, arms) => { + writeln!(f, "match ({}) {{", discriminator.display_cont(self))?; + for arm in arms { + write!(f, " {}", indent(arm.pattern.display_for_exp(self)))?; + if let Some(c) = &arm.condition { + write!(f, " if {}", c.display_cont(self))? + } + writeln!(f, " => {{")?; + writeln!(f, " {}", indent(indent(arm.body.display_cont(self))))?; + writeln!(f, " }}")? + } + writeln!(f, "}}") + }, Sequence(_, es) => { for (i, e) in es.iter().enumerate() { if i > 0 { @@ -3205,7 +3222,12 @@ impl<'a> fmt::Display for OperationDisplay<'a> { } Ok(()) }, - Pack(mid, sid) => write!(f, "pack {}", self.struct_str(mid, sid)), + Pack(mid, sid, variant) => write!( + f, + "pack {}{}", + self.struct_str(mid, sid), + optional_variant_suffix(self.env.symbol_pool(), variant) + ), Select(mid, sid, fid) => { write!(f, "select {}", self.field_str(mid, sid, fid)) }, @@ -3321,6 +3343,14 @@ impl<'a> fmt::Display for EnvDisplay<'a, Spec> { } } +fn optional_variant_suffix(pool: &SymbolPool, variant: &Option) -> String { + if let Some(v) = variant { + format!("::{}", v.display(pool)) + } else { + String::new() + } +} + #[cfg(test)] mod tests { use crate::{ 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 5a027f100b5fb..7c3e6c33d5ba7 100644 --- a/third_party/move/move-model/src/builder/exp_builder.rs +++ b/third_party/move/move-model/src/builder/exp_builder.rs @@ -4,17 +4,20 @@ use crate::{ ast::{ - AccessSpecifier, Address, AddressSpecifier, Exp, ExpData, ModuleName, Operation, Pattern, - QualifiedSymbol, QuantKind, ResourceSpecifier, RewriteResult, Spec, TempIndex, Value, + AccessSpecifier, Address, AddressSpecifier, Exp, ExpData, MatchArm, ModuleName, Operation, + Pattern, QualifiedSymbol, QuantKind, ResourceSpecifier, RewriteResult, Spec, TempIndex, + Value, }, builder::{ - model_builder::{AnyFunEntry, ConstEntry, EntryVisibility, LocalVarEntry, StructEntry}, + model_builder::{ + AnyFunEntry, ConstEntry, EntryVisibility, LocalVarEntry, StructEntry, StructLayout, + }, module_builder::{ModuleBuilder, SpecBlockContext}, }, metadata::LanguageVersion, model::{ - FieldId, GlobalEnv, Loc, ModuleId, NodeId, Parameter, QualifiedId, QualifiedInstId, - SpecFunId, StructId, TypeParameter, TypeParameterKind, + FieldData, FieldId, GlobalEnv, Loc, ModuleId, NodeId, Parameter, QualifiedId, + QualifiedInstId, SpecFunId, StructId, TypeParameter, TypeParameterKind, }, symbol::{Symbol, SymbolPool}, ty::{ @@ -27,7 +30,7 @@ use codespan_reporting::diagnostic::Severity; use itertools::Itertools; use move_binary_format::file_format::{self, AbilitySet}; use move_compiler::{ - expansion::{ast as EA, ast::SequenceItem}, + expansion::ast as EA, hlir::ast as HA, naming::ast as NA, parser::{ast as PA, ast::CallKind}, @@ -97,7 +100,7 @@ pub enum ExpPlaceholder { /// Locals at the point of the spec block, with an optional assigned TempIndex. locals: BTreeMap)>, }, - /// If attached to an expression, a placeholder for an field selection for which the full + /// If attached to an expression, a placeholder for a field selection for which the full /// structure type was not known yet, but should be at the end of function body checking. FieldSelectInfo { struct_ty: Type, field_name: Symbol }, /// If attached to an expression, a placeholder for a receiver call which has not been @@ -747,7 +750,10 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo impl<'env, 'builder, 'module_builder> UnificationContext for ExpTranslator<'env, 'builder, 'module_builder> { - fn get_struct_field_map(&self, id: &QualifiedInstId) -> BTreeMap { + fn get_struct_field_map( + &self, + id: &QualifiedInstId, + ) -> (BTreeMap, bool) { self.parent.parent.lookup_struct_fields(id) } @@ -1169,7 +1175,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo }); let maccess = sp( specifier.loc, - EA::ModuleAccess_::ModuleAccess(mident, *resource), + EA::ModuleAccess_::ModuleAccess(mident, *resource, None), ); let sym = self.parent.module_access_to_qualified(&maccess); if let Type::Struct(mid, sid, _) = self.parent.parent.lookup_type(&loc, &sym) { @@ -1469,7 +1475,9 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo ExpData::Call(id, Operation::Vector, elems) }, EA::Exp_::Call(maccess, kind, type_params, args) => { - if *kind == CallKind::Macro { + if !self.parent.check_no_variant(maccess) { + self.new_error_exp() + } else if *kind == CallKind::Macro { self.translate_macro_call(maccess, type_params, args, expected_type, context) } else { // Need to make a &[&Exp] out of args. @@ -1486,7 +1494,18 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo } }, EA::Exp_::Pack(maccess, generics, fields) => { - self.translate_pack(&loc, maccess, generics, fields, expected_type, context) + if let Some(exp) = self.translate_pack( + &loc, + maccess, + generics, + Some(fields), + expected_type, + context, + ) { + exp + } else { + self.new_error_exp() + } }, EA::Exp_::IfElse(cond, then, else_) => { let try_freeze_if_else = |et: &mut ExpTranslator, @@ -1526,6 +1545,9 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo let id = self.new_node_id_with_type_loc(&rty, &loc); ExpData::IfElse(id, cond.into_exp(), then.into_exp(), else_.into_exp()) }, + EA::Exp_::Match(discriminator, arms) => { + self.translate_match(loc, context, expected_type, discriminator, arms) + }, EA::Exp_::While(cond, body) => { let cond = self.translate_exp(cond, &Type::new_prim(PrimitiveType::Bool)); let body_type = self.check_type(&loc, &Type::unit(), expected_type, context); @@ -1962,7 +1984,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo } }, &mut |pat, _entering_scope| match pat { - Pattern::Struct(sid, std, patterns) => { + Pattern::Struct(sid, std, variant, patterns) => { let mut new_inst = vec![]; for ty in &std.inst { let nty = subs.specialize(ty); @@ -1970,7 +1992,8 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo } let mut new_std = std.clone(); new_std.inst = new_inst; - let new_pat = Pattern::Struct(*sid, new_std.clone(), patterns.clone()); + let new_pat = + Pattern::Struct(*sid, new_std.clone(), *variant, patterns.clone()); Some(new_pat) }, _ => None, @@ -2136,6 +2159,72 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo std::mem::take(&mut self.parent.inline_spec_builder) } + /// Translates a match expression. + fn translate_match( + &mut self, + loc: Loc, + context: &ErrorMessageContext, + expected_type: &Type, + discriminator: &EA::Exp, + arms: &[Spanned<(EA::LValueList, Option, EA::Exp)>], + ) -> ExpData { + let (discr_ty, discr_exp) = self.translate_exp_free(discriminator); + // Translate all arms, and compute the joined type of the arms. If + // any of the arms produces an immutable reference, the joined type + // will also be immutable. + let mut joined_type = self.subs.specialize(expected_type); + let mut translate_arms = vec![]; + for arm in arms { + // Translate the arms lvalue list into a pattern + let pattern = self.translate_lvalue_list( + &arm.value.0, + &discr_ty, + // The discriminator is assigned to the pattern, so like in a binding, + // it is allowed to be widened to the pattern type. + WideningOrder::RightToLeft, + false, + &ErrorMessageContext::Binding, + ); + // Declare the variables in the pattern + self.enter_scope(); + self.define_locals_of_pat(&pattern); + // Translate the condition, if present. + let condition = arm.value.1.as_ref().map(|c| { + self.translate_exp(c, &Type::new_prim(PrimitiveType::Bool)) + .into_exp() + }); + // Translate the body. + let body = self.translate_exp_in_context(&arm.value.2, &joined_type, context); + let body_ty = self + .subs + .specialize(&self.env().get_node_type(body.node_id())); + self.exit_scope(); + translate_arms.push(MatchArm { + loc: self.to_loc(&arm.loc), + pattern, + condition, + body: body.into_exp(), + }); + // Refine the joined type from mutable to immutable if needed. + joined_type = match (self.subs.specialize(&joined_type), body_ty) { + ( + Type::Reference(ReferenceKind::Mutable, _), + Type::Reference(ReferenceKind::Immutable, ty), + ) => Type::Reference(ReferenceKind::Immutable, ty), + (ty, _) => ty, + }; + } + // Now go over the arms again and freeze mutable references as needed. + if joined_type.is_immutable_reference() { + for arm in translate_arms.iter_mut() { + let ty = self.env().get_node_type(arm.body.node_id()); + arm.body = self.try_freeze(&joined_type, &ty, arm.body.clone()); + } + } + let id = self.new_node_id_with_type_loc(&joined_type, &loc); + ExpData::Match(id, discr_exp.into_exp(), translate_arms) + } + fn translate_lvalue_list( &mut self, list: &EA::LValueList, @@ -2216,108 +2305,232 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo ) -> Pattern { let loc = &self.to_loc(&lv.loc); match &lv.value { - EA::LValue_::Var(maccess, None) => { - let name = match &maccess.value { - EA::ModuleAccess_::Name(n) => n, - EA::ModuleAccess_::ModuleAccess(_, n) => n, - }; + EA::LValue_::Var(maccess, generics) => { let mut id = self.new_node_id_with_type_loc(expected_type, loc); - if name.value.as_str() == "_" { - let specialized_expected_type = self.subs.specialize(expected_type); - if let Type::Tuple(tys) = specialized_expected_type { - if tys.len() != 1 { - self.error(loc, &context.arity_mismatch(false, tys.len(), 1)); - return self.new_error_pat(loc); - } - } - Pattern::Wildcard(id) - } else { - let name = self.symbol_pool().make(&name.value); - if match_locals { - if let Some(local_ty) = self - .lookup_local(name, false) - .map(|local| local.type_.clone()) - { - // For a pattern where expected type is mutable reference and the original type is immutable ref - // the result type should still be immutable - if local_ty.is_immutable_reference() - && expected_type.is_mutable_reference() + match maccess.value { + EA::ModuleAccess_::Name(n) if n.value.as_str() == "_" => { + self.add_constraint_and_report( + loc, + &ErrorMessageContext::General, + expected_type, + Constraint::NoTuple, + None, + ); + Pattern::Wildcard(id) + }, + EA::ModuleAccess_::Name(n) => { + let name = self.symbol_pool().make(&n.value); + if match_locals { + if let Some(local_ty) = self + .lookup_local(name, false) + .map(|local| local.type_.clone()) { - id = self.new_node_id_with_type_loc(&local_ty, loc); + // For a pattern where expected type is mutable reference and the original type is immutable ref + // the result type should still be immutable + if local_ty.is_immutable_reference() + && expected_type.is_mutable_reference() + { + id = self.new_node_id_with_type_loc(&local_ty, loc); + } + self.check_type_with_order( + expected_order, + loc, + &local_ty, + expected_type, + context, + ); + } else { + self.error( + loc, + &format!("undeclared `{}`", name.display(self.symbol_pool())), + ) } - self.check_type_with_order( - expected_order, - loc, - &local_ty, - expected_type, - context, - ); + } + Pattern::Var(id, name) + }, + _ => { + // Translate as a struct pattern with no arguments + if let Some(pat) = self.translate_lvalue_unpack( + expected_type, + expected_order, + match_locals, + context, + loc, + maccess, + generics, + None, + ) { + pat } else { - self.error( - loc, - &format!("undeclared `{}`", name.display(self.symbol_pool())), - ) + self.new_error_pat(loc) } - } - Pattern::Var(id, name) + }, } }, EA::LValue_::Unpack(maccess, generics, args) => { - // Check whether the requested type is a reference. If so, we remember this and - // the target type of the reference. The reference expectation is pushed down - // to the arguments of the unpack if needed. - let (ref_expected, expected_type) = if let Type::Reference(kind, ty) = expected_type - { - (Some(*kind), ty.as_ref().clone()) - } else { - (None, expected_type.clone()) - }; - if let Some((struct_id, mut args)) = self.translate_lvalue_fields( - loc, - maccess, - generics, - args, - ref_expected, + if let Some(pat) = self.translate_lvalue_unpack( + expected_type, expected_order, match_locals, context, + loc, + maccess, + generics, + Some(args), ) { - if args.is_empty() { - // TODO: The v1 move compiler inserts a dummy field with the value of false - // for structs with no fields. We simulate this here for now. - let id = self - .new_node_id_with_type_loc(&Type::new_prim(PrimitiveType::Bool), loc); - args.push(Pattern::Wildcard(id)) - } - let ty = struct_id.to_type(); - let ty = self.check_type_with_order( - expected_order, - loc, - &ty, - &expected_type, - context, - ); - let node_ty = if let Some(kind) = ref_expected { - Type::Reference(kind, Box::new(ty.clone())) - } else { - ty.clone() - }; - let id = self.new_node_id_with_type_loc(&node_ty, loc); - let mut std = struct_id; - if let Type::Struct(_, _, types) = ty { - std.inst = types; - } - Pattern::Struct(id, std, args) + pat } else { - // Error reported self.new_error_pat(loc) } }, + } + } + + fn translate_lvalue_unpack( + &mut self, + expected_type: &Type, + expected_order: WideningOrder, + match_locals: bool, + context: &ErrorMessageContext, + loc: &Loc, + maccess: &EA::ModuleAccess, + generics: &Option>, + fields: Option<&EA::Fields>, + ) -> Option { + // Check whether the requested type is a reference. If so, we remember this and + // the target type of the reference. The reference expectation is pushed down + // to the arguments of the unpack if needed. + let (ref_expected, expected_type) = + if let Type::Reference(kind, ty) = self.subs.specialize(expected_type) { + (Some(kind), *ty) + } else { + (None, expected_type.clone()) + }; + + // Determine whether expected type has variants + let variant_struct_info = if let Type::Struct(mid, sid, _) = &expected_type { + let entry = self.parent.parent.lookup_struct_entry(mid.qualified(*sid)); + if let StructLayout::Variants(variants) = &entry.layout { + Some(( + entry, + variants.iter().map(|v| v.name).collect::>(), + )) + } else { + None + } + } else { + None + }; + + // Resolve reference to struct. + let struct_name_loc = self.to_loc(&maccess.loc); + let (struct_name, variant, struct_entry) = match (&maccess.value, variant_struct_info) { + (EA::ModuleAccess_::Name(name), Some((struct_entry, _variants))) => { + // Simple name and we could infer from expected type that it is a struct with + // variants. + let variant = self.symbol_pool().make(name.value.as_str()); + let struct_name = self + .parent + .parent + .get_struct_name(struct_entry.module_id.qualified(struct_entry.struct_id)); + (struct_name.clone(), Some(variant), struct_entry.clone()) + }, _ => { - self.error(loc, "unsupported language construct"); - self.new_error_pat(loc) + let (struct_name, variant) = + self.parent.module_access_to_qualified_with_variant(maccess); + let struct_name_loc = self.to_loc(&maccess.loc); + let struct_entry = + self.get_struct_report_undeclared(&struct_name, &struct_name_loc)?; + (struct_name, variant, struct_entry) }, + }; + + // Resolve type instantiation. + let instantiation = self.make_instantiation_or_report( + loc, + true, + struct_name.symbol, + &struct_entry.type_params, + generics, + )?; + + // If this is a struct variant, check whether it exists. + if let Some(v) = variant { + if !self.check_variant_declared(&struct_name, &struct_entry, &struct_name_loc, v) { + return None; + } } + + // Process argument list + let mut args = BTreeMap::new(); + let field_decls = self + .get_field_decls_for_pack_unpack( + &struct_entry, + &struct_name, + &struct_name_loc, + variant, + )? + .clone(); + if let Some(fields) = fields { + // Check whether all fields are covered. + self.check_missing_or_undeclared_fields(loc, struct_name, &field_decls, fields)?; + // Translate fields + for (_, name, (_, value)) in fields.iter() { + let field_name = self.symbol_pool().make(name); + if let Some(field_data) = field_decls.get(&field_name) { + let field_ty = field_data.ty.instantiate(&instantiation); + let expected_field_ty = if let Some(kind) = ref_expected { + Type::Reference(kind, Box::new(field_ty.clone())) + } else { + field_ty.clone() + }; + let translated = self.translate_lvalue( + value, + &expected_field_ty, + expected_order, + match_locals, + context, + ); + args.insert(field_data.offset, translated); + } + } + } else if !field_decls.is_empty() { + self.error( + loc, + &format!( + "no arguments provided for unpack, expected {}", + field_decls.len() + ), + ) + } + + let struct_id = struct_entry + .module_id + .qualified_inst(struct_entry.struct_id, instantiation); + let mut args = args + .into_iter() + .sorted_by_key(|(i, _)| *i) + .map(|(_, value)| value) + .collect_vec(); + if variant.is_none() && args.is_empty() { + // The v1 move compiler inserts a dummy field with the value of false + // for structs with no fields. We simulate this here for now. + let id = self.new_node_id_with_type_loc(&Type::new_prim(PrimitiveType::Bool), loc); + args.push(Pattern::Wildcard(id)) + } + let ty = struct_id.to_type(); + let ty = self.check_type_with_order(expected_order, loc, &ty, &expected_type, context); + let node_ty = if let Some(kind) = ref_expected { + Type::Reference(kind, Box::new(ty.clone())) + } else { + ty.clone() + }; + let id = self.new_node_id_with_type_loc(&node_ty, loc); + let mut std = struct_id; + if let Type::Struct(_, _, types) = ty { + std.inst = types; + } + Some(Pattern::Struct(id, std, variant, args)) } fn new_error_pat(&mut self, loc: &Loc) -> Pattern { @@ -2495,7 +2708,8 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo } // Treat this as a call to a global function. - let (module_name, name) = self.parent.module_access_to_parts(maccess); + self.parent.check_no_variant(maccess); + let (module_name, name, _) = self.parent.module_access_to_parts(maccess); // Process `old(E)` scoping let is_old = @@ -2773,7 +2987,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo fn translate_seq_items( &mut self, loc: &Loc, - items: &[&SequenceItem], + items: &[&EA::SequenceItem], expected_type: &Type, context: &ErrorMessageContext, ) -> ExpData { @@ -3100,7 +3314,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo let expected_type = &self.subs.specialize(expected_type); if let Type::Struct(mid, sid, inst) = self.subs.specialize(expected_type) { // field_map contains the instantiated field type. - let field_map = self + let (field_map, _) = self .parent .parent .lookup_struct_fields(&mid.qualified_inst(sid, inst)); @@ -3724,40 +3938,118 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo loc: &Loc, maccess: &EA::ModuleAccess, generics: &Option>, - fields: &EA::Fields, + fields: Option<&EA::Fields>, expected_type: &Type, context: &ErrorMessageContext, - ) -> ExpData { - if let Some((struct_id, bindings, field_args)) = - self.translate_exp_fields(loc, maccess, generics, fields) - { - let struct_ty = struct_id.to_type(); - let struct_ty = self.check_type(loc, &struct_ty, expected_type, context); - let mut field_args = field_args.into_iter().map(|e| e.into_exp()).collect_vec(); - if field_args.is_empty() { - // The move compiler inserts a dummy field with the value of false - // for structs with no fields. This is also what we find in the - // Model metadata (i.e. a field `dummy_field`). We simulate this here - // for now, though it would be better to remove it everywhere as it - // can be confusing to users. However, its currently hard to do this, - // because a user could also have defined the `dummy_field`. - let id = self.new_node_id_with_type_loc(&BOOL_TYPE, loc); - field_args.push(ExpData::Value(id, Value::Bool(false)).into_exp()); + ) -> Option { + // Resolve reference to struct + let (struct_name, variant) = self.parent.module_access_to_qualified_with_variant(maccess); + let struct_name_loc = self.to_loc(&maccess.loc); + let struct_entry = self.get_struct_report_undeclared(&struct_name, &struct_name_loc)?; + + // Resolve type instantiation + let instantiation = self.make_instantiation_or_report( + &self.to_loc(&maccess.loc), + true, + struct_name.symbol, + &struct_entry.type_params, + generics, + )?; + + // If this is a struct variant, check whether it exists. + if let Some(v) = variant { + if !self.check_variant_declared(&struct_name, &struct_entry, &struct_name_loc, v) { + return None; } - let id = self.new_node_id_with_type_loc(&struct_ty, loc); - self.set_node_instantiation(id, struct_id.inst); - let body = ExpData::Call( - id, - Operation::Pack(struct_id.module_id, struct_id.id), - field_args, - ); - bindings.into_iter().rev().fold(body, |acc, (x, e)| { - self.new_bind_exp(loc, x, Some(e.into_exp()), acc.into_exp()) - }) - } else { - // Error already reported - self.new_error_exp() } + + // Process argument list. + // given pack{ f_p(1): e_1, ... }, where p is a permutation of the fields + // compute: + // - the struct id of S + // - (x_1, e_1), (x_2, e_2), ... + // - arg_1, arg_2, ... + // such that the transformed code + // { let x_1 = e_1; let x_2 = e_2; ...; pack(arg1, arg2, ...) } + // is equivalent. + let mut bindings = BTreeMap::new(); + let mut args = BTreeMap::new(); + let field_decls = self + .get_field_decls_for_pack_unpack( + &struct_entry, + &struct_name, + &struct_name_loc, + variant, + )? + .clone(); + if let Some(fields) = fields { + self.check_missing_or_undeclared_fields(loc, struct_name, &field_decls, fields)?; + let in_order_fields = self.in_order_fields(&field_decls, fields); + for (_, name, (exp_idx, field_exp)) in fields.iter() { + let (def_idx, field_name, translated_field_exp) = + self.translate_exp_field(&field_decls, name, &instantiation, field_exp); + if in_order_fields.contains(&def_idx) { + args.insert(def_idx, translated_field_exp); + } else { + // starts with $ for internal generated vars + let var_name = self + .symbol_pool() + .make(&format!("${}", field_name.display(self.symbol_pool()))); + // the x_i to be used in the let bindings + let var = Pattern::Var(translated_field_exp.node_id(), var_name); + // the x_i to be used in the pack exp + let arg = ExpData::LocalVar(translated_field_exp.node_id(), var_name); + args.insert(def_idx, arg); + bindings.insert(*exp_idx, (var, translated_field_exp)); + } + } + } else if !field_decls.is_empty() { + self.error( + loc, + &format!( + "no arguments provided for pack, expected {}", + field_decls.len() + ), + ) + } + let struct_id = struct_entry + .module_id + .qualified_inst(struct_entry.struct_id, instantiation); + let bindings = bindings + .into_iter() + .sorted_by_key(|(i, _)| *i) + .map(|(_, value)| value) + .collect_vec(); + let args = args + .into_iter() + .sorted_by_key(|(i, _)| *i) + .map(|(_, value)| value) + .collect_vec(); + + let struct_ty = struct_id.to_type(); + let struct_ty = self.check_type(loc, &struct_ty, expected_type, context); + let mut field_args = args.into_iter().map(|e| e.into_exp()).collect_vec(); + if variant.is_none() && field_args.is_empty() { + // The move compiler inserts a dummy field with the value of false + // for structs with no fields. This is also what we find in the + // Model metadata (i.e. a field `dummy_field`). We simulate this here + // for now, though it would be better to remove it everywhere as it + // can be confusing to users. However, its currently hard to do this, + // because a user could also have defined the `dummy_field`. + let id = self.new_node_id_with_type_loc(&BOOL_TYPE, loc); + field_args.push(ExpData::Value(id, Value::Bool(false)).into_exp()); + } + let id = self.new_node_id_with_type_loc(&struct_ty, loc); + self.set_node_instantiation(id, struct_id.inst); + let body = ExpData::Call( + id, + Operation::Pack(struct_id.module_id, struct_id.id, variant), + field_args, + ); + // Fold the bindings and the body into result exp + Some(bindings.into_iter().rev().fold(body, |acc, (x, e)| { + self.new_bind_exp(loc, x, Some(e.into_exp()), acc.into_exp()) + })) } fn get_struct_with_diag( @@ -3786,23 +4078,66 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo ) } + fn check_variant_declared( + &mut self, + struct_name: &QualifiedSymbol, + struct_entry: &StructEntry, + loc: &Loc, + variant: Symbol, + ) -> bool { + match &struct_entry.layout { + StructLayout::Variants(variants) => { + if variants.iter().any(|v| v.name == variant) { + return true; + } + self.error( + loc, + &format!( + "variant `{}` not declared in `{}`", + variant.display(self.symbol_pool()), + struct_name.display(self.env()) + ), + ) + }, + StructLayout::Singleton(_) | StructLayout::None => self.error( + loc, + &format!( + "struct `{}` has no variants", + struct_name.display(self.env()) + ), + ), + } + false + } + fn get_field_decls_for_pack_unpack<'a>( &'a mut self, s: &'a StructEntry, struct_name: &QualifiedSymbol, struct_name_loc: &Loc, - ) -> Option<&BTreeMap> { - if let Some(field_decls) = &s.fields { - Some(field_decls) - } else { - self.error( - struct_name_loc, - &format!( - "native struct `{}` cannot be packed or unpacked", - struct_name.display(self.env()) - ), - ); - None + variant: Option, + ) -> Option<&BTreeMap> { + match (&s.layout, variant) { + (StructLayout::Singleton(fields), None) => Some(fields), + (StructLayout::Variants(variants), Some(name)) => { + if let Some(variant) = variants.iter().find(|v| v.name == name) { + Some(&variant.fields) + } else { + self.error( + struct_name_loc, + &format!( + "struct `{}` has no variant named `{}`", + struct_name.display(self.env()), + name.display(self.symbol_pool()) + ), + ); + None + } + }, + _ => { + self.bug(struct_name_loc, "inconsistent struct definition"); + None + }, } } @@ -3810,7 +4145,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo &mut self, loc: &Loc, struct_name: QualifiedSymbol, - field_decls: &BTreeMap, + field_decls: &BTreeMap, fields: &EA::Fields, ) -> Option<()> { let mut succeed = true; @@ -3823,13 +4158,13 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo ); for (name_loc, name, (_, _)) in fields.iter() { let field_name = self.symbol_pool().make(name); - if let Some((_, _, _)) = field_decls.get(&field_name) { + if field_decls.contains_key(&field_name) { fields_not_covered.remove(&field_name); } else { self.error( &self.to_loc(&name_loc), &format!( - "field `{}` not declared in struct `{}`", + "field `{}` not declared in `{}`", field_name.display(self.symbol_pool()), struct_name.display(self.env()) ), @@ -3841,7 +4176,12 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo self.error( loc, &format!( - "missing fields {}", + "missing field{} {}", + if fields_not_covered.len() == 1 { + "" + } else { + "s" + }, fields_not_covered .iter() .map(|n| format!("`{}`", n.display(self.symbol_pool()))) @@ -3860,7 +4200,7 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo // return the indices of fields that can be left in place during transforming pack exprs fn in_order_fields( &mut self, - field_decls: &BTreeMap, + field_decls: &BTreeMap, fields: &EA::Fields, ) -> BTreeSet { // def_indices in evaluation order @@ -3868,8 +4208,8 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo .iter() .map(|(_, name, (exp_idx, _))| { let field_name = self.symbol_pool().make(name); - let (_, def_idx, _) = field_decls.get(&field_name).unwrap(); - (*exp_idx, *def_idx) + let field_data = field_decls.get(&field_name).unwrap(); + (*exp_idx, field_data.offset) }) .sorted_by_key(|(exp_idx, _)| *exp_idx) .map(|(_, def_idx)| def_idx) @@ -3896,153 +4236,16 @@ impl<'env, 'translator, 'module_translator> ExpTranslator<'env, 'translator, 'mo // - translated field exp fn translate_exp_field( &mut self, - field_decls: &BTreeMap, + field_decls: &BTreeMap, field_name: &move_symbol_pool::Symbol, instantiation: &[Type], field_exp: &EA::Exp, ) -> (usize, Symbol, ExpData) { let field_name = self.symbol_pool().make(field_name); - let (_, def_idx, field_ty) = field_decls.get(&field_name).unwrap(); - let field_ty = field_ty.instantiate(instantiation); + let field_data = field_decls.get(&field_name).unwrap(); + let field_ty = field_data.ty.instantiate(instantiation); let translated_field_exp = self.translate_exp(field_exp, &field_ty); - (*def_idx, field_name, translated_field_exp) - } - - // given pack{ f_p(1): e_1, ... }, where p is a permutation of the fields - // return: - // - the struct id of S - // - (x_1, e_1), (x_2, e_2), ... - // - arg_1, arg_2, ... - // such that the transformed code - // { let x_1 = e_1; let x_2 = e_2; ...; pack(arg1, arg2, ...) } - // is equivalent. - fn translate_exp_fields( - &mut self, - loc: &Loc, - maccess: &EA::ModuleAccess, - generics: &Option>, - fields: &EA::Fields, - ) -> Option<( - QualifiedInstId, - Vec<(Pattern, ExpData)>, - Vec, - )> { - let struct_name = self.parent.module_access_to_qualified(maccess); - let struct_name_loc = self.to_loc(&maccess.loc); - let struct_entry = self.get_struct_report_undeclared(&struct_name, &struct_name_loc)?; - let instantiation = self.make_instantiation_or_report( - &self.to_loc(&maccess.loc), - true, - struct_name.symbol, - &struct_entry.type_params, - generics, - )?; - let field_decls = self - .get_field_decls_for_pack_unpack(&struct_entry, &struct_name, &struct_name_loc)? - .clone(); - - self.check_missing_or_undeclared_fields(loc, struct_name, &field_decls, fields)?; - - let in_order_fields = self.in_order_fields(&field_decls, fields); - // maps i to (x_i, e_i) where i is the expression idx, i.e., idx of the field exp in the pack exp - let mut bindings = BTreeMap::new(); - // maps i to x_i where i is the field definition idx, i.e., idx of the field in the struct definition - let mut args = BTreeMap::new(); - for (_, name, (exp_idx, field_exp)) in fields.iter() { - let (def_idx, field_name, translated_field_exp) = - self.translate_exp_field(&field_decls, name, &instantiation, field_exp); - if in_order_fields.contains(&def_idx) { - args.insert(def_idx, translated_field_exp); - } else { - // starts with $ for internal generated vars - let var_name = self - .symbol_pool() - .make(&format!("${}", field_name.display(self.symbol_pool()))); - // the x_i to be used in the let bindings - let var = Pattern::Var(translated_field_exp.node_id(), var_name); - // the x_i to be used in the pack exp - let arg = ExpData::LocalVar(translated_field_exp.node_id(), var_name); - args.insert(def_idx, arg); - bindings.insert(*exp_idx, (var, translated_field_exp)); - } - } - - let struct_id = struct_entry - .module_id - .qualified_inst(struct_entry.struct_id, instantiation); - let bindings = bindings - .into_iter() - .sorted_by_key(|(i, _)| *i) - .map(|(_, value)| value) - .collect_vec(); - let args = args - .into_iter() - .sorted_by_key(|(i, _)| *i) - .map(|(_, value)| value) - .collect_vec(); - Some((struct_id, bindings, args)) - } - - fn translate_lvalue_fields( - &mut self, - loc: &Loc, - maccess: &EA::ModuleAccess, - generics: &Option>, - fields: &EA::Fields, - // whether matching against a reference value - ref_expected: Option, - // pack { f_i : t_i }, should the type of f_i >: t_i or <: t_i - expected_order: WideningOrder, - // whether the pattern vars are already bound - match_locals: bool, - context: &ErrorMessageContext, - ) -> Option<(QualifiedInstId, Vec)> { - let struct_name = self.parent.module_access_to_qualified(maccess); - let struct_name_loc = self.to_loc(&maccess.loc); - let struct_entry = self.get_struct_report_undeclared(&struct_name, &struct_name_loc)?; - let instantiation = self.make_instantiation_or_report( - &self.to_loc(&maccess.loc), - true, - struct_name.symbol, - &struct_entry.type_params, - generics, - )?; - let field_decls = self - .get_field_decls_for_pack_unpack(&struct_entry, &struct_name, &struct_name_loc)? - .clone(); - - self.check_missing_or_undeclared_fields(loc, struct_name, &field_decls, fields)?; - - let mut args = BTreeMap::new(); - for (_, name, (_, value)) in fields.iter() { - let field_name = self.symbol_pool().make(name); - if let Some((_, def_idx, field_ty)) = field_decls.get(&field_name) { - let field_ty = field_ty.instantiate(&instantiation); - let expected_field_ty = if let Some(kind) = ref_expected { - Type::Reference(kind, Box::new(field_ty.clone())) - } else { - field_ty.clone() - }; - let translated = self.translate_lvalue( - value, - &expected_field_ty, - expected_order, - match_locals, - context, - ); - args.insert(def_idx, translated); - } - } - - let struct_id = struct_entry - .module_id - .qualified_inst(struct_entry.struct_id, instantiation); - let args = args - .into_iter() - .sorted_by_key(|(i, _)| *i) - .map(|(_, value)| value) - .collect_vec(); - Some((struct_id, args)) + (field_data.offset, field_name, translated_field_exp) } fn translate_lambda( 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 1b7874001553d..ce3a841046124 100644 --- a/third_party/move/move-model/src/builder/model_builder.rs +++ b/third_party/move/move-model/src/builder/model_builder.rs @@ -12,8 +12,8 @@ use crate::{ builder::builtins, intrinsics::IntrinsicDecl, model::{ - FunId, FunctionKind, GlobalEnv, Loc, ModuleId, Parameter, QualifiedId, QualifiedInstId, - SpecFunId, SpecVarId, StructId, TypeParameter, + FieldData, FunId, FunctionKind, GlobalEnv, Loc, ModuleId, Parameter, QualifiedId, + QualifiedInstId, SpecFunId, SpecVarId, StructId, TypeParameter, }, symbol::Symbol, ty::{Constraint, Type, TypeDisplayContext}, @@ -119,13 +119,28 @@ pub(crate) struct StructEntry { pub struct_id: StructId, pub type_params: Vec, pub abilities: AbilitySet, - pub fields: Option>, + pub layout: StructLayout, pub attributes: Vec, /// Maps simple function names to the qualified symbols of receiver functions. The /// symbol can be used to index the global function table. pub receiver_functions: BTreeMap, } +#[derive(Debug, Clone)] +pub(crate) enum StructLayout { + Singleton(BTreeMap), + Variants(Vec), + None, +} + +#[derive(Debug, Clone)] +pub(crate) struct StructVariant { + pub loc: Loc, + pub name: Symbol, + pub attributes: Vec, + pub fields: BTreeMap, +} + /// A declaration of a function. #[derive(Debug, Clone)] pub(crate) struct FunEntry { @@ -335,7 +350,7 @@ impl<'env> ModelBuilder<'env> { struct_id: StructId, abilities: AbilitySet, type_params: Vec, - fields: Option>, + layout: StructLayout, ) { let entry = StructEntry { loc, @@ -344,7 +359,7 @@ impl<'env> ModelBuilder<'env> { struct_id, abilities, type_params, - fields, + layout, receiver_functions: BTreeMap::new(), }; self.struct_table.insert(name.clone(), entry); @@ -483,18 +498,37 @@ impl<'env> ModelBuilder<'env> { }) } - /// Looks up the fields of a structure, with instantiated field types. - pub fn lookup_struct_fields(&self, id: &QualifiedInstId) -> BTreeMap { + /// Looks up the fields of a structure, with instantiated field types. Returns empty + /// map if the struct has variants. + pub fn lookup_struct_fields( + &self, + id: &QualifiedInstId, + ) -> (BTreeMap, bool) { let entry = self.lookup_struct_entry(id.to_qualified_id()); - entry - .fields - .as_ref() - .map(|f| { - f.iter() - .map(|(n, (_, _, field_ty))| (*n, field_ty.instantiate(&id.inst))) - .collect::>() - }) - .unwrap_or_default() + let instantiate_fields = |fields: &BTreeMap, common_only: bool| { + fields + .values() + .filter_map(|f| { + if !common_only || f.common_for_variants { + Some((f.name, f.ty.instantiate(&id.inst))) + } else { + None + } + }) + .collect() + }; + match &entry.layout { + StructLayout::Singleton(fields) => (instantiate_fields(fields, false), false), + StructLayout::Variants(variants) => ( + if variants.is_empty() { + BTreeMap::new() + } else { + instantiate_fields(&variants[0].fields, true) + }, + true, + ), + _ => (BTreeMap::new(), false), + } } /// Looks up a receiver function for a given type. 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 3dc8f4ddee9dc..e2f93ff89b8ad 100644 --- a/third_party/move/move-model/src/builder/module_builder.rs +++ b/third_party/move/move-model/src/builder/module_builder.rs @@ -12,12 +12,13 @@ use crate::{ exp_builder::ExpTranslator, model_builder::{ ConstEntry, EntryVisibility, FunEntry, LocalVarEntry, ModelBuilder, - SpecOrBuiltinFunEntry, + SpecOrBuiltinFunEntry, StructLayout, StructVariant, }, }, constant_folder::ConstantFolder, exp_rewriter::{ExpRewriter, ExpRewriterFunctions, RewriteTarget}, intrinsics::process_intrinsic_declaration, + model, model::{ EqIgnoringLoc, FieldData, FieldId, FunId, FunctionData, FunctionKind, Loc, ModuleId, MoveIrLoc, NamedConstantData, NamedConstantId, NodeId, Parameter, SchemaId, SpecFunId, @@ -216,32 +217,63 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> { pub fn module_access_to_parts( &self, access: &EA::ModuleAccess, - ) -> (Option, Symbol) { + ) -> (Option, Symbol, Option) { + let pool = self.symbol_pool(); match &access.value { - EA::ModuleAccess_::Name(n) => (None, self.symbol_pool().make(n.value.as_str())), - EA::ModuleAccess_::ModuleAccess(m, n) => { + EA::ModuleAccess_::Name(n) => (None, pool.make(n.value.as_str()), None), + EA::ModuleAccess_::ModuleAccess(m, n, v) => { let loc = self.parent.to_loc(&m.loc); let addr_bytes = self.parent.resolve_address(&loc, &m.value.address); let module_name = ModuleName::from_address_bytes_and_name( addr_bytes, - self.symbol_pool().make(m.value.module.0.value.as_str()), + pool.make(m.value.module.0.value.as_str()), ); - (Some(module_name), self.symbol_pool().make(n.value.as_str())) + ( + Some(module_name), + pool.make(n.value.as_str()), + v.map(|v| pool.make(v.value.as_str())), + ) }, } } /// Converts a ModuleAccess into a qualified symbol which can be used for lookup of - /// types or functions. + /// types or functions. If the access has a struct variant, an error is produced. pub fn module_access_to_qualified(&self, access: &EA::ModuleAccess) -> QualifiedSymbol { - let (module_name_opt, symbol) = self.module_access_to_parts(access); - let module_name = module_name_opt.unwrap_or_else(|| self.module_name.clone()); - QualifiedSymbol { - module_name, - symbol, + self.check_no_variant(access); + let (qsym, _) = self.module_access_to_qualified_with_variant(access); + qsym + } + + pub fn check_no_variant(&self, maccess: &EA::ModuleAccess) -> bool { + if let EA::ModuleAccess_::ModuleAccess(_, _, Some(n)) = &maccess.value { + self.parent.env.error( + &self.parent.to_loc(&n.loc), + "variants not allowed in this context", + ); + false + } else { + true } } + /// Converts a ModuleAccess into a qualified symbol which can be used for lookup of + /// types or functions, plus an optional struct variant. + pub fn module_access_to_qualified_with_variant( + &self, + access: &EA::ModuleAccess, + ) -> (QualifiedSymbol, Option) { + let (module_name_opt, symbol, variant) = self.module_access_to_parts(access); + let module_name = module_name_opt.unwrap_or_else(|| self.module_name.clone()); + ( + QualifiedSymbol { + module_name, + symbol, + }, + variant, + ) + } + /// Creates a SpecBlockContext from the given SpecBlockTarget. The context is used during /// definition analysis when visiting a schema block member (condition, invariant, etc.). /// This returns None if the SpecBlockTarget cannot be resolved; error reporting happens @@ -360,7 +392,8 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> { None, self.symbol_pool().make(n.value.as_str()), ), - EA::ModuleAccess_::ModuleAccess(mident, n) => { + EA::ModuleAccess_::ModuleAccess(mident, n, _) => { + self.check_no_variant(macc); let addr_bytes = self.parent.resolve_address( &self.parent.to_loc(&macc.loc), &mident.value.address, @@ -458,7 +491,7 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> { struct_id, abilities, type_params, - None, // will be filled in during definition analysis + StructLayout::None, // will be filled in during definition analysis ); } @@ -1149,42 +1182,119 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> { et.set_translate_move_fun(); // translating structs counts as move fun, not spec let loc = et.to_loc(&name.0.loc); et.define_type_params(&loc, &type_params, false); - let fields = match &def.fields { - EA::StructFields::Defined(fields) => { - let mut field_map = BTreeMap::new(); - for (name_loc, field_name_, (idx, ty)) in fields { - let field_loc = et.to_loc(&name_loc); - let field_sym = et.symbol_pool().make(field_name_); - let field_ty = et.translate_type(ty); - let field_ty_loc = et.to_loc(&ty.loc); - for ctr in Constraint::for_field(struct_abilities, &field_ty) { - et.add_constraint_and_report( - &field_ty_loc, - &ErrorMessageContext::General, - &field_ty, - ctr, - Some(ConstraintContext::default().for_field(field_sym)), - ) + // Notice: duplicate field and variant declarations are currently checked in + // the expansion phase, so don't need to do here again. + let layout = + match &def.layout { + EA::StructLayout::Singleton(fields) => StructLayout::Singleton( + Self::build_field_map(&mut et, None, struct_abilities, &loc, fields), + ), + EA::StructLayout::Variants(variants) => { + let mut variant_maps = variants + .iter() + .map(|v| { + let variant_loc = et.to_loc(&v.loc); + let variant_name = et.symbol_pool().make(v.name.0.value.as_str()); + let attributes = et.parent.translate_attributes(&v.attributes); + let variant_fields = Self::build_field_map( + &mut et, + Some(variant_name), + struct_abilities, + &variant_loc, + &v.fields, + ); + StructVariant { + loc: variant_loc, + name: variant_name, + attributes, + fields: variant_fields, + } + }) + .collect_vec(); + // Identify common fields + if !variant_maps.is_empty() { + let mut common_fields = BTreeSet::new(); + let main = &variant_maps[0]; + for field in main.fields.values() { + let mut common = true; + for other in &variant_maps[1..variant_maps.len()] { + if !other + .fields + .values() + .any(|f| f.name == field.name && f.ty == field.ty) + { + common = false; + break; + } + } + if common { + common_fields.insert(field.name); + } + } + for variant_map in variant_maps.iter_mut() { + for field in variant_map.fields.values_mut() { + field.common_for_variants = common_fields.contains(&field.name) + } + } } - field_map.insert(field_sym, (field_loc, *idx, field_ty)); - } - if field_map.is_empty() { - // The legacy Move compiler inserts a `dummy_field: bool` here, we need to - // simulate this behavior for now, as that is what we find in the bytecode - // generated by the compiler. - let field_sym = et.parent.dummy_field_name(); - let field_ty = Type::new_prim(PrimitiveType::Bool); - field_map.insert(field_sym, (loc.clone(), 0, field_ty)); - } - Some(field_map) - }, - EA::StructFields::Native(_) => None, - }; + StructLayout::Variants(variant_maps) + }, + EA::StructLayout::Native(_) => StructLayout::None, + }; self.parent .struct_table .get_mut(&qsym) .expect("struct invalid") - .fields = fields; + .layout = layout; + } + + fn build_field_map( + et: &mut ExpTranslator, + for_variant: Option, + struct_abilities: AbilitySet, + loc: &Loc, + fields: &EA::Fields, + ) -> BTreeMap { + let mut field_map = BTreeMap::new(); + for (name_loc, field_name_, (idx, ty)) in fields { + let field_loc = et.to_loc(&name_loc); + let field_sym = et.symbol_pool().make(field_name_); + let field_ty = et.translate_type(ty); + let field_ty_loc = et.to_loc(&ty.loc); + for ctr in Constraint::for_field(struct_abilities, &field_ty) { + et.add_constraint_and_report( + &field_ty_loc, + &ErrorMessageContext::General, + &field_ty, + ctr, + Some(ConstraintContext::default().for_field(field_sym)), + ) + } + field_map.insert(field_sym, FieldData { + name: field_sym, + loc: field_loc.clone(), + offset: *idx, + variant: for_variant, + common_for_variants: false, + ty: field_ty, + }); + } + if for_variant.is_none() && field_map.is_empty() { + // The legacy Move compiler inserts a `dummy_field: bool` here, we need to + // simulate this behavior for now, as that is what we find in the bytecode + // generated by the v1 compiler and stored on chain. + let field_sym = et.parent.dummy_field_name(); + let field_ty = Type::new_prim(PrimitiveType::Bool); + field_map.insert(field_sym, FieldData { + name: field_sym, + loc: loc.clone(), + offset: 0, + variant: None, + common_for_variants: false, + ty: field_ty, + }); + } + field_map } /// The name of a dummy field the legacy Move compilers adds to zero-arity structs. @@ -1454,7 +1564,7 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> { } }, Some(EA::PragmaValue::Ident(ema)) => match self.module_access_to_parts(ema) { - (None, sym) => PropertyValue::Symbol(sym), + (None, sym, _) => PropertyValue::Symbol(sym), _ => PropertyValue::QualifiedSymbol(self.module_access_to_qualified(ema)), }, }; @@ -1642,17 +1752,17 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> { let mut et = ExpTranslator::new_with_old(self, allows_old); et.define_type_params(loc, &entry.type_params, false); - if let Some(fields) = &entry.fields { + if let StructLayout::Singleton(fields) = &entry.layout { et.enter_scope(); - for (n, (_, _, ty)) in fields { + for f in fields.values() { et.define_local( loc, - *n, - ty.clone(), + f.name, + f.ty.clone(), Some(Operation::Select( entry.module_id, entry.struct_id, - FieldId::new(*n), + FieldId::new(f.name), )), None, ); @@ -3287,21 +3397,36 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> { } // New struct in this module let spec = self.struct_specs.remove(&name.symbol).unwrap_or_default(); - let field_data = if let Some(fields) = &entry.fields { - fields - .iter() - .map(|(name, (loc, offset, ty))| { - (FieldId::new(*name), FieldData { - name: *name, - loc: loc.clone(), - offset: *offset, - ty: ty.clone(), - }) - }) - .collect::>() - } else { - BTreeMap::new() - }; + let mut field_data: BTreeMap = BTreeMap::new(); + let mut variants: BTreeMap = BTreeMap::new(); + match &entry.layout { + StructLayout::Singleton(fields) => { + field_data.extend(fields.values().map(|f| (FieldId::new(f.name), f.clone()))); + }, + StructLayout::Variants(entry_variants) => { + for variant in entry_variants { + variants.insert(variant.name, model::StructVariant { + loc: variant.loc.clone(), + attributes: variant.attributes.clone(), + }); + let pool = self.parent.env.symbol_pool(); + field_data.extend(variant.fields.values().map(|f| { + let variant_field_name = if !f.common_for_variants { + // If the field is not common between variants, we need to qualify + // the name with the variant for a unique id. + pool.make(&FieldId::make_variant_field_id_str( + pool.string(variant.name).as_str(), + pool.string(f.name).as_str(), + )) + } else { + f.name + }; + (FieldId::new(variant_field_name), f.clone()) + })) + } + }, + StructLayout::None => {}, + } let data = StructData { name: name.symbol, loc: entry.loc.clone(), @@ -3311,6 +3436,11 @@ impl<'env, 'translator> ModuleBuilder<'env, 'translator> { abilities: entry.abilities, spec_var_opt: None, field_data, + variants: if variants.is_empty() { + None + } else { + Some(variants) + }, spec: RefCell::new(spec), }; struct_data.insert(StructId::new(name.symbol), data); diff --git a/third_party/move/move-model/src/exp_rewriter.rs b/third_party/move/move-model/src/exp_rewriter.rs index 616a24b3bdc46..2221274b43b5d 100644 --- a/third_party/move/move-model/src/exp_rewriter.rs +++ b/third_party/move/move-model/src/exp_rewriter.rs @@ -4,8 +4,8 @@ use crate::{ ast::{ - Condition, Exp, ExpData, MemoryLabel, Operation, Pattern, Spec, SpecBlockTarget, TempIndex, - Value, + Condition, Exp, ExpData, MatchArm, MemoryLabel, Operation, Pattern, Spec, SpecBlockTarget, + TempIndex, Value, }, model::{GlobalEnv, ModuleId, NodeId, SpecVarId}, symbol::Symbol, @@ -454,6 +454,34 @@ pub trait ExpRewriterFunctions { exp } }, + Match(id, disc, arms) => { + let (id_changed, new_id) = self.internal_rewrite_id(*id); + let (disc_changed, new_disc) = self.internal_rewrite_exp(disc); + let (mut arms_changed, mut new_arms) = (false, vec![]); + for arm in arms { + let (pat_changed, new_pat) = self.internal_rewrite_pattern(&arm.pattern, true); + self.rewrite_enter_block_scope(new_id, &new_pat, &None); + let (cond_changed, new_cond) = if let Some(c) = &arm.condition { + let (c, e) = self.internal_rewrite_exp(c); + (c, Some(e)) + } else { + (false, arm.condition.clone()) + }; + let (body_changed, new_body) = self.internal_rewrite_exp(&arm.body); + new_arms.push(MatchArm { + loc: arm.loc.clone(), + pattern: new_pat, + condition: new_cond, + body: new_body, + }); + arms_changed = arms_changed || pat_changed || cond_changed || body_changed; + } + if id_changed || disc_changed || arms_changed { + Match(*id, new_disc, new_arms).into_exp() + } else { + exp + } + }, Sequence(id, es) => { let (id_changed, new_id) = self.internal_rewrite_id(*id); let changed_vec = self.internal_rewrite_vec(es); @@ -549,14 +577,14 @@ pub trait ExpRewriterFunctions { fn internal_rewrite_pattern(&mut self, pat: &Pattern, creating_scope: bool) -> (bool, Pattern) { match pat { - Pattern::Tuple(_, pattern_vec) | Pattern::Struct(_, _, pattern_vec) => { + Pattern::Tuple(_, pattern_vec) | Pattern::Struct(_, _, _, pattern_vec) => { let (changed, final_pattern_vec) = self.internal_rewrite_pattern_vector(pattern_vec, creating_scope); if changed { let new_pat = match pat { Pattern::Tuple(id, _) => Pattern::Tuple(*id, final_pattern_vec), - Pattern::Struct(id, struct_id, _) => { - Pattern::Struct(*id, struct_id.clone(), final_pattern_vec) + Pattern::Struct(id, struct_id, variant, _) => { + Pattern::Struct(*id, struct_id.clone(), *variant, final_pattern_vec) }, _ => unreachable!(), }; diff --git a/third_party/move/move-model/src/lib.rs b/third_party/move/move-model/src/lib.rs index 58afd021b5c3e..dcc5b81e66fe0 100644 --- a/third_party/move/move-model/src/lib.rs +++ b/third_party/move/move-model/src/lib.rs @@ -111,7 +111,9 @@ pub fn run_model_builder_in_compiler_mode( }, Flags::model_compilation() .set_skip_attribute_checks(skip_attribute_checks) - .set_keep_testing_functions(compile_test_code), + .set_keep_testing_functions(compile_test_code) + .set_lang_v2(language_version != LanguageVersion::V1) + .set_compiler_v2(true), known_attributes, ) } @@ -1029,7 +1031,7 @@ fn downgrade_type_inlining_to_expansion(ty: &N::Type) -> E::Type { E::Type_::Apply(sp(ty.loc, access), rewritten_args) }, N::TypeName_::ModuleType(module_ident, struct_name) => { - let access = E::ModuleAccess_::ModuleAccess(*module_ident, struct_name.0); + let access = E::ModuleAccess_::ModuleAccess(*module_ident, struct_name.0, None); E::Type_::Apply(sp(struct_name.loc(), access), rewritten_args) }, N::TypeName_::Multiple(size) => { @@ -1061,7 +1063,7 @@ fn downgrade_exp_inlining_to_expansion(exp: &T::Exp) -> E::Exp { UnannotatedExp_::Constant(module_ident_opt, name) => { let access = match module_ident_opt { None => E::ModuleAccess_::Name(name.0), - Some(module_ident) => E::ModuleAccess_::ModuleAccess(*module_ident, name.0), + Some(module_ident) => E::ModuleAccess_::ModuleAccess(*module_ident, name.0, None), }; Exp_::Name(sp(name.loc(), access), None) }, @@ -1076,7 +1078,7 @@ fn downgrade_exp_inlining_to_expansion(exp: &T::Exp) -> E::Exp { parameter_types: _, acquires: _, } = call.as_ref(); - let access = E::ModuleAccess_::ModuleAccess(*module, name.0); + let access = E::ModuleAccess_::ModuleAccess(*module, name.0, None); let rewritten_arguments = match downgrade_exp_inlining_to_expansion(arguments).value { Exp_::Unit { .. } => vec![], Exp_::ExpList(exps) => exps, @@ -1192,7 +1194,7 @@ fn downgrade_exp_inlining_to_expansion(exp: &T::Exp) -> E::Exp { ), UnannotatedExp_::Pack(module_ident, struct_name, ty_args, fields) => { - let access = E::ModuleAccess_::ModuleAccess(*module_ident, struct_name.0); + let access = E::ModuleAccess_::ModuleAccess(*module_ident, struct_name.0, None); let rewritten_ty_args = ty_args .iter() .map(downgrade_type_inlining_to_expansion) @@ -1283,7 +1285,7 @@ fn downgrade_lvalue_inlining_to_expansion(val: &T::LValue) -> E::LValue { }, T::LValue_::Unpack(module_ident, struct_name, ty_args, fields) | T::LValue_::BorrowUnpack(_, module_ident, struct_name, ty_args, fields) => { - let access = E::ModuleAccess_::ModuleAccess(*module_ident, struct_name.0); + let access = E::ModuleAccess_::ModuleAccess(*module_ident, struct_name.0, None); let rewritten_ty_args: Vec<_> = ty_args .iter() .map(downgrade_type_inlining_to_expansion) diff --git a/third_party/move/move-model/src/model.rs b/third_party/move/move-model/src/model.rs index 9d0a1cd40a060..84111e114595c 100644 --- a/third_party/move/move-model/src/model.rs +++ b/third_party/move/move-model/src/model.rs @@ -331,6 +331,16 @@ impl FieldId { pub fn symbol(self) -> Symbol { self.0 } + + /// Makes a variant field name unique to a given struct. + /// TODO: Consider making FieldId containing two symbols, but this can be a breaking change + /// to public APIs. + pub fn make_variant_field_id_str( + variant_name: impl AsRef, + field_name: impl AsRef, + ) -> String { + format!("{}.{}", variant_name.as_ref(), field_name.as_ref()) + } } impl SpecFunId { @@ -1616,6 +1626,8 @@ impl GlobalEnv { name: field_name, loc: loc.clone(), offset: 0, + variant: None, + common_for_variants: false, ty, }); StructData { @@ -1627,6 +1639,7 @@ impl GlobalEnv { abilities: AbilitySet::ALL, spec_var_opt: Some(var_id), field_data, + variants: None, spec: RefCell::new(Spec::default()), } } @@ -2310,15 +2323,30 @@ impl GlobalEnv { emitln!(writer, "{}", self.display(&*module_spec)); } for str in module.get_structs() { - emitln!(writer, "struct {} {{", str.get_name().display(spool)); - writer.indent(); - for fld in str.get_fields() { - emitln!( - writer, - "{}: {},", - fld.get_name().display(spool), - fld.get_type().display(tctx) - ); + if str.has_variants() { + emitln!(writer, "enum {} {{", str.get_name().display(spool)); + writer.indent(); + for variant in str.get_variants() { + emit!(writer, "{}", variant.display(spool)); + let fields = str.get_fields_of_variant(variant).collect_vec(); + if !fields.is_empty() { + emitln!(writer, " {"); + writer.indent(); + for fld in fields { + emitln!(writer, "{},", self.dump_field(tctx, &fld)) + } + writer.unindent(); + emitln!(writer, "}") + } else { + emitln!(writer, ",") + } + } + } else { + emitln!(writer, "struct {} {{", str.get_name().display(spool)); + writer.indent(); + for fld in str.get_fields() { + emitln!(writer, "{},", self.dump_field(tctx, &fld)) + } } writer.unindent(); emitln!(writer, "}"); @@ -2356,6 +2384,14 @@ impl GlobalEnv { writer.extract_result() } + fn dump_field(&self, tctx: &TypeDisplayContext, fld: &FieldEnv) -> String { + format!( + "{}: {}", + fld.get_name().display(tctx.env.symbol_pool()), + fld.get_type().display(tctx) + ) + } + pub fn dump_fun(&self, fun: &FunctionEnv) -> String { let tctx = &self.get_type_display_ctx(); let writer = CodeWriter::new(self.internal_loc()); @@ -3213,10 +3249,21 @@ pub struct StructData { /// Field definitions. pub(crate) field_data: BTreeMap, + /// If this structure has variants (i.e. is an `enum`), information about the + /// names of the variants and the location of their declaration. The fields + /// of variants can be identified via the variant name in `FieldData`. + pub(crate) variants: Option>, + /// Associated specification. pub(crate) spec: RefCell, } +#[derive(Debug)] +pub(crate) struct StructVariant { + pub(crate) loc: Loc, + pub(crate) attributes: Vec, +} + #[derive(Debug, Clone)] pub struct StructEnv<'env> { /// Reference to enclosing module. @@ -3364,7 +3411,41 @@ impl<'env> StructEnv<'env> { self.get_abilities().has_key() } - /// Get an iterator for the fields, ordered by offset. + /// Returns true if the struct has variants. + pub fn has_variants(&self) -> bool { + self.data.variants.is_some() + } + + /// Returns an iteration of the variant names in the struct. + pub fn get_variants(&self) -> impl Iterator + 'env { + self.data + .variants + .as_ref() + .expect("struct has variants") + .keys() + .cloned() + } + + /// Returns the location of the variant. + pub fn get_variant_loc(&self, variant: Symbol) -> &Loc { + self.data + .variants + .as_ref() + .and_then(|vars| vars.get(&variant).map(|v| &v.loc)) + .expect("variant defined") + } + + /// Returns the attributes of the variant. + pub fn get_variant_attributes(&self, variant: Symbol) -> &[Attribute] { + self.data + .variants + .as_ref() + .and_then(|vars| vars.get(&variant).map(|v| v.attributes.as_slice())) + .expect("variant defined") + } + + /// Get an iterator for the fields, ordered by offset. Notice if the struct has + /// variants, all fields of all variants are returned. pub fn get_fields(&'env self) -> impl Iterator> { self.data .field_data @@ -3376,7 +3457,24 @@ impl<'env> StructEnv<'env> { }) } - /// Return the number of fields in the struct. + /// Get fields of a particular variant. + pub fn get_fields_of_variant( + &'env self, + variant: Symbol, + ) -> impl Iterator> { + self.data + .field_data + .values() + .filter(|data| data.common_for_variants || data.variant == Some(variant)) + .sorted_by_key(|data| data.offset) + .map(move |data| FieldEnv { + struct_env: self.clone(), + data, + }) + } + + /// Return the number of fields in the struct. Notice of the struct has variants, this + /// includes the sum of all fields in all variants. pub fn get_field_count(&self) -> usize { self.data.field_data.len() } @@ -3464,7 +3562,7 @@ impl<'env> StructEnv<'env> { // ================================================================================================= /// # Field Environment -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct FieldData { /// The name of this field. pub name: Symbol, @@ -3475,6 +3573,12 @@ pub struct FieldData { /// The offset of this field. pub offset: usize, + /// If the field is associated with a variant, the name of that variant. + pub variant: Option, + + /// Whether the field is common between all variants + pub common_for_variants: bool, + /// The type of this field. pub ty: Type, } diff --git a/third_party/move/move-model/src/ty.rs b/third_party/move/move-model/src/ty.rs index d7f3eae679f8c..99ec3a572fcad 100644 --- a/third_party/move/move-model/src/ty.rs +++ b/third_party/move/move-model/src/ty.rs @@ -821,6 +821,11 @@ impl Type { matches!(self, Type::Struct(..)) } + /// Determines whether this is a variant struct + pub fn is_variant_struct(&self, env: &GlobalEnv) -> bool { + self.is_struct() && self.get_struct(env).expect("struct").0.has_variants() + } + /// Determines whether this is the error type. pub fn is_error(&self) -> bool { matches!(self, Type::Error) @@ -1418,8 +1423,13 @@ pub trait AbilityContext { /// A trait to provide context information for unification. pub trait UnificationContext: AbilityContext { - /// Get the field map for a struct, with field types instantiated. - fn get_struct_field_map(&self, id: &QualifiedInstId) -> BTreeMap; + /// Get the field map for a struct, with field types instantiated. Also returns a boolean + /// whether the struct has variants, and therefore the returned fields are those common + /// between variants. + fn get_struct_field_map( + &self, + id: &QualifiedInstId, + ) -> (BTreeMap, bool); /// For a given type, return a receiver style function of the given name, if available. /// If the function is generic it will be instantiated with fresh type variables. @@ -1461,8 +1471,11 @@ impl ReceiverFunctionInstance { pub struct NoUnificationContext; impl UnificationContext for NoUnificationContext { - fn get_struct_field_map(&self, _id: &QualifiedInstId) -> BTreeMap { - BTreeMap::new() + fn get_struct_field_map( + &self, + _id: &QualifiedInstId, + ) -> (BTreeMap, bool) { + (BTreeMap::new(), false) } fn get_receiver_function( @@ -1673,7 +1686,7 @@ impl Substitution { .map(|_| ()) .map_err(|e| e.redirect(loc.clone())), (Constraint::SomeStruct(constr_field_map), Type::Struct(mid, sid, inst)) => { - let field_map = + let (field_map, _) = context.get_struct_field_map(&mid.qualified_inst(*sid, inst.clone())); // The actual struct must have all the fields in the constraint, with same // type. @@ -2837,12 +2850,16 @@ impl TypeUnificationError { Constraint::SomeReference(ty) => { error_context.expected_reference(display_context, ty) }, - Constraint::SomeStruct(field_map) => Self::message_for_struct( - unification_context, - display_context, - field_map, - ty, - ), + Constraint::SomeStruct(field_map) => { + let (main_msg, mut special_hints) = Self::message_for_struct( + unification_context, + display_context, + field_map, + ty, + ); + hints.append(&mut special_hints); + main_msg + }, Constraint::SomeReceiverFunction(name, ..) => { format!( "undeclared receiver function `{}` for type `{}`", @@ -2916,10 +2933,11 @@ impl TypeUnificationError { display_context: &TypeDisplayContext, field_map: &BTreeMap, ty: &Type, - ) -> String { + ) -> (String, Vec) { + let mut hints = vec![]; // Determine why this constraint did not match for better error message - if let Type::Struct(mid, sid, inst) = ty { - let actual_field_map = + let msg = if let Type::Struct(mid, sid, inst) = ty { + let (actual_field_map, has_variants) = unification_context.get_struct_field_map(&mid.qualified_inst(*sid, inst.clone())); let missing_fields = field_map .keys() @@ -2929,10 +2947,19 @@ impl TypeUnificationError { // Primary error is missing fields let fields = Self::print_fields(display_context.env, missing_fields.into_iter().cloned()); + let str = ty.display(display_context); + if has_variants { + hints.push(format!("field must be declared in all variants of `{}` to be accessible without match expression", str)) + } format!( - "{} not declared in struct `{}`", + "{} not declared in {} `{}`", fields, - ty.display(display_context) + if has_variants { + "all variants of" + } else { + "struct" + }, + str ) } else { // Primary error is a type mismatch @@ -2967,7 +2994,8 @@ impl TypeUnificationError { }, ty.display(display_context) ) - } + }; + (msg, hints) } fn print_fields(env: &GlobalEnv, names: impl Iterator) -> String { 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 1fdfae08a6795..fc78a5f833fc4 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 @@ -698,6 +698,10 @@ impl<'env> SpecTranslator<'env> { self.translate_exp_parenthesised(on_false); emit!(self.writer, ")"); }, + ExpData::Match(node_id, ..) => self.error( + &self.env.get_node_loc(*node_id), + "match not yet implemented", + ), ExpData::Invalid(_) => panic!("unexpected error expression"), ExpData::Sequence(_, exp_vec) if exp_vec.len() == 1 => { // Single-element sequence is just a wrapped value. @@ -825,7 +829,10 @@ impl<'env> SpecTranslator<'env> { Operation::SpecFunction(module_id, fun_id, memory_labels) => { self.translate_spec_fun_call(node_id, *module_id, *fun_id, args, memory_labels) }, - Operation::Pack(mid, sid) => self.translate_pack(node_id, *mid, *sid, args), + Operation::Pack(_, _, Some(_)) => { + self.error(&loc, "variants not yet supported"); + }, + Operation::Pack(mid, sid, None) => self.translate_pack(node_id, *mid, *sid, args), Operation::Tuple if args.len() == 1 => self.translate_exp(&args[0]), Operation::Tuple => self.error(&loc, "Tuple not yet supported"), Operation::Select(module_id, struct_id, field_id) => { diff --git a/third_party/move/move-prover/bytecode-pipeline/src/spec_instrumentation.rs b/third_party/move/move-prover/bytecode-pipeline/src/spec_instrumentation.rs index 5c4498a465266..93275129773d8 100644 --- a/third_party/move/move-prover/bytecode-pipeline/src/spec_instrumentation.rs +++ b/third_party/move/move-prover/bytecode-pipeline/src/spec_instrumentation.rs @@ -754,7 +754,7 @@ impl<'a> Instrumenter<'a> { let (rhs_temp, _) = self.builder.emit_let(self.builder.mk_call_with_inst( &ghost_mem_ty, ghost_mem.inst.clone(), - ast::Operation::Pack(ghost_mem.module_id, ghost_mem.id), + ast::Operation::Pack(ghost_mem.module_id, ghost_mem.id, None), vec![new_rhs.clone()], )); diff --git a/third_party/move/move-prover/bytecode-pipeline/src/well_formed_instrumentation.rs b/third_party/move/move-prover/bytecode-pipeline/src/well_formed_instrumentation.rs index 4434653781415..a8f8c8d8a21db 100644 --- a/third_party/move/move-prover/bytecode-pipeline/src/well_formed_instrumentation.rs +++ b/third_party/move/move-prover/bytecode-pipeline/src/well_formed_instrumentation.rs @@ -95,7 +95,7 @@ impl FunctionTargetProcessor for WellFormedInstrumentationProcessor { let mem_val = builder.mk_call_with_inst( &mem_ty, mem.inst.clone(), - Operation::Pack(mem.module_id, mem.id), + Operation::Pack(mem.module_id, mem.id, None), vec![init.clone()], ); let mem_access = builder.mk_call_with_inst( diff --git a/third_party/move/tools/move-cli/tests/build_tests/include_exclude_stdlib/args.exp b/third_party/move/tools/move-cli/tests/build_tests/include_exclude_stdlib/args.exp index 1d60e31b47be4..0381b2823aacf 100644 --- a/third_party/move/tools/move-cli/tests/build_tests/include_exclude_stdlib/args.exp +++ b/third_party/move/tools/move-cli/tests/build_tests/include_exclude_stdlib/args.exp @@ -16,7 +16,7 @@ error[E03002]: unbound module ┌─ ./sources/UseSigner.move:6:5 │ 6 │ signer::address_of(account) - │ ^^^^^^ Unbound module alias 'signer' + │ ^^^^^^ Unbound module or type alias 'signer' Command `-d -v build`: INCLUDING DEPENDENCY MoveStdlib diff --git a/third_party/move/tools/move-cli/tests/build_tests/include_exclude_stdlib/args.v2_exp b/third_party/move/tools/move-cli/tests/build_tests/include_exclude_stdlib/args.v2_exp index c75244dd72bf6..f7e92a4cad5cc 100644 --- a/third_party/move/tools/move-cli/tests/build_tests/include_exclude_stdlib/args.v2_exp +++ b/third_party/move/tools/move-cli/tests/build_tests/include_exclude_stdlib/args.v2_exp @@ -16,7 +16,7 @@ error: unbound module ┌─ ./sources/UseSigner.move:6:5 │ 6 │ signer::address_of(account) - │ ^^^^^^ Unbound module alias 'signer' + │ ^^^^^^ Unbound module or type alias 'signer' Command `-d -v build`: INCLUDING DEPENDENCY MoveStdlib diff --git a/third_party/move/tools/move-package/tests/test_sources/compilation/basic_no_deps/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/compilation/basic_no_deps/Move.v2_exp index adaca3b1886fd..6bcaca2bc52d9 100644 --- a/third_party/move/tools/move-package/tests/test_sources/compilation/basic_no_deps/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/compilation/basic_no_deps/Move.v2_exp @@ -7,6 +7,7 @@ CompiledPackageInfo { build_flags: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false, diff --git a/third_party/move/tools/move-package/tests/test_sources/compilation/basic_no_deps_address_assigned/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/compilation/basic_no_deps_address_assigned/Move.v2_exp index 5d9dcfb4ccff0..839e1fac31694 100644 --- a/third_party/move/tools/move-package/tests/test_sources/compilation/basic_no_deps_address_assigned/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/compilation/basic_no_deps_address_assigned/Move.v2_exp @@ -9,6 +9,7 @@ CompiledPackageInfo { build_flags: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false, diff --git a/third_party/move/tools/move-package/tests/test_sources/compilation/basic_no_deps_address_not_assigned_with_dev_assignment/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/compilation/basic_no_deps_address_not_assigned_with_dev_assignment/Move.v2_exp index 972262e9be61c..751804328a2b9 100644 --- a/third_party/move/tools/move-package/tests/test_sources/compilation/basic_no_deps_address_not_assigned_with_dev_assignment/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/compilation/basic_no_deps_address_not_assigned_with_dev_assignment/Move.v2_exp @@ -9,6 +9,7 @@ CompiledPackageInfo { build_flags: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false, diff --git a/third_party/move/tools/move-package/tests/test_sources/compilation/basic_no_deps_test_mode/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/compilation/basic_no_deps_test_mode/Move.v2_exp index 538af07d87225..0773cc5aada5d 100644 --- a/third_party/move/tools/move-package/tests/test_sources/compilation/basic_no_deps_test_mode/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/compilation/basic_no_deps_test_mode/Move.v2_exp @@ -9,6 +9,7 @@ CompiledPackageInfo { build_flags: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false, diff --git a/third_party/move/tools/move-package/tests/test_sources/compilation/diamond_problem_backflow_resolution/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/compilation/diamond_problem_backflow_resolution/Move.v2_exp index 5bb1b26ab4d70..f89883e1aed67 100644 --- a/third_party/move/tools/move-package/tests/test_sources/compilation/diamond_problem_backflow_resolution/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/compilation/diamond_problem_backflow_resolution/Move.v2_exp @@ -10,6 +10,7 @@ CompiledPackageInfo { build_flags: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false, diff --git a/third_party/move/tools/move-package/tests/test_sources/compilation/diamond_problem_no_conflict/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/compilation/diamond_problem_no_conflict/Move.v2_exp index 5bb1b26ab4d70..f89883e1aed67 100644 --- a/third_party/move/tools/move-package/tests/test_sources/compilation/diamond_problem_no_conflict/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/compilation/diamond_problem_no_conflict/Move.v2_exp @@ -10,6 +10,7 @@ CompiledPackageInfo { build_flags: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false, diff --git a/third_party/move/tools/move-package/tests/test_sources/compilation/one_dep/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/compilation/one_dep/Move.v2_exp index 27e2ded9923af..de62443012213 100644 --- a/third_party/move/tools/move-package/tests/test_sources/compilation/one_dep/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/compilation/one_dep/Move.v2_exp @@ -9,6 +9,7 @@ CompiledPackageInfo { build_flags: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false, diff --git a/third_party/move/tools/move-package/tests/test_sources/compilation/one_dep_assigned_address/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/compilation/one_dep_assigned_address/Move.v2_exp index aa27396b2824b..f593096323f5b 100644 --- a/third_party/move/tools/move-package/tests/test_sources/compilation/one_dep_assigned_address/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/compilation/one_dep_assigned_address/Move.v2_exp @@ -9,6 +9,7 @@ CompiledPackageInfo { build_flags: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false, diff --git a/third_party/move/tools/move-package/tests/test_sources/compilation/one_dep_renamed/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/compilation/one_dep_renamed/Move.v2_exp index 27e2ded9923af..de62443012213 100644 --- a/third_party/move/tools/move-package/tests/test_sources/compilation/one_dep_renamed/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/compilation/one_dep_renamed/Move.v2_exp @@ -9,6 +9,7 @@ CompiledPackageInfo { build_flags: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false, diff --git a/third_party/move/tools/move-package/tests/test_sources/compilation/one_dep_with_scripts/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/compilation/one_dep_with_scripts/Move.v2_exp index 27e2ded9923af..de62443012213 100644 --- a/third_party/move/tools/move-package/tests/test_sources/compilation/one_dep_with_scripts/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/compilation/one_dep_with_scripts/Move.v2_exp @@ -9,6 +9,7 @@ CompiledPackageInfo { build_flags: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false, diff --git a/third_party/move/tools/move-package/tests/test_sources/compilation/std-lib-override/Move.toml b/third_party/move/tools/move-package/tests/test_sources/compilation/std-lib-override/Move.toml_deactivated similarity index 100% rename from third_party/move/tools/move-package/tests/test_sources/compilation/std-lib-override/Move.toml rename to third_party/move/tools/move-package/tests/test_sources/compilation/std-lib-override/Move.toml_deactivated diff --git a/third_party/move/tools/move-package/tests/test_sources/compilation/std-lib-override/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/compilation/std-lib-override/Move.v2_exp new file mode 100644 index 0000000000000..668c6ec7680c6 --- /dev/null +++ b/third_party/move/tools/move-package/tests/test_sources/compilation/std-lib-override/Move.v2_exp @@ -0,0 +1 @@ +Unable to resolve packages for package 'std-lib-conflicts': While resolving dependency 'AptosFramework' in package 'std-lib-conflicts': Failed to reset to latest Git state 'devnet' for package 'AptosFramework', to skip set --skip-fetch-latest-git-deps | Exit status: exit status: 128 diff --git a/third_party/move/tools/move-package/tests/test_sources/compilation/test_symlinks/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/compilation/test_symlinks/Move.v2_exp index 5d9dcfb4ccff0..839e1fac31694 100644 --- a/third_party/move/tools/move-package/tests/test_sources/compilation/test_symlinks/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/compilation/test_symlinks/Move.v2_exp @@ -9,6 +9,7 @@ CompiledPackageInfo { build_flags: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false, diff --git a/third_party/move/tools/move-package/tests/test_sources/parsing/invalid_identifier_package_name/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/parsing/invalid_identifier_package_name/Move.v2_exp index 02350c3e42619..3acafccf25f4c 100644 --- a/third_party/move/tools/move-package/tests/test_sources/parsing/invalid_identifier_package_name/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/parsing/invalid_identifier_package_name/Move.v2_exp @@ -3,6 +3,7 @@ ResolutionGraph { build_options: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false, diff --git a/third_party/move/tools/move-package/tests/test_sources/parsing/minimal_manifest/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/parsing/minimal_manifest/Move.v2_exp index 90b6acee1ce5b..31cf89db8e99f 100644 --- a/third_party/move/tools/move-package/tests/test_sources/parsing/minimal_manifest/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/parsing/minimal_manifest/Move.v2_exp @@ -3,6 +3,7 @@ ResolutionGraph { build_options: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false, diff --git a/third_party/move/tools/move-package/tests/test_sources/resolution/basic_no_deps/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/resolution/basic_no_deps/Move.v2_exp index 923aef2b025f4..2b64bb5793588 100644 --- a/third_party/move/tools/move-package/tests/test_sources/resolution/basic_no_deps/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/resolution/basic_no_deps/Move.v2_exp @@ -3,6 +3,7 @@ ResolutionGraph { build_options: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false, diff --git a/third_party/move/tools/move-package/tests/test_sources/resolution/basic_no_deps_address_assigned/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/resolution/basic_no_deps_address_assigned/Move.v2_exp index a18ee763f196b..af6f27a951730 100644 --- a/third_party/move/tools/move-package/tests/test_sources/resolution/basic_no_deps_address_assigned/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/resolution/basic_no_deps_address_assigned/Move.v2_exp @@ -3,6 +3,7 @@ ResolutionGraph { build_options: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false, diff --git a/third_party/move/tools/move-package/tests/test_sources/resolution/basic_no_deps_address_not_assigned_with_dev_assignment/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/resolution/basic_no_deps_address_not_assigned_with_dev_assignment/Move.v2_exp index 2bd608ac8bb28..2af68c6f62b4e 100644 --- a/third_party/move/tools/move-package/tests/test_sources/resolution/basic_no_deps_address_not_assigned_with_dev_assignment/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/resolution/basic_no_deps_address_not_assigned_with_dev_assignment/Move.v2_exp @@ -3,6 +3,7 @@ ResolutionGraph { build_options: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false, diff --git a/third_party/move/tools/move-package/tests/test_sources/resolution/dep_good_digest/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/resolution/dep_good_digest/Move.v2_exp index e06ca0547ab30..a5c8fb687a2b2 100644 --- a/third_party/move/tools/move-package/tests/test_sources/resolution/dep_good_digest/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/resolution/dep_good_digest/Move.v2_exp @@ -3,6 +3,7 @@ ResolutionGraph { build_options: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false, diff --git a/third_party/move/tools/move-package/tests/test_sources/resolution/diamond_problem_backflow_resolution/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/resolution/diamond_problem_backflow_resolution/Move.v2_exp index ecdc89bf8e457..6995b52c9b03f 100644 --- a/third_party/move/tools/move-package/tests/test_sources/resolution/diamond_problem_backflow_resolution/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/resolution/diamond_problem_backflow_resolution/Move.v2_exp @@ -3,6 +3,7 @@ ResolutionGraph { build_options: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false, diff --git a/third_party/move/tools/move-package/tests/test_sources/resolution/diamond_problem_no_conflict/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/resolution/diamond_problem_no_conflict/Move.v2_exp index e21847fbd867b..3aa243d2b69bb 100644 --- a/third_party/move/tools/move-package/tests/test_sources/resolution/diamond_problem_no_conflict/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/resolution/diamond_problem_no_conflict/Move.v2_exp @@ -3,6 +3,7 @@ ResolutionGraph { build_options: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false, diff --git a/third_party/move/tools/move-package/tests/test_sources/resolution/multiple_deps_rename/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/resolution/multiple_deps_rename/Move.v2_exp index 7008fb15c56ba..ebc71d633ac3c 100644 --- a/third_party/move/tools/move-package/tests/test_sources/resolution/multiple_deps_rename/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/resolution/multiple_deps_rename/Move.v2_exp @@ -3,6 +3,7 @@ ResolutionGraph { build_options: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false, diff --git a/third_party/move/tools/move-package/tests/test_sources/resolution/one_dep/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/resolution/one_dep/Move.v2_exp index a4c32b07747f0..f371c17ff3bc9 100644 --- a/third_party/move/tools/move-package/tests/test_sources/resolution/one_dep/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/resolution/one_dep/Move.v2_exp @@ -3,6 +3,7 @@ ResolutionGraph { build_options: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false, diff --git a/third_party/move/tools/move-package/tests/test_sources/resolution/one_dep_assigned_address/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/resolution/one_dep_assigned_address/Move.v2_exp index 21a2c21581e8d..d32c7f82d912a 100644 --- a/third_party/move/tools/move-package/tests/test_sources/resolution/one_dep_assigned_address/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/resolution/one_dep_assigned_address/Move.v2_exp @@ -3,6 +3,7 @@ ResolutionGraph { build_options: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false, diff --git a/third_party/move/tools/move-package/tests/test_sources/resolution/one_dep_multiple_of_same_name/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/resolution/one_dep_multiple_of_same_name/Move.v2_exp index 0f5e470e6914f..3af26d56b669e 100644 --- a/third_party/move/tools/move-package/tests/test_sources/resolution/one_dep_multiple_of_same_name/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/resolution/one_dep_multiple_of_same_name/Move.v2_exp @@ -3,6 +3,7 @@ ResolutionGraph { build_options: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false, diff --git a/third_party/move/tools/move-package/tests/test_sources/resolution/one_dep_reassigned_address/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/resolution/one_dep_reassigned_address/Move.v2_exp index d9e5dfc3fc2dc..6c4ad1cbd406d 100644 --- a/third_party/move/tools/move-package/tests/test_sources/resolution/one_dep_reassigned_address/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/resolution/one_dep_reassigned_address/Move.v2_exp @@ -3,6 +3,7 @@ ResolutionGraph { build_options: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false, diff --git a/third_party/move/tools/move-package/tests/test_sources/resolution/one_dep_unification_across_local_renamings/Move.v2_exp b/third_party/move/tools/move-package/tests/test_sources/resolution/one_dep_unification_across_local_renamings/Move.v2_exp index a793634bf9363..f5a7612f51987 100644 --- a/third_party/move/tools/move-package/tests/test_sources/resolution/one_dep_unification_across_local_renamings/Move.v2_exp +++ b/third_party/move/tools/move-package/tests/test_sources/resolution/one_dep_unification_across_local_renamings/Move.v2_exp @@ -3,6 +3,7 @@ ResolutionGraph { build_options: BuildConfig { dev_mode: true, test_mode: false, + override_std: None, generate_docs: false, generate_abis: false, generate_move_model: false,