Skip to content

Commit

Permalink
[compiler-v2] Enum types frontend (#13577)
Browse files Browse the repository at this point in the history
* [compiler-v2] Enum types frontend

This implements the frontend (parser, context checker, and model representation) of struct variants aka 'enum types', including the `enum` type declaration, as well as the `match` expression.

The internal design principle is that enum types are not a new kind of types, but just a variation of the existing struct types, which now have multiple variants. This allows the implementation to have a relative small footprint. The same principle is likely later to be applied for the VM implementation.

Many of the existing code for dealing with struct pack and unpack can be reused for enum types. Some changes in the expansion phase and the model builder have to be applied, as a struct name can now be accompanied by an optional variant name. The model builder has also been slightly refactored and cleaned up to deal with the new features.

The implementation does not yet check for exhaustive matches and similar conditions. Those checks are naturally done later by the code which compiles matches to bytecode.

There are some general changes to baseline files unrelated to the functionality of this PR but resulting from refining the Model dump representation, as well as minor bug fixes. For the tests relevant to this PR, see `test/checking/variants/`.

* Check for correct naming of variants, and resolve unqualified variants in match

* addressing reviewer comments. Also adding common field resolution for variants.
  • Loading branch information
wrwg authored Jun 19, 2024
1 parent 8501f33 commit 97a555b
Show file tree
Hide file tree
Showing 164 changed files with 2,499 additions and 944 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -83,6 +87,11 @@ fn compile_yul_to_bytecode_bytes(filename: &str) -> Result<Vec<u8>> {
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()
Expand Down
26 changes: 24 additions & 2 deletions third_party/move/move-compiler-v2/src/ast_simplifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {
Expand Down Expand Up @@ -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),
Expand All @@ -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())
);
Expand Down
11 changes: 9 additions & 2 deletions third_party/move/move-compiler-v2/src/bytecode_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ impl<'env> Generator<'env> {
fn gen(&mut self, targets: Vec<TempIndex>, 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),
Expand Down Expand Up @@ -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)
},
Expand Down Expand Up @@ -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() {
Expand Down
20 changes: 17 additions & 3 deletions third_party/move/move-compiler-v2/src/flow_insensitive_checkers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand All @@ -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, ..) => {
Expand All @@ -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, _) => {
Expand Down
4 changes: 2 additions & 2 deletions third_party/move/move-compiler-v2/src/function_checker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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());
Expand Down
9 changes: 7 additions & 2 deletions third_party/move/move-compiler-v2/src/inliner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ error: type `R<key>` 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`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<u64>(f, h)
}
private fun assign_struct(s: &mut assign::S) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}
Expand Down
Loading

0 comments on commit 97a555b

Please sign in to comment.