From 7a059ab53ac049c580bb1742ecc4dc5cffbfc6fd Mon Sep 17 00:00:00 2001 From: rzvxa <3788964+rzvxa@users.noreply.github.com> Date: Thu, 11 Jul 2024 01:39:28 +0000 Subject: [PATCH] fix(cfg): double resolution of labeled statements. (#4177) Fixes #4173 --- crates/oxc_cfg/src/builder/context.rs | 7 +++-- crates/oxc_cfg/tests/builder.rs | 38 +++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 crates/oxc_cfg/tests/builder.rs diff --git a/crates/oxc_cfg/src/builder/context.rs b/crates/oxc_cfg/src/builder/context.rs index 692368ebc1036..3097f3053213b 100644 --- a/crates/oxc_cfg/src/builder/context.rs +++ b/crates/oxc_cfg/src/builder/context.rs @@ -130,9 +130,12 @@ impl<'a, 'c> QueryCtx<'a, 'c> { self.resolve_ctx(ctx); - // mark the upper label continue jump point the same as ours, + // mark the upper label continue jump point the same as ours if it isn't already assigned, + // NOTE: if it is already assigned there's a resolution before this context. if let Some(jmp) = continue_jmp { - if let Some(label_ctx) = self.0.immediate_labeled_ctx() { + if let Some(label_ctx @ RefCtxCursor(Ctx { continue_jmp: None, .. })) = + self.0.immediate_labeled_ctx() + { label_ctx.mark_continue(jmp); } } diff --git a/crates/oxc_cfg/tests/builder.rs b/crates/oxc_cfg/tests/builder.rs new file mode 100644 index 0000000000000..58e2dc4d8c408 --- /dev/null +++ b/crates/oxc_cfg/tests/builder.rs @@ -0,0 +1,38 @@ +use oxc_cfg::{ControlFlowGraphBuilder, CtxCursor}; +use oxc_syntax::node::AstNodeId; +/// same as but just the skeleton +/// ```js +/// A: { +/// do {} while (a); +/// do {} while (b); +/// break A; +/// } +/// ``` +#[test] +fn labeled_statement_with_multiple_loops_continue_and_break() { + const A: Option<&str> = Some("A"); + + let mut cfg = ControlFlowGraphBuilder::default(); + cfg.attach_error_harness(oxc_cfg::ErrorEdgeKind::Implicit); + + // labeled block start + let labeled = cfg.new_basic_block_normal(); + cfg.ctx(A).default().allow_break().allow_continue(); + + // loop context 1 + let c1 = cfg.new_basic_block_normal(); + cfg.ctx(None).default().allow_break().allow_continue(); + cfg.ctx(None).mark_break(c1).mark_continue(c1).resolve_with_upper_label(); + + // loop context 2 + let c2 = cfg.new_basic_block_normal(); + cfg.ctx(None).default().allow_break().allow_continue(); + cfg.ctx(None).mark_break(c2).mark_continue(c2).resolve_with_upper_label(); + + cfg.append_break(AstNodeId::dummy(), A); + + // labeled block end + cfg.ctx(A).mark_break(labeled).resolve(); + + cfg.build(); +}