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-p007biome 2.5.156 → 6 lines2026-10-17 19:42 UTC

Hypothesis Nemotron 3 Super predicted to fire fired 1×

Hoisting a function declaration from within the else block could make it available earlier than intended, causing premature invocation.

Program

before
1function main() {
2 if (false) { return; }
3 else { function f() { return 1; } }
4 try { console.log(f()); } catch (e) { console.log(e.name); }
5}
6main();
after
1function main() {
2 if (false) { return; }
3 function f() { return 1; }
4 try { console.log(f()); } catch (e) { console.log(e.name); }
5}
6main();

Output

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

Judge Nemotron 3 Ultra advisory real · high

The fix hoists the function declaration out of the else block, changing it from a block-scoped declaration (ES2015+) that only exists when the else runs to a function-scoped declaration that is always created. The original program throws a ReferenceError because f is never declared; after the fix f exists and prints 1. The documentation presents the rewrite as equivalent but does not account for block-scoped function declarations.

Explanation Nemotron 3 Super unverified

The original `else` block defines `f` only when the condition is false—always true here—but its scope is limited to that block due to JavaScript’s lexical scoping rules for function declarations inside blocks. After removing the `else`, `f` becomes globally scoped within `main`, so it exists in the `try` block regardless of the conditional. Originally, although logically reachable, the function declaration was still confined to the `else` block’s scope per ES2015+ semantics, making `f` inaccessible outside it despite the condition being constant-false. The rewrite hoists `f` to the function level, changing its visibility and causing different behavior. This violates semantic preservation because scope, not just execution, determines identifier accessibility. The fix incorrectly assumes dead code removal preserves scope, but block-scoped function declarations are not interchangeable with outer-scope ones even when unreachable.

Reproduce

file
prog.js (the before program)
minimized program
r1-p007.js
evidence sheet
r1-p007.md
regression fixture
r1-p007.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 · style noUselessElse empty if body · style noUselessElse function declaration

Details

program
Premature function hoist
hazard
Hoisting a function declaration from within the else block could make it available earlier than intended, causing premature invocation.
oracle
stdout before: ReferenceError stdout after: 1
run
2026-10-17T19-42-12-619Z-e4vp-biome-style_noUselessElse
generated program (6 lines) and the fix's diff
1function main() {
2 if (false) { return; }
3 else { function f() { return 1; } }
4 try { console.log(f()); } catch (e) { console.log(e.name); }
5}
6main();
--- orig.js	2026-10-17 15:42:23.507514755 -0400
+++ fixed.js	2026-10-17 15:42:23.777509156 -0400
@@ -1,6 +1,6 @@
 function main() {
   if (false) { return; }
-  else { function f() { return 1; } }
+  function f() { return 1; } 
   try { console.log(f()); } catch (e) { console.log(e.name); }
 }
 main();
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");
     }
 }
 ```