fixhunt

biome style/noUselessElse

labelled safe
Runs / 2026-10-17T19-57-27-934Z-8ilt-biome-style_noUselessElsebiome 2.5.152026-10-17 19:57 UTC8 programs × 2 round(s)16 programs, 6 fired, 6 fixed, 0 findings, 5 rejectedmodel cost $0.0030

Analysis Nemotron 3 Super

Flags else blocks after if statements containing breaking statements (return, break, continue, throw), as they are unreachable.

Fix: Removes the else block and places its statements directly after the if block, dedenting them by one level while preserving their original order.

10 hazards
  • Moving a break statement out of a switch case into the enclosing loop changes which loop it breaks, altering control flow.
  • Lifting a continue statement from inside a nested loop to an outer scope may cause it to break the wrong loop or become invalid if no enclosing loop exists.
  • Hoisting a throw statement before a variable declaration in the else block could reference a variable that hasn't been initialized yet due to TDZ.
  • Extracting a return statement from an else block inside a function may skip cleanup logic in a finally block of a surrounding try statement.
  • Moving a break from an else block inside a labeled statement to an outer context may break the wrong label or become syntactically invalid.
  • If the else block contains a function declaration, moving it to the outer scope may alter hoisting behavior and create a naming conflict.
  • Comments attached to the else block or its braces may be lost or misplaced during the rewrite, affecting readability but not semantics.
  • If the if block contains a labeled break and the else block is lifted, the label may no longer be in scope for the lifted statement.
  • Lifting a statement with side effects (e.g., i++) from an else block changes the timing of execution relative to prior code in the same block.
  • In a try-finally construct, moving a return from an else block before the finally block may prevent the finally block from executing if the return was previously guarded.

Programs

idresulttitlehazard
r1-p001fix okContinue lifted from inner loop breaks wrong outer loopLifting a continue statement from inside a nested loop to an outer scope may cause it to break the wrong loop or become invalid if no enclosing loop exists.
r1-p002fix okClass field initialization skipped due to removed else blockclass fields, static blocks, private names, super calls
r1-p003fix okBreak moved from else in labeled block breaks outer label incorrectlylabel/break/continue control flow, finally blocks, early returns in nested blocks
r1-p004fix okBreak from else inside labeled statement moves to wrong label scopeMoving a break from an else block inside a labeled statement to an outer context may break the wrong label or become syntactically invalid.
r1-p005invalidReturn moved before finally skips cleanup actionIn a try-finally construct, moving a return from an else block before the finally block may prevent the finally block from executing if the return was previously guarded.
r1-p006silent prediction offFunction call in else condition runs twice after fixorder of evaluation when expressions are merged, duplicated or deleted (side effects run twice or never)
r1-p007invalidThrow hoisted before let declaration causes TDZ errorHoisting a throw statement before a variable declaration in the else block could reference a variable that hasn't been initialized yet due to TDZ.
r1-p008silent prediction offFunction declaration in else block becomes hoisted and alters control flowfunction declarations inside blocks, switch cases, labeled statements
r2-p001invalidShadowing after else removalname collisions across scopes after a move (shadowing)
r2-p002fix okBreak to wrong label after liftMoving a break from an else block inside a labeled statement to an outer context may break the wrong label or become syntactically invalid.
r2-p003silent prediction offThrow before let TDZHoisting a throw statement before a variable declaration in the else block could reference a variable that hasn't been initialized yet due to TDZ.
r2-p004invalidComments lost on movecomments attached to the removed or moved code
r2-p005silent prediction offSide effect timing changedLifting a statement with side effects (e.g., i++) from an else block changes the timing of execution relative to prior code in the same block.
r2-p006invalidFunction declaration hoisted in elsefunction declarations inside blocks, switch cases, labeled statements
r2-p007fix okLabeled break loses label scopeIf the if block contains a labeled break and the else block is lifted, the label may no longer be in scope for the lifted statement.
r2-p008silent prediction offNullish vs falsy after liftnull/undefined distinction, optional chaining short-circuit, nullish vs falsy

Sources

r1-p001 · Continue lifted from inner loop breaks wrong outer loop
1let out = [];
2outer: for (let i = 0; i < 2; i++) {
3 inner: for (let j = 0; j < 2; j++) {
4 if (i === 0) { continue outer; }
5 else { out.push(i + ',' + j); }
6 }
7}
8console.log(out.join('|'));
--- orig.js	2026-10-17 15:57:36.172011573 -0400
+++ fixed.js	2026-10-17 15:57:36.448021434 -0400
@@ -2,7 +2,7 @@
 outer: for (let i = 0; i < 2; i++) {
   inner: for (let j = 0; j < 2; j++) {
     if (i === 0) { continue outer; }
-    else { out.push(i + ',' + j); }
+    out.push(i + ',' + j); 
   }
 }
 console.log(out.join('|'));
1,0|1,1
r1-p002 · Class field initialization skipped due to removed else block
1class C {
2 static x = (() => { if (false) { return 1; } else { return 2; } })();
3}
4console.log(C.x);
--- orig.js	2026-10-17 15:57:36.612027294 -0400
+++ fixed.js	2026-10-17 15:57:36.873036619 -0400
@@ -1,4 +1,4 @@
 class C {
-  static x = (() => { if (false) { return 1; } else { return 2; } })();
+  static x = (() => { if (false) { return 1; }return 2; })();
 }
 console.log(C.x);
2
r1-p003 · Break moved from else in labeled block breaks outer label incorrectly
1let result = '';
2loop: {
3 if (true) { break loop; }
4 else { result += 'b'; }
5}
6result += 'a';
7console.log(result);
--- orig.js	2026-10-17 15:57:37.034042369 -0400
+++ fixed.js	2026-10-17 15:57:37.296051707 -0400
@@ -1,7 +1,7 @@
 let result = '';
 loop: {
   if (true) { break loop; }
-  else { result += 'b'; }
+  result += 'b'; 
 }
 result += 'a';
 console.log(result);
a
r1-p004 · Break from else inside labeled statement moves to wrong label scope
1let log = '';
2outer: {
3 inner: {
4 if (false) { break inner; }
5 else { break outer; }
6 }
7 log += 'after inner';
8}
9log += 'end';
10console.log(log);
--- orig.js	2026-10-17 15:57:37.461057587 -0400
+++ fixed.js	2026-10-17 15:57:37.728067103 -0400
@@ -2,7 +2,7 @@
 outer: {
   inner: {
     if (false) { break inner; }
-    else { break outer; }
+    break outer; 
   }
   log += 'after inner';
 }
end
r1-p005 · Return moved before finally skips cleanup action (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T19-57-2)
1let finallyRan = false;
2try {
3 if (false) { return 'skipped'; }
4 else { return 'not skipped'; }
5} finally {
6 finallyRan = true;
7}
8console.log('finally ran:', finallyRan);
r1-p006 · Function call in else condition runs twice after fix
1let callCount = 0;
2function f() { return ++callCount; }
3if (f() > 0) { console.log('yes'); }
4else { console.log('no', f()); }
yes
r1-p007 · Throw hoisted before let declaration causes TDZ error (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T19-57-2)
1try {
2 if (false) { return; }
3 else { throw x; }
4} catch (e) {
5 console.log(e.name);
6}
7let x = 42;
r1-p008 · Function declaration in else block becomes hoisted and alters control flow
1let fCalled = false;
2if (false) {
3 function f() { fCalled = true; }
4} else {
5 f();
6}
7console.log(fCalled);
r2-p001 · Shadowing after else removal (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T19-57-2)
1let x = 1;
2if (true) { return; }
3else {
4 const x = 2;
5 console.log(x);
6}
7console.log('after');
r2-p002 · Break to wrong label after lift
1outer: {
2 if (false) { break outer; }
3 else {
4 console.log('in else');
5 break outer;
6 }
7}
8console.log('reached');
--- orig.js	2026-10-17 15:57:41.802211505 -0400
+++ fixed.js	2026-10-17 15:57:42.055220429 -0400
@@ -1,8 +1,7 @@
 outer: {
   if (false) { break outer; }
-  else {
+  
     console.log('in else');
     break outer;
-  }
 }
 console.log('reached');
in else
reached
r2-p003 · Throw before let TDZ
1if (false) {}
2else {
3 throw new Error(x);
4 let x = 1;
5}
6console.log('not reached');
r2-p004 · Comments lost on move (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T19-57-2)
1if (true) { return; }
2else {
3 // important side effect
4 console.log(42);
5}
6console.log('done');
r2-p005 · Side effect timing changed
1let i = 0;
2if (false) { i++ }
3else {
4 console.log(i); // should print 0
5 i++;
6}
7console.log(i); // should print 1 if not lifted, 2 if lifted before log
0
1
r2-p006 · Function declaration hoisted in else (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T19-57-2)
1if (true) { return; }
2else {
3 function f() { return 1; }
4 console.log(f());
5}
6// After fix, f is hoisted and callable before
7console.log(typeof f);
r2-p007 · Labeled break loses label scope
1outer: {
2 if (false) { break outer; }
3 else {
4 console.log('in else');
5 break outer; // label 'outer' must still be in scope
6 }
7}
8console.log('after label');
--- orig.js	2026-10-17 15:57:42.783246061 -0400
+++ fixed.js	2026-10-17 15:57:43.054255598 -0400
@@ -1,8 +1,7 @@
 outer: {
   if (false) { break outer; }
-  else {
+  
     console.log('in else');
     break outer; // label 'outer' must still be in scope
-  }
 }
 console.log('after label');
in else
after label
r2-p008 · Nullish vs falsy after lift
1let obj = null;
2if (false) {}
3else {
4 console.log(obj?.prop ?? 'default');
5}
6// After fix, if obj is reassigned later, timing matters
7obj = { prop: 'present' };
default