fixhunt

biome complexity/useSimplifiedLogicExpression

labelled safe
Runs / 2026-10-17T20-15-13-121Z-vjcv-biome-complexity_useSimplifiedLogicExpressionbiome 2.5.152026-10-17 20:15 UTC8 programs × 2 round(s)16 programs, 10 fired, 10 fixed, 1 findings, 1 rejectedmodel cost $0.03

Analysis Nemotron 3 Super

Flags redundant literals in logical expressions (`&&`, `||`, `!!`) that can be removed without changing truthiness in boolean contexts.

Fix: Removes the redundant literal: `true && expr` → `expr`, `false || expr` → `expr`, `expr || false` → `expr`, `expr && true` → `expr`, `!a || !b` → `!(a && b)`, `null ?? expr` → `expr`.

12 hazards
  • Rewriting `true && expr` to `expr` changes behavior if `expr` has side effects and the surrounding context relies on short-circuiting (e.g., in `if` conditions where `expr` must not run).
  • Rewriting `false || expr` to `expr` alters evaluation order and may cause `expr` to execute when it previously would not have due to short-circuiting.
  • Rewriting `expr || false` to `expr` removes a falsy fallback, potentially changing the result when `expr` is `undefined` or `null` in non-boolean contexts (though rule only fires in boolean contexts, this notes boundary risk).
  • Rewriting `expr && true` to `expr` eliminates a truthy guard, which could affect outcomes if `expr` is falsy and the result is used in a non-boolean context (rule restricts to boolean contexts, but notes potential misuse).
  • Rewriting `!a || !b` to `!(a && b)` via De Morgan’s law is logically equivalent but may interfere with debugging or intent if the original form was used for readability or breakpoint placement.
  • Rewriting `null ?? expr` to `expr` removes nullish coalescing, causing `expr` to evaluate even when `null` is present (but note: `null ?? expr` only fires if `expr` is truthy? Actually, rule flags `null ?? nonNullExp` as invalid — fix removes `null ??`, so rewrites to `expr`; hazard: if `expr` has side effects, it now runs unconditionally whereas before it only ran if `null` was null/undefined).
  • If the expression contains comments (e.g., `true && /* comment */ foo()`), the autofix may drop inline comments attached to the literal or expression.
  • In rare cases involving `eval` or `with`, the rewritten expression might resolve variables differently due to scope changes, though unlikely.
  • If `expr` is a getter with side effects, removing the literal may change the number of times it is invoked.
  • The fix may break parsing if `expr` begins with a lookahead ambiguity (e.g., `true && function(){}()` → `function(){}()` which is invalid as a statement).
  • In template literals or tagged templates, removing literals could alter the shape of passed arguments if the expression is spread or concatenated.
  • If the logical expression is part of a larger sequence (e.g., `return true && expr, other;`), removing `true &&` may alter comma operator behavior.

Findings

programoraclelabeljudgestatussummary
r2-p001fix-breaks-syntaxlabelled safereal · highduplicateThe rule rewrites 'true && function() { return 1; }()' to 'function() { return 1; }()', but a function expression in statement position is a syntax error becau…

Programs

idresulttitlehazard
r1-p001fix okRewriting expr || false loses falsy fallbackIn boolean contexts like ternary conditionals, replacing `x || false` with `x` removes the guarantee that falsy values become `false`. When `x` is `undefined` or `null`, the conditional branch selecti
r1-p002fix okGetter side effects invocation count changedIf `expr` is a getter with side effects, rewriting `getter || false` to `getter` does not change evaluation count in boolean context—but rewriting `true && getter` to `getter` reduces invocations from
r1-p003silent prediction offSparse array holes treated as undefined in logical expressionsAccessing a hole in a sparse array yields `undefined`. In `arr[i] || false`, if `arr[i]` is a hole, it evaluates to `undefined || false → false`. After fix: `arr[i]` alone is `undefined`, which in boo
r1-p004silent prediction offClass field initialization with logical expressionsClass field initializers run during construction. If an initializer contains `expr || false`, rewriting it to `expr` may cause `undefined` to be stored instead of `false`, affecting later behavior. Th
r1-p005silent prediction off__proto__ assignment altered by truthiness shiftWhen assigning to `__proto__`, the value must be an object or `null`. Using `expr || false` ensures a fallback to `false`, which coerces to object-like behavior in some engines? Actually, `__proto__`
r1-p006fix okTrue && expr removal breaks short-circuiting expectationAlthough `true && expr` always evaluates `expr`, rewriting it to `expr` removes the explicit `true` that might be relied upon for readability or tooling. More importantly, if this pattern appears in a
r1-p007silent prediction offNullish coalescing fallback removalRewriting `null ?? expr` to `expr` removes the intentional fallback to `expr` when the left side is `null` or `undefined`. If `expr` has side effects, those still occur—but the fallback logic is gone.
r1-p008silent prediction offTagged template literal argument shape changedIn tagged templates, expressions inside `${}` are passed as arguments. If such an expression is `expr || false`, rewriting it to `expr` changes the value passed when `expr` is `undefined` or `null`—fr
r2-p001fix-breaks-syntaxLookahead ambiguity breaking parseFix removing 'true &&' leaves a function expression starting at statement position, which is invalid syntax.
r2-p002invalidVar hoisting and redeclarationAfter fixing 'true && var x = 1' to 'var x = 1', hoisting and redeclaration in loop cause ReferenceError or wrong value.
r2-p003fix okFalse || expr evaluation order changedFixing 'false || (a=1)' to '(a=1)' causes assignment to run unconditionally, whereas before it was skipped due to short-circuit.
r2-p004fix okComments attached to removed codeFix removes 'true &&' and drops the inline comment on the expression, losing documentation.
r2-p005fix okNullish coalescing fallback removalFix rewrites 'null ?? expr' to 'expr', causing expr to run unconditionally even when null is present.
r2-p006fix okInline comment droppedAutofix removes 'true &&' and the attached inline comment on the expression.
r2-p007fix okASI with leading parenAfter fix, expression starts with '(' on next line, causing ASI to misinterpret as function call.
r2-p008fix okNumeric/string coercion hazardFix removes 'true &&' from expression involving Symbol.toPrimitive, altering coercion path and result.

Sources

r1-p001 · Rewriting expr || false loses falsy fallback
1function test(val) {
2 return (val || false) ? 'truthy' : 'falsy';
3}
4console.log(test(undefined));
5console.log(test(null));
--- orig.js	2026-10-17 16:15:29.514988087 -0400
+++ fixed.js	2026-10-17 16:15:29.781984182 -0400
@@ -1,5 +1,5 @@
 function test(val) {
-  return (val || false) ? 'truthy' : 'falsy';
+  return (val) ? 'truthy' : 'falsy';
 }
 console.log(test(undefined));
 console.log(test(null));
falsy
falsy
r1-p002 · Getter side effects invocation count changed
1let callCount = 0;
2const obj = {
3 get value() {
4 callCount++;
5 return 42;
6 }
7};
8if (true && obj.value) {
9 // first call
10}
11if (obj.value) {
12 // second call after fix
13}
14console.log('Getter called:', callCount);
--- orig.js	2026-10-17 16:15:29.940981857 -0400
+++ fixed.js	2026-10-17 16:15:30.203978018 -0400
@@ -5,7 +5,7 @@
     return 42;
   }
 };
-if (true && obj.value) {
+if (obj.value) {
   // first call
 }
 if (obj.value) {
Getter called: 2
r1-p003 · Sparse array holes treated as undefined in logical expressions
1const arr = [, 1]; // hole at index 0
2let target = {};
3const val = arr[0] || false;
4target.prop = val;
5console.log('Stored value:', target.prop, typeof target.prop);
6// After fix: target.prop = arr[0]; → stores undefined
Stored value: false boolean
r1-p004 · Class field initialization with logical expressions
1class C {
2 flag = (this.value || false);
3 constructor() {
4 this.value = undefined;
5 }
6}
7const c = new C();
8console.log('flag:', c.flag);
9// After fix: flag = this.value → undefined
flag: false
r1-p005 · __proto__ assignment altered by truthiness shift
1let fallbackUsed = false;
2const getValue = () => {
3 fallbackUsed = true;
4 return null;
5};
6try {
7 const proto = getValue() || false;
8 Object.defineProperty({}, '__proto__', { value: proto });
9} catch (e) {
10 console.log('Error:', e.name, fallbackUsed ? '(fallback used)' : '(no fallback)');
11}
r1-p006 · True && expr removal breaks short-circuiting expectation
1let i = 0;
2while (true && i < 3) {
3 console.log('Iteration:', i);
4 i++;
5}
6console.log('Loop exited at i=' + i);
--- orig.js	2026-10-17 16:15:31.009966261 -0400
+++ fixed.js	2026-10-17 16:15:31.261962594 -0400
@@ -1,5 +1,5 @@
 let i = 0;
-while (true && i < 3) {
+while (i < 3) {
   console.log('Iteration:', i);
   i++;
 }
Iteration: 0
Iteration: 1
Iteration: 2
Loop exited at i=3
r1-p007 · Nullish coalescing fallback removal
1function getConfig() {
2 return null;
3}
4const settings = getConfig() ?? { debug: true };
5console.log('settings.debug:', settings.debug);
6// After fix: settings = getConfig() → null, then accessing .debug throws
settings.debug: true
r1-p008 · Tagged template literal argument shape changed
1function tags(strings, ...values) {
2 console.log('Values received:', values.map(v => String(v)));
3 return strings.raw.join('');
4}
5const x = undefined;
6const result = tags`value: ${x || false}`;
7console.log('Result:', result);
8// After fix: ${x} → passes undefined, so values[0] is 'undefined'
Values received: [ 'false' ]
Result: value:
r2-p001 · Lookahead ambiguity breaking parse
1try {
2 true && function() { return 1; }();
3 console.log('ok');
4} catch (e) {
5 console.log(e.name + ': ' + e.message);
6}
--- orig.js	2026-10-17 16:15:37.605870939 -0400
+++ fixed.js	2026-10-17 16:15:37.866867196 -0400
@@ -1,5 +1,5 @@
 try {
-  true && function() { return 1; }();
+  function() { return 1; }();
   console.log('ok');
 } catch (e) {
   console.log(e.name + ': ' + e.message);
ok
r2-p002 · Var hoisting and redeclaration (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T20-15-1)
1for (let i = 0; i < 2; i++) {
2 try {
3 true && var x = i;
4 console.log(x);
5 } catch (e) {
6 console.log(e.name + ': ' + e.message);
7 }
8}
r2-p003 · False || expr evaluation order changed
1let a = 0;
2false || (a = 1);
3console.log(a); // should remain 0 if short-circuited
--- orig.js	2026-10-17 16:15:37.968865734 -0400
+++ fixed.js	2026-10-17 16:15:38.234861928 -0400
@@ -1,3 +1,3 @@
 let a = 0;
-false || (a = 1);
+(a = 1);
 console.log(a); // should remain 0 if short-circuited
1
r2-p004 · Comments attached to removed code
1let x = true && /* important */ 42;
2console.log(x);
--- orig.js	2026-10-17 16:15:38.398859582 -0400
+++ fixed.js	2026-10-17 16:15:38.666855749 -0400
@@ -1,2 +1,2 @@
-let x = true && /* important */ 42;
+let x = 42;
 console.log(x);
42
r2-p005 · Nullish coalescing fallback removal
1let called = 0;
2const f = () => { called++; return 99; };
3let result = null ?? f();
4console.log('result=' + result + ', called=' + called);
--- orig.js	2026-10-17 16:15:38.826853461 -0400
+++ fixed.js	2026-10-17 16:15:39.100849545 -0400
@@ -1,4 +1,4 @@
 let called = 0;
 const f = () => { called++; return 99; };
-let result = null ?? f();
+let result = f();
 console.log('result=' + result + ', called=' + called);
result=99, called=1
r2-p006 · Inline comment dropped
1let y = true && /* note */ parseInt('5');
2console.log(y);
--- orig.js	2026-10-17 16:15:39.263847220 -0400
+++ fixed.js	2026-10-17 16:15:39.530843410 -0400
@@ -1,2 +1,2 @@
-let y = true && /* note */ parseInt('5');
+let y = parseInt('5');
 console.log(y);
5
r2-p007 · ASI with leading paren
1let z =
2true &&
3( () => 7 )()
4console.log(z);
--- orig.js	2026-10-17 16:15:39.693841084 -0400
+++ fixed.js	2026-10-17 16:15:39.958837303 -0400
@@ -1,4 +1,3 @@
 let z =
-true &&
 ( () => 7 )()
 console.log(z);
7
r2-p008 · Numeric/string coercion hazard
1const obj = {
2 [Symbol.toPrimitive](hint) {
3 return hint === 'string' ? 'str' : 42;
4 }
5};
6let res = true && String(obj);
7console.log(res);
--- orig.js	2026-10-17 16:15:40.131834840 -0400
+++ fixed.js	2026-10-17 16:15:40.399831026 -0400
@@ -3,5 +3,5 @@
     return hint === 'string' ? 'str' : 42;
   }
 };
-let res = true && String(obj);
+let res = String(obj);
 console.log(res);
str