biome style/noUselessElse: fix changes program behavior
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
Output
ReferenceError
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
- duplicate biomejs/biome/issues/11937 same rule noUselessElse hoisting a function declaration out of an else block and colliding with an outer binding
- related biomejs/biome/issues/3770 same rule noUselessElse but different construct (break in loop)
- related biomejs/biome/issues/1191 same rule noUselessElse but different construct (else-if chain)
- related biomejs/biome/issues/4354 same rule noUselessElse but different construct (else-if conditional)
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
--- 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");
}
}
```