Skip to content

Commit 7a059ab

Browse files
committed
fix(cfg): double resolution of labeled statements. (#4177)
Fixes #4173
1 parent ca0b4fa commit 7a059ab

2 files changed

Lines changed: 43 additions & 2 deletions

File tree

crates/oxc_cfg/src/builder/context.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,12 @@ impl<'a, 'c> QueryCtx<'a, 'c> {
130130

131131
self.resolve_ctx(ctx);
132132

133-
// mark the upper label continue jump point the same as ours,
133+
// mark the upper label continue jump point the same as ours if it isn't already assigned,
134+
// NOTE: if it is already assigned there's a resolution before this context.
134135
if let Some(jmp) = continue_jmp {
135-
if let Some(label_ctx) = self.0.immediate_labeled_ctx() {
136+
if let Some(label_ctx @ RefCtxCursor(Ctx { continue_jmp: None, .. })) =
137+
self.0.immediate_labeled_ctx()
138+
{
136139
label_ctx.mark_continue(jmp);
137140
}
138141
}

crates/oxc_cfg/tests/builder.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use oxc_cfg::{ControlFlowGraphBuilder, CtxCursor};
2+
use oxc_syntax::node::AstNodeId;
3+
/// same as but just the skeleton
4+
/// ```js
5+
/// A: {
6+
/// do {} while (a);
7+
/// do {} while (b);
8+
/// break A;
9+
/// }
10+
/// ```
11+
#[test]
12+
fn labeled_statement_with_multiple_loops_continue_and_break() {
13+
const A: Option<&str> = Some("A");
14+
15+
let mut cfg = ControlFlowGraphBuilder::default();
16+
cfg.attach_error_harness(oxc_cfg::ErrorEdgeKind::Implicit);
17+
18+
// labeled block start
19+
let labeled = cfg.new_basic_block_normal();
20+
cfg.ctx(A).default().allow_break().allow_continue();
21+
22+
// loop context 1
23+
let c1 = cfg.new_basic_block_normal();
24+
cfg.ctx(None).default().allow_break().allow_continue();
25+
cfg.ctx(None).mark_break(c1).mark_continue(c1).resolve_with_upper_label();
26+
27+
// loop context 2
28+
let c2 = cfg.new_basic_block_normal();
29+
cfg.ctx(None).default().allow_break().allow_continue();
30+
cfg.ctx(None).mark_break(c2).mark_continue(c2).resolve_with_upper_label();
31+
32+
cfg.append_break(AstNodeId::dummy(), A);
33+
34+
// labeled block end
35+
cfg.ctx(A).mark_break(labeled).resolve();
36+
37+
cfg.build();
38+
}

0 commit comments

Comments
 (0)