diff --git a/.github/workflows/indexer-processor-testing.yaml b/.github/workflows/indexer-processor-testing.yaml index 942076e1270d8..091ef7982b017 100644 --- a/.github/workflows/indexer-processor-testing.yaml +++ b/.github/workflows/indexer-processor-testing.yaml @@ -6,6 +6,8 @@ on: pull_request: # Trigger on PR-level events branches: - main + paths: + - 'ecosystem/indexer-grpc/indexer-test-transactions/**' # Only trigger if files under this path change # the required permissions to request the ID token permissions: @@ -14,7 +16,7 @@ permissions: jobs: dispatch_event: - runs-on: runs-on,cpu=64,family=c7,hdd=500,image=aptos-ubuntu-x64,run-id=${{ github.run_id }} + runs-on: runs-on,cpu=16,family=c7,hdd=500,image=aptos-ubuntu-x64,run-id=${{ github.run_id }} steps: - name: Checkout the repository diff --git a/third_party/move/move-compiler-v2/src/bytecode_generator.rs b/third_party/move/move-compiler-v2/src/bytecode_generator.rs index 2b024cb47991d..9cb45341d9743 100644 --- a/third_party/move/move-compiler-v2/src/bytecode_generator.rs +++ b/third_party/move/move-compiler-v2/src/bytecode_generator.rs @@ -450,11 +450,11 @@ impl<'env> Generator<'env> { self.emit_with(*id, |attr| Bytecode::Jump(attr, continue_label)); self.emit_with(*id, |attr| Bytecode::Label(attr, break_label)); }, - ExpData::LoopCont(id, 0, do_continue) => { + ExpData::LoopCont(id, nest, do_continue) => { if let Some(LoopContext { continue_label, break_label, - }) = self.loops.last() + }) = self.loops.iter().rev().nth(*nest) { let target = if *do_continue { *continue_label @@ -466,9 +466,6 @@ impl<'env> Generator<'env> { self.error(*id, "missing enclosing loop statement") } }, - ExpData::LoopCont(_, _, _) => { - unimplemented!("continue/break with nesting") - }, ExpData::SpecBlock(id, spec) => { // Map locals in spec to assigned temporaries. let mut replacer = |id, target| { diff --git a/third_party/move/move-compiler-v2/tests/bytecode-generator/loop_labels.exp b/third_party/move/move-compiler-v2/tests/bytecode-generator/loop_labels.exp new file mode 100644 index 0000000000000..247f1e144dfdb --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/bytecode-generator/loop_labels.exp @@ -0,0 +1,78 @@ +// -- Model dump before bytecode pipeline +module 0x815::test { + private fun f1() { + loop { + loop { + loop { + if true { + loop { + if false { + continue[3] + } else { + break[1] + }; + break + } + } else { + continue[2] + } + } + }; + break + } + } +} // end 0x815::test + +// -- Sourcified model before bytecode pipeline +module 0x815::test { + fun f1() { + 'l0: loop { + loop 'l1: loop if (true) loop { + if (false) continue 'l0 else break 'l1; + break + } else continue 'l0; + break + } + } +} + +============ initial bytecode ================ + +[variant baseline] +fun test::f1() { + var $t0: bool + var $t1: bool + 0: label L0 + 1: label L2 + 2: label L4 + 3: $t0 := true + 4: if ($t0) goto 5 else goto 19 + 5: label L6 + 6: label L9 + 7: $t1 := false + 8: if ($t1) goto 9 else goto 12 + 9: label L11 + 10: goto 0 + 11: goto 14 + 12: label L12 + 13: goto 23 + 14: label L13 + 15: goto 17 + 16: goto 6 + 17: label L10 + 18: goto 21 + 19: label L7 + 20: goto 0 + 21: label L8 + 22: goto 2 + 23: label L5 + 24: goto 1 + 25: label L3 + 26: goto 28 + 27: goto 0 + 28: label L1 + 29: return () +} + + +============ bytecode verification succeeded ======== diff --git a/third_party/move/move-compiler-v2/tests/bytecode-generator/loop_labels.move b/third_party/move/move-compiler-v2/tests/bytecode-generator/loop_labels.move new file mode 100644 index 0000000000000..e91763e82ae00 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/bytecode-generator/loop_labels.move @@ -0,0 +1,14 @@ +module 0x815::test { + fun f1() { + 'outer: loop { + // unlabeled loop, but counts in nesting in AST + loop { + 'inner: loop if (true) loop { + if (false) continue 'outer else break 'inner; + break + } else continue 'outer + }; + break + } + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking-lang-v1/loop_labels.exp b/third_party/move/move-compiler-v2/tests/checking-lang-v1/loop_labels.exp new file mode 100644 index 0000000000000..ca660b6e4e138 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking-lang-v1/loop_labels.exp @@ -0,0 +1,31 @@ + +Diagnostics: +error: unsupported language construct + ┌─ tests/checking-lang-v1/loop_labels.move:3:9 + │ +3 │ 'outer: loop { + │ ^^^^^^ loop labels are not enabled before version 2.1 + +error: unsupported language construct + ┌─ tests/checking-lang-v1/loop_labels.move:6:17 + │ +6 │ 'inner: loop if (true) loop { + │ ^^^^^^ loop labels are not enabled before version 2.1 + +error: unsupported language construct + ┌─ tests/checking-lang-v1/loop_labels.move:7:41 + │ +7 │ if (false) continue 'outer else break 'inner; + │ ^^^^^^ loop labels are not enabled before version 2.1 + +error: unsupported language construct + ┌─ tests/checking-lang-v1/loop_labels.move:7:59 + │ +7 │ if (false) continue 'outer else break 'inner; + │ ^^^^^^ loop labels are not enabled before version 2.1 + +error: unsupported language construct + ┌─ tests/checking-lang-v1/loop_labels.move:9:33 + │ +9 │ } else continue 'outer + │ ^^^^^^ loop labels are not enabled before version 2.1 diff --git a/third_party/move/move-compiler-v2/tests/checking-lang-v1/loop_labels.move b/third_party/move/move-compiler-v2/tests/checking-lang-v1/loop_labels.move new file mode 100644 index 0000000000000..e91763e82ae00 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking-lang-v1/loop_labels.move @@ -0,0 +1,14 @@ +module 0x815::test { + fun f1() { + 'outer: loop { + // unlabeled loop, but counts in nesting in AST + loop { + 'inner: loop if (true) loop { + if (false) continue 'outer else break 'inner; + break + } else continue 'outer + }; + break + } + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_check_err.exp b/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_check_err.exp new file mode 100644 index 0000000000000..fd0b9ddf3ef67 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_check_err.exp @@ -0,0 +1,21 @@ + +Diagnostics: +error: label `'outer` undefined + ┌─ tests/checking/control_flow/loop_labels_check_err.move:3:15 + │ +3 │ break 'outer; + │ ^^^^^^ + +error: label `'inner` undefined + ┌─ tests/checking/control_flow/loop_labels_check_err.move:5:19 + │ +5 │ break 'inner + │ ^^^^^^ + +error: label `'l1` already used by outer loop + ┌─ tests/checking/control_flow/loop_labels_check_err.move:11:19 + │ +11 │ 'l1: loop 'l1: loop {}; + │ --- ^^^ + │ │ + │ outer definition of label diff --git a/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_check_err.move b/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_check_err.move new file mode 100644 index 0000000000000..6a1a1f616934e --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_check_err.move @@ -0,0 +1,14 @@ +module 0x815::test { + fun undefined_label() { + break 'outer; + 'outer: loop { + break 'inner + } + } + + fun duplicate_label() { + 'l1: loop {}; + 'l1: loop 'l1: loop {}; + 'l1: loop {} + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_check_ok.exp b/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_check_ok.exp new file mode 100644 index 0000000000000..3bf1a2816123f --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_check_ok.exp @@ -0,0 +1,37 @@ +// -- Model dump before bytecode pipeline +module 0x815::test { + private fun f1() { + loop { + loop { + loop { + if true { + loop { + if false { + continue[3] + } else { + break[1] + }; + break + } + } else { + continue[2] + } + } + }; + break + } + } +} // end 0x815::test + +// -- Sourcified model before bytecode pipeline +module 0x815::test { + fun f1() { + 'l0: loop { + loop 'l1: loop if (true) loop { + if (false) continue 'l0 else break 'l1; + break + } else continue 'l0; + break + } + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_check_ok.move b/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_check_ok.move new file mode 100644 index 0000000000000..e91763e82ae00 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_check_ok.move @@ -0,0 +1,14 @@ +module 0x815::test { + fun f1() { + 'outer: loop { + // unlabeled loop, but counts in nesting in AST + loop { + 'inner: loop if (true) loop { + if (false) continue 'outer else break 'inner; + break + } else continue 'outer + }; + break + } + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_parse_err1.exp b/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_parse_err1.exp new file mode 100644 index 0000000000000..5da0a89107cbc --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_parse_err1.exp @@ -0,0 +1,10 @@ + +Diagnostics: +error: unexpected token + ┌─ tests/checking/control_flow/loop_labels_parse_err1.move:3:13 + │ +3 │ 'a: if (true) false else true + │ ^^ + │ │ + │ Unexpected 'if' + │ Expected one of: `while` or `loop` diff --git a/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_parse_err1.move b/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_parse_err1.move new file mode 100644 index 0000000000000..319268dd01537 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_parse_err1.move @@ -0,0 +1,5 @@ +module 0x815::test { + fun f1(): bool { + 'a: if (true) false else true + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_parse_err2.exp b/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_parse_err2.exp new file mode 100644 index 0000000000000..f2275ffd0e61e --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_parse_err2.exp @@ -0,0 +1,10 @@ + +Diagnostics: +error: unexpected token + ┌─ tests/checking/control_flow/loop_labels_parse_err2.move:3:13 + │ +3 │ 'a: if (true) false else true + │ ^^ + │ │ + │ Unexpected 'if' + │ Expected one of: `while` or `loop` diff --git a/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_parse_err2.move b/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_parse_err2.move new file mode 100644 index 0000000000000..319268dd01537 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_parse_err2.move @@ -0,0 +1,5 @@ +module 0x815::test { + fun f1(): bool { + 'a: if (true) false else true + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_parse_err3.exp b/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_parse_err3.exp new file mode 100644 index 0000000000000..59cf17aac2daa --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_parse_err3.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: invalid character + ┌─ tests/checking/control_flow/loop_labels_parse_err3.move:3:10 + │ +3 │ ': if (true) false else true + │ ^ Label quote must be followed by 'A-Z', `a-z', or '_' diff --git a/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_parse_err3.move b/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_parse_err3.move new file mode 100644 index 0000000000000..150322d37c6b9 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_parse_err3.move @@ -0,0 +1,9 @@ +module 0x815::test { + fun f1(): bool { + ': if (true) false else true + } + + fun f1(): bool { + '0x: if (true) false else true + } +} diff --git a/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_parse_err4.exp b/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_parse_err4.exp new file mode 100644 index 0000000000000..b8bfb04974e35 --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_parse_err4.exp @@ -0,0 +1,7 @@ + +Diagnostics: +error: invalid character + ┌─ tests/checking/control_flow/loop_labels_parse_err4.move:3:10 + │ +3 │ '0x: if (true) false else true + │ ^ Label quote must be followed by 'A-Z', `a-z', or '_' diff --git a/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_parse_err4.move b/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_parse_err4.move new file mode 100644 index 0000000000000..4ec39b2125b2d --- /dev/null +++ b/third_party/move/move-compiler-v2/tests/checking/control_flow/loop_labels_parse_err4.move @@ -0,0 +1,5 @@ +module 0x815::test { + fun f1(): bool { + '0x: if (true) false else true + } +} diff --git a/third_party/move/move-compiler-v2/tests/testsuite.rs b/third_party/move/move-compiler-v2/tests/testsuite.rs index 3bd4ea13694d8..132c5d11d30c1 100644 --- a/third_party/move/move-compiler-v2/tests/testsuite.rs +++ b/third_party/move/move-compiler-v2/tests/testsuite.rs @@ -106,7 +106,7 @@ const TEST_CONFIGS: Lazy> = Lazy::new(|| { // Turn optimization on by default. Some configs below may turn it off. .set_experiment(Experiment::OPTIMIZE, true) .set_experiment(Experiment::OPTIMIZE_WAITING_FOR_COMPARE_TESTS, true) - .set_language_version(LanguageVersion::V2_0); + .set_language_version(LanguageVersion::V2_1); opts.testing = true; let configs = vec![ // --- Tests for checking and ast processing @@ -718,7 +718,7 @@ const TEST_CONFIGS: Lazy> = Lazy::new(|| { include: vec!["/op-equal/"], exclude: vec![], exp_suffix: None, - options: opts.clone().set_language_version(LanguageVersion::V2_1), + options: opts.clone(), // Run the entire compiler pipeline to double-check the result stop_after: StopAfter::FileFormat, dump_ast: DumpLevel::EndStage, diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/loop_labels.exp b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/loop_labels.exp new file mode 100644 index 0000000000000..6cd67db3f6472 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/loop_labels.exp @@ -0,0 +1 @@ +processed 1 task diff --git a/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/loop_labels.move b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/loop_labels.move new file mode 100644 index 0000000000000..b1c0cf1f69c32 --- /dev/null +++ b/third_party/move/move-compiler-v2/transactional-tests/tests/no-v1-comparison/loop_labels.move @@ -0,0 +1,18 @@ +//# run +script { + fun main() { + let result = 0; + 'outer: while (result < 100) { + while (result < 50) { + 'inner: while (result < 30) { + result += 1; + continue 'outer + }; + result += 10; + continue 'outer + }; + result += 20 + }; + assert!(result == 110); + } +} diff --git a/third_party/move/move-compiler/src/expansion/ast.rs b/third_party/move/move-compiler/src/expansion/ast.rs index 880234d6fc715..47db86f2654ba 100644 --- a/third_party/move/move-compiler/src/expansion/ast.rs +++ b/third_party/move/move-compiler/src/expansion/ast.rs @@ -5,7 +5,7 @@ use crate::{ expansion::translate::is_valid_struct_constant_or_schema_name, parser::ast::{ - self as P, Ability, Ability_, BinOp, CallKind, ConstantName, Field, FunctionName, + self as P, Ability, Ability_, BinOp, CallKind, ConstantName, Field, FunctionName, Label, ModuleName, QuantKind, SpecApplyPattern, StructName, UnaryOp, UseDecl, Var, VariantName, ENTRY_MODIFIER, }, @@ -25,7 +25,6 @@ use std::{ fmt, hash::Hash, }; - //************************************************************************************************** // Program //************************************************************************************************** @@ -504,8 +503,8 @@ pub enum Exp_ { IfElse(Box, Box, Box), Match(Box, Vec, Exp)>>), - While(Box, Box), - Loop(Box), + While(Option