fixhunt

biome style/noUselessElse: fix changes program behavior

fix-changes-behaviorlabelled safereal · highduplicate
Findings / 2026-10-17T19-42-12-619Z-e4vp-biome-style_noUselessElse / r1-p008biome 2.5.1510 → 9 lines2026-10-17 19:42 UTC

Hypothesis Nemotron 3 Super predicted to fire fired 1×

function declarations inside blocks, switch cases, labeled statements

Program

before
1function main() {
2 switch (0) {
3 case 0:
4 if (false) { return; }
5 else { function g() { return 2; } }
6 console.log(typeof g);
7 }
8}
9main();
after
1function main() {
2 switch (0) {
3 case 0:
4 if (false) { return; }
5 function g() { return 2; }
6 console.log(typeof g);
7 }
8}
9main();

Output

stdout beforeexit 0
undefined
stdout afterexit 0
function
fired
1 before · 0 after
runs
each version twice, same file name, no network

Judge Nemotron 3 Ultra advisory real · high

The fix hoists a function declaration out of an else block into a switch case clause, where function declarations are not allowed in strict mode and have implementation-dependent semantics in sloppy mode. Before the fix the function was never created (the else was dead code), so typeof g yielded 'undefined'; after the fix the function is created (or a syntax error occurs), changing the observable behavior.

Explanation Nemotron 3 Super unverified

The original `else` block defines `g` only when the condition is false—here always executed because `if(false)` never runs—but as a function declaration inside a block, it remains scoped to that block in strict mode, making `g` inaccessible outside. After rewriting, `g` becomes a top-level function declaration within the same block scope but now hoisted to the block’s start, still confined to the block. However, JavaScript treats block-scoped function declarations inconsistently across engines; here, the engine likely hoists `g` to the function scope of `main`, making it accessible for `typeof`. Thus, `typeof g` changes from `undefined` (original, due to block scoping) to `function` (rewritten, due to hoisting to outer scope). This alters observable behavior.

Reproduce

file
prog.js (the before program)
minimized program
r1-p008.js
evidence sheet
r1-p008.md
regression fixture
r1-p008.js the minimized program with a header stating the observed change, for the tool's test suite
node prog.js
bunx @biomejs/biome lint --only=style/noUselessElse --write prog.js
node prog.js

Upstream search GitHub issues Tavily Nemotron 3 Super + Ultra

noUselessElse fix · style noUselessElse conditional block · else clause containing function declaration · switch case if-else refactoring

  • duplicate biomejs/biome/issues/11937 same rule noUselessElse hoisting a function declaration out of an else block into a switch case, colliding with an outer binding and changing typeof g from undefined to function
  • related biomejs/biome/issues/3770 same rule noUselessElse but about a useful else with break in a for loop, not a function declaration hoisting in a switch case
  • related biomejs/biome/issues/1191 same rule noUselessElse but about an else-if chain in object pattern matching, not a function declaration hoisting in a switch case
  • related biomejs/biome/issues/4354 same rule noUselessElse but about not respecting else-if conditional, not a function declaration hoisting in a switch case

Details

program
Block-scoped function in switch
hazard
function declarations inside blocks, switch cases, labeled statements
oracle
stdout before: undefined stdout after: function
run
2026-10-17T19-42-12-619Z-e4vp-biome-style_noUselessElse
generated program (10 lines) and the fix's diff
1function main() {
2 switch (0) {
3 case 0:
4 if (false) { return; }
5 else { function g() { return 2; } }
6 console.log(typeof g);
7 break;
8 }
9}
10main();
--- orig.js	2026-10-17 15:42:23.938505817 -0400
+++ fixed.js	2026-10-17 15:42:24.206500254 -0400
@@ -2,7 +2,7 @@
   switch (0) {
     case 0:
       if (false) { return; }
-      else { function g() { return 2; } }
+      function g() { return 2; } 
       console.log(typeof g);
       break;
   }
rule documentation given to the models
Summary

- Name: noUselessElse
- Fix: safe
- Default severity: info
- Available from version: 1.3.0
- Diagnostic category: lint/style/noUselessElse


Description

 Disallow `else` block when the `if` block breaks early.

 If an `if` block breaks early using a breaking statement (`return`, `break`, `continue`, or `throw`),
 then the `else` block becomes useless.
 Its contents can be placed outside of the block.

 If an `if` block breaks early using a breaking statement (`return`, `break`, `continue`, or `throw`),
 then the `else` block becomes unnecessary.
 This is because the content of the `else` block will never be executed in conjunction with the `if` block,
 as the breaking statement ensures the control flow exits the `if` block immediately.
 Therefore, the `else` block is redundant, and its content can be placed outside of the block,
 reducing the indentation level by one.

Examples

Invalid

 ```js,expect_diagnostic
 while (x > 0) {
     if (f(x)) {
         break;
     } else {
         x++
     }
 }
 ```

 ```js,expect_diagnostic
 function f(x) {
     if (x < 0) {
         return 0;
     } else {
         return x;
     }
 }
 ```

 ```js,expect_diagnostic
 function f(x) {
     if (x < 0) {
         throw new RangeError();
     } else {
         return x;
     }
 }
 ```

Valid

 ```js
 function f(x) {
     if (x < 0) {
         return 0;
     }
     return x;
 }
 ```

 ```js
 function f(x) {
     if (x < 0) {
         console.info("negative number");
     } else if (x > 0) {
         return x;
     } else {
         console.info("number 0");
     }
 }
 ```