fixhunt

eslint no-implicit-coercion

labelled safe
Runs / 2026-10-22T18-17-38-943Z-0wnb-eslint-no-implicit-coercioneslint 9.39.52026-10-22 18:17 UTC8 programs × 2 round(s)16 programs, 15 fired, 0 fixed, 0 findings, 0 rejectedmodel cost $0.0029

Analysis Nemotron 3 Super

Flags implicit type coercions like !!expr, +expr, expr+'', etc., suggesting explicit Boolean(), Number(), String() calls.

Fix: Rewrites implicit coercions to explicit constructor calls: !!expr → Boolean(expr), +expr/-expr patterns → Number(expr), ''+expr/template literals → String(expr), and compound assignments like foo+= '' → foo = String(foo).

9 hazards
  • The fix assumes expr has no side effects; if expr is a function call or property access with side effects, duplicating it in the fix (e.g., Number(foo()) vs original +foo()) changes evaluation count.
  • If expr evaluates to an object with a custom valueOf/toString, the implicit coercion may trigger those methods differently than the explicit constructor (though ES6+ spec aligns them, edge cases exist in proxy objects).
  • In expressions like foo += '', the fix foo = String(foo) changes the assignment target if foo is a complex lhs (e.g., obj.prop += '' becomes obj.prop = String(obj.prop), which is safe, but if foo is a dereference like arr[0] += '', it remains safe; however, if the lhs involves getters/setters, the fix may invoke the setter once instead of twice (get + set vs just set).
  • The fix removes any whitespace or formatting from the original expression (e.g., +  foo becomes Number(foo)), which is harmless but strips user formatting.
  • If the original code relied on the implicit coercion producing NaN or 0 for non-numeric inputs (e.g., +undefined), the fix behaves identically, so no hazard here—this is actually safe.
  • In rare cases involving @@toPrimitive symbols, the order of hint preference between implicit and explicit coercion could differ pre-ES2015, but modern engines unify this.
  • If the expression is wrapped in parentheses with a comment (e.g., +(/* hint */foo)), the fix may drop the comment during rewrite, losing developer intent.
  • When the coerced result is used immediately in a larger expression (e.g., +foo + 1), the fix Number(foo) + 1 preserves precedence and behavior, so no hazard.
  • If the variable foo is const and the fix attempts to reassign it (only relevant for foo += '' cases), the linter would not suggest the fix for const variables, so this hazard does not apply—the tool correctly avoids proposing invalid fixes.

Programs

idresulttitlehazard
r1-p001silent prediction off__proto__ keys and property access interaction1. __proto__ keys, prototype access, Object.assign vs spread
r1-p002fired, no fixParenthesized expression with inline comment losing comment after fix2. Parenthesized expression with comment may lose comment during rewrite
r1-p003fired, no fixCompound assignment with getter-setter side effect counting3. Compound assignment lhs with getters/setters may invoke setter once instead of twice
r1-p004fired, no fix prediction offNon-numeric input coercion safety check (+undefined)4. Implicit coercion producing NaN/0 for non-numeric inputs is safe under fix
r1-p005fired, no fixFunction declaration inside block scoped by if statement5. Function declarations inside blocks, switch cases, labeled statements
r1-p006fired, no fixThis binding in extracted method called via call()6. This binding: arrow vs function, methods extracted from objects, call/apply/bind
r1-p007fired, no fixLabelled break with continue in nested loop interacting with coerced value7. Label/break/continue control flow, finally blocks, early returns in nested blocks
r1-p008fired, no fixGetter invocation count change due to rewrite of +getter8. Getters, setters and Object.defineProperty side effects
r2-p001fired, no fixCustom valueOf/toString in Proxy breaks equivalenceIf expr evaluates to an object with a custom valueOf/toString, the implicit coercion may trigger those methods differently than the explicit constructor.
r2-p002fired, no fixSide effect duplication in function callThe fix assumes expr has no side effects; if expr is a function call or property access with side effects, duplicating it in the fix (e.g., Number(foo()) vs original +foo()) changes evaluation count.
r2-p003fired, no fix__proto__ key interaction with assignment__proto__ keys, prototype access, Object.assign vs spread
r2-p004fired, no fixSparse array hole in implicit coercion contextsparse arrays, holes, Array(n) vs [n], array-likes
r2-p005fired, no fixASI hazard with leading parenthesisASI and semicolon-less code, leading ( or [ on the next line
r2-p006fired, no fix prediction offCoerced result used in larger expression (control)When the coerced result is used immediately in a larger expression (e.g., +foo + 1), the fix Number(foo) + 1 preserves precedence and behavior, so no hazard.
r2-p007fired, no fixVar hoisting and re-declaration in loopvar hoisting and re-declaration inside loops or after use
r2-p008fired, no fixComment attached to moved code affects readability but not semanticscomments attached to the removed or moved code

Sources

r1-p001 · __proto__ keys and property access interaction
1let o = {a: 1}; let p = {}; p.__proto__ = o;
2function f(x){ return x + 0; }
3console.log(f(p.a));
1
r1-p002 · Parenthesized expression with inline comment losing comment after fix
1let x = 5;
2let y = +(/* keep this */x);
3console.log(typeof y, y);
number 5
r1-p003 · Compound assignment with getter-setter side effect counting
1let val = 0;
2const obj = {
3 get prop(){ return val; },
4 set prop(v){ val = v; log.push('set:' + v); }
5};
6let log = [];
7obj.prop += '';
8console.log(log.join('|'), val);
set:0 0
r1-p004 · Non-numeric input coercion safety check (+undefined)
1let u;
2console.log(typeof +u, +u);
3console.log(typeof Number(u), Number(u));
number NaN
number NaN
r1-p005 · Function declaration inside block scoped by if statement
1if(true){
2 function f(){ return +''; }
3 console.log(f());
4}
5console.log(typeof f);
0
function
r1-p006 · This binding in extracted method called via call()
1const obj = {val: 42, getNum(){ return +this.val; }};
2const fn = obj.getNum;
3try{ console.log(fn.call(obj)); }catch(e){ console.log(e.name); }
42
r1-p007 · Labelled break with continue in nested loop interacting with coerced value
1outer: for(let i=0;i<2;i++){
2 for(let j=0;j<2;j++){
3 if(j===1) continue outer;
4 let x = +'';
5 console.log(i+j+x);
6 }
7}
0
1
r1-p008 · Getter invocation count change due to rewrite of +getter
1let count = 0;
2let obj = {};
3Object.defineProperty(obj, 'x', {
4 get(){ count++; return 5; }
5});
6console.log(+obj.x, count);
5 1
r2-p001 · Custom valueOf/toString in Proxy breaks equivalence
1let obj = new Proxy({ valueOf: () => { console.log('valueOf'); return 42; }, toString: () => { console.log('toString'); return '42'; } }, {});
2console.log(+obj);
3console.log(Boolean(obj));
valueOf
42
true
r2-p002 · Side effect duplication in function call
1let count = 0;
2function foo() { count++; return '5';
3}
4console.log(+foo());
5console.log(count);
5
1
r2-p003 · __proto__ key interaction with assignment
1let o = {};
2o['__proto__'] = { valueOf: () => 99 };
3console.log(+o);
99
r2-p004 · Sparse array hole in implicit coercion context
1let arr = Array(1);
2arr[0] = '5';
3console.log(+arr);
5
r2-p005 · ASI hazard with leading parenthesis
1let x = 1
2(+x).toString()
3console.log(x)
r2-p006 · Coerced result used in larger expression (control)
1let foo = '5';
2console.log(+foo + 1);
6
r2-p007 · Var hoisting and re-declaration in loop
1for (var i = 0; i < 1; i++) {
2 var x = '10';
3 console.log(+x);
4}
5console.log(typeof x);
10
string
r2-p008 · Comment attached to moved code affects readability but not semantics
1let y = '7' // inline comment
2;console.log(+y); // another
7