fixhunt

eslint prefer-exponentiation-operator

labelled safe
Runs / 2026-10-22T18-26-37-669Z-tava-eslint-prefer-exponentiation-operatoreslint 9.39.52026-10-22 18:26 UTC8 programs × 2 round(s)16 programs, 12 fired, 11 fixed, 1 findings, 1 rejectedmodel cost $0.0097

Analysis Nemotron 3 Super

The rule flags any call expression where the callee is exactly 'Math.pow' and replaces it with the '**

Fix: Replace every occurrence of Math.pow(base, exponent) with base ** exponent.

10 hazards
  • If either operand contains side effects (e.g., function calls), changing from Math.pow(a(), b()) to a() ** b() may alter evaluation order if the language specification differed—though both evaluate left-to-right, the rewrite assumes identical semantics and any future spec change could break equivalence.
  • If 'Math' is rebound in the current scope (e.g., var Math = {};), the original code would reference the binding while the fix assumes the global Math, potentially causing a ReferenceError or wrong value.
  • If 'pow' is rebound as a property of Math (e.g., Math.pow = function(){return 0;}), the fix bypasses the overridden method and uses the built-in operator, altering behavior.
  • If the code relies on Math.pow's specific handling of NaN or signed zeros (though ** matches), any future divergence in engine implementations could cause subtle differences.
  • If the expression includes decorators, annotations, or non-standard syntax that attaches meaning to the call site, stripping the call form could lose metadata.
  • If the codebase uses a transpiler that treats Math.pow specially (e.g., for polyfilling older engines), replacing it with ** might interfere with the transpiler's output.
  • If a comment is attached to the Math token or the dot (e.g., Math/*ignore*/.pow(2,3)), the autofix may discard the comment when rewriting to 2 ** 3.
  • If the arguments are expressions that themselves contain commas (e.g., Math.pow(a, b, c)), the rule does not fire because the shape is invalid, but if mistakenly applied, the fix would produce a SyntaxError.
  • If the code is parsed in strict mode and Math is not defined, the original throws a ReferenceError; the fix would throw a ReferenceError earlier when evaluating the left-hand side if it is an undefined variable, changing timing but not outcome.
  • If the exponentiation operator is used in a context where an expression is expected but the surrounding code relies on the call being a valid LeftHandSideExpression (e.g., in destructuring like [Math.pow] = []), the fix breaks because ** cannot appear there.

Findings

programoraclelabeljudgestatussummary
r2-p003fix-changes-behaviorlabelled safereal · highrelatedThe program redefines `Math.pow` to perform addition, so `Math.pow(2, 3)` returns 5. The fix replaces the call with `2 ** 3`, which uses the built-in exponenti…

Programs

idresulttitlehazard
r1-p001fired, no fixComment Discard HazardIf a comment is attached to the Math token or the dot (e.g., Math/*ignore*/.pow(2,3)), the autofix may discard the comment when rewriting to 2 ** 3.
r1-p002fix okNaN/Signed Zero Handling HazardIf the code relies on Math.pow's specific handling of NaN or signed zeros (though ** matches), any future divergence in engine implementations could cause subtle differences.
r1-p003silentComma Expression Argument HazardIf the arguments are expressions that themselves contain commas (e.g., Math.pow(a, b, c)), the rule does not fire because the shape is invalid, but if mistakenly applied, the fix would produce a Synta
r1-p004fix okAsync/Await/Yield Position Hazardasync/await ordering, generators and yield position
r1-p005silent prediction offMath Rebound in Scope HazardIf 'Math' is rebound in the current scope (e.g., var Math = {};), the original code would reference the binding while the fix assumes the global Math, potentially causing a ReferenceError or wrong val
r1-p006fix ok__proto__/Prototype Access Hazard__proto__ keys, prototype access, Object.assign vs spread
r1-p007fix okNumeric/String Coercion Hazardnumeric/string coercion: + vs template literal, objects with toString/valueOf, Symbol, BigInt
r1-p008fix okNull/Undefined Distinction Hazardnull/undefined distinction, optional chaining short-circuit, nullish vs falsy
r2-p001fix okSide Effects in OperandsIf either operand contains side effects (e.g., function calls), changing from Math.pow(a(), b()) to a() ** b() may alter evaluation order if the language specification differed—though both evaluate le
r2-p002fix okNull/Undefined Distinctionnull/undefined distinction, optional chaining short-circuit, nullish vs falsy
r2-p003fix-changes-behaviorRebound Math.pow PropertyIf 'pow' is rebound as a property of Math (e.g., Math.pow = function(){return 0;}), the fix bypasses the overridden method and uses the built-in operator, altering behavior.
r2-p004fix okSparse Arrays and Holessparse arrays, holes, Array(n) vs [n], array-likes
r2-p005fix okArguments Object and Parametersarguments object, function.length, default parameters, rest parameters
r2-p006invalidStrict vs Sloppy Mode Semanticsstrict vs sloppy mode semantics
r2-p007silentComma Expressions in ArgumentsIf the arguments are expressions that themselves contain commas (e.g., Math.pow(a, b, c)), the rule does not fire because the shape is invalid, but if mistakenly applied, the fix would produce a Synta
r2-p008fix okTemporal Dead Zone After Hoistingtemporal dead zone after code is hoisted or reordered

Sources

r1-p001 · Comment Discard Hazard
1let result;
2try {
3 // Comment attached after dot
4 result = Math//comment
5 .pow(2, 3);
6 console.log('Success:', result);
7} catch (e) {
8 console.log('Error:', e.name, e.message);
9}
Success: 8
r1-p002 · NaN/Signed Zero Handling Hazard
1console.log(Math.pow(-0, -1)); // Should be -Infinity
2console.log((-0) ** (-1)); // Same currently, but testing equivalence
3console.log(Math.pow(NaN, 0)); // Should be 1
4console.log(NaN ** 0); // Same currently
--- orig.js	2026-10-22 14:26:47.923829742 -0400
+++ fixed.js	2026-10-22 14:26:50.545779858 -0400
@@ -1,4 +1,4 @@
-console.log(Math.pow(-0, -1)); // Should be -Infinity
+console.log((-0)**-1); // Should be -Infinity
 console.log((-0) ** (-1));     // Same currently, but testing equivalence
-console.log(Math.pow(NaN, 0));   // Should be 1
+console.log(NaN**0);   // Should be 1
 console.log(NaN ** 0);         // Same currently
-Infinity
-Infinity
1
1
r1-p003 · Comma Expression Argument Hazard
1const a = 2, b = 3, c = 4;
2// This has three args -> rule should NOT fire
3if (false) {
4 // Hypothetical broken fix: Math.pow(a, b, c) -> a ** b, c
5 // Would be syntax error if uncommented
6 // Math.pow(a, b, c);
7}
8console.log('a:', a, 'b:', b, 'c:', c);
a: 2 b: 3 c: 4
r1-p004 · Async/Await/Yield Position Hazard
1async function foo() {
2 const x = await Math//no comment
3 .pow(2, 3);
4 return x;
5}
6foo().then(r => console.log('Async result:', r));
7
8function* gen() {
9 yield Math.pow(2, 3);
10}
11const g = gen();
12console.log('Generator first yield:', g.next().value);
--- orig.js	2026-10-22 14:26:47.924829722 -0400
+++ fixed.js	2026-10-22 14:26:51.775756714 -0400
@@ -6,7 +6,7 @@
 foo().then(r => console.log('Async result:', r));
 
 function* gen() {
-  yield Math.pow(2, 3);
+  yield 2**3;
 }
 const g = gen();
 console.log('Generator first yield:', g.next().value);
Generator first yield: 8
Async result: 8
r1-p005 · Math Rebound in Scope Hazard
1var Math = { pow: (b, e) => b * e }; // Local rebinding
2console.log('Local Math.pow(2,3):', Math.pow(2, 3));
3try {
4 // This would be rewritten to 2 ** 3 by the rule, ignoring local Math
5 // But we simulate what the broken fix would do:
6 const brokenFix = 2 ** 3;
7 console.log('Broken fix (2**3):', brokenFix);
8} catch (e) {
9 console.log('Error in fix simulation:', e.name, e.message);
10}
Local Math.pow(2,3): 6
Broken fix (2**3): 8
r1-p006 · __proto__/Prototype Access Hazard
1const obj = {};
2obj.__proto__.Math = { pow: (b, e) => b + e };
3console.log('obj.Math.pow(2,3):', obj.Math.pow(2, 3));
4// Rule would see obj.Math.pow and NOT fire (not direct Math)
5// So no rewrite happens here.
6console.log('Global Math.pow(2,3):', Math.pow(2, 3));
--- orig.js	2026-10-22 14:26:47.925829703 -0400
+++ fixed.js	2026-10-22 14:26:51.413763510 -0400
@@ -3,4 +3,4 @@
 console.log('obj.Math.pow(2,3):', obj.Math.pow(2, 3));
 // Rule would see obj.Math.pow and NOT fire (not direct Math)
 // So no rewrite happens here.
-console.log('Global Math.pow(2,3):', Math.pow(2, 3));
+console.log('Global Math.pow(2,3):', 2**3);
obj.Math.pow(2,3): 5
Global Math.pow(2,3): 8
r1-p007 · Numeric/String Coercion Hazard
1const val = { valueOf: () => 2, toString: () => '2' };
2console.log('Math.pow(val, 3):', Math.pow(val, 3));
3console.log('val ** 3:', val ** 3);
4
5const sym = Symbol(1);
6try {
7 console.log(Math.pow(sym, 2));
8} catch (e) {
9 console.log('Math.pow(Symbol) error:', e.name);
10}
11try {
12 console.log(sym ** 2);
13} catch (e) {
14 console.log('Symbol ** error:', e.name);
15}
--- orig.js	2026-10-22 14:26:49.998790189 -0400
+++ fixed.js	2026-10-22 14:26:53.768719579 -0400
@@ -1,10 +1,10 @@
 const val = { valueOf: () => 2, toString: () => '2' };
-console.log('Math.pow(val, 3):', Math.pow(val, 3));
+console.log('Math.pow(val, 3):', val**3);
 console.log('val ** 3:', val ** 3);
 
 const sym = Symbol(1);
 try {
-  console.log(Math.pow(sym, 2));
+  console.log(sym**2);
 } catch (e) {
   console.log('Math.pow(Symbol) error:', e.name);
 }
Math.pow(val, 3): 8
val ** 3: 8
Math.pow(Symbol) error: TypeError
Symbol ** error: TypeError
r1-p008 · Null/Undefined Distinction Hazard
1let x = null;
2console.log('x?.prop?.Math?.pow?.(2,3):', x?.prop?.Math?.pow?.(2, 3));
3
4x = { prop: { Math: { pow: (b, e) => b ** e } } };
5console.log('x?.prop?.Math?.pow?.(2,3):', x?.prop?.Math?.pow?.(2, 3));
6
7// Direct call that rule would fire on
8const base = 2;
9exp = 3;
10console.log('Math.pow(base,exp):', Math.pow(base, exp));
11console.log('base ** exp:', base ** exp);
--- orig.js	2026-10-22 14:26:50.434781954 -0400
+++ fixed.js	2026-10-22 14:26:53.066732602 -0400
@@ -7,5 +7,5 @@
 // Direct call that rule would fire on
 const base = 2;
 exp = 3;
-console.log('Math.pow(base,exp):', Math.pow(base, exp));
+console.log('Math.pow(base,exp):', base**exp);
 console.log('base ** exp:', base ** exp);
x?.prop?.Math?.pow?.(2,3): undefined
x?.prop?.Math?.pow?.(2,3): 8
Math.pow(base,exp): 8
base ** exp: 8
r2-p001 · Side Effects in Operands
1let x = 0;
2const inc = () => {
3 x++;
4 return x;
5};
6console.log(Math.pow(inc(), inc()));
7x = 0;
8console.log(inc() ** inc());
--- orig.js	2026-10-22 14:27:00.173603221 -0400
+++ fixed.js	2026-10-22 14:27:02.863555701 -0400
@@ -3,6 +3,6 @@
   x++;
   return x;
 };
-console.log(Math.pow(inc(), inc()));
+console.log(inc()**inc());
 x = 0;
 console.log(inc() ** inc());
1
1
r2-p002 · Null/Undefined Distinction
1let val = null;
2try {
3 console.log(Math.pow(val, 2));
4} catch (e) {
5 console.log(e.name + ': ' + e.message);
6}
7val = undefined;
8try {
9 console.log(val ** 2);
10} catch (e) {
11 console.log(e.name + ': ' + e.message);
12}
--- orig.js	2026-10-22 14:27:00.174603203 -0400
+++ fixed.js	2026-10-22 14:27:02.980553647 -0400
@@ -1,6 +1,6 @@
 let val = null;
 try {
-  console.log(Math.pow(val, 2));
+  console.log(val**2);
 } catch (e) {
   console.log(e.name + ': ' + e.message);
 }
0
NaN
r2-p003 · Rebound Math.pow Property
1Math.pow = function(base, exp) { return base + exp; };
2console.log(Math.pow(2, 3));
3depth = 0;
4while (depth < 1) {
5 console.log(2 ** 3);
6 depth++;
7}
--- orig.js	2026-10-22 14:27:00.174603203 -0400
+++ fixed.js	2026-10-22 14:27:02.947554227 -0400
@@ -1,5 +1,5 @@
 Math.pow = function(base, exp) { return base + exp; };
-console.log(Math.pow(2, 3));
+console.log(2**3);
 depth = 0;
 while (depth < 1) {
   console.log(2 ** 3);
5
8
r2-p004 · Sparse Arrays and Holes
1const arr = Array(3);
2arr[2] = 2;
3console.log(Math.pow(arr[0], arr[2]));
4console.log(arr[0] ** arr[2]);
--- orig.js	2026-10-22 14:27:00.175603185 -0400
+++ fixed.js	2026-10-22 14:27:02.896555122 -0400
@@ -1,4 +1,4 @@
 const arr = Array(3);
 arr[2] = 2;
-console.log(Math.pow(arr[0], arr[2]));
+console.log(arr[0]**arr[2]);
 console.log(arr[0] ** arr[2]);
NaN
NaN
r2-p005 · Arguments Object and Parameters
1function test(a = 2, b = 3) {
2 console.log(arguments.length);
3 console.log(Math.pow(a, b));
4}
5test();
6function test2() {
7 console.log(arguments.length);
8 console.log((arguments[0] || 2) ** (arguments[1] || 3));
9}
10test2();
--- orig.js	2026-10-22 14:27:00.176603168 -0400
+++ fixed.js	2026-10-22 14:27:02.871555561 -0400
@@ -1,6 +1,6 @@
 function test(a = 2, b = 3) {
   console.log(arguments.length);
-  console.log(Math.pow(a, b));
+  console.log(a**b);
 }
 test();
 function test2() {
0
8
0
8
r2-p006 · Strict vs Sloppy Mode Semantics (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-22T18-26-3)
1"use strict";
2(function() {
3 try {
4 with ({Math: {pow: (b, e) => b + e}}) {
5 console.log(Math.pow(2, 3));
6 }
7 } catch (e) {
8 console.log(e.name);
9 }
10})();
11(function() {
12 "use strict";
13 try {
14 with ({Math: {pow: (b, e) => b + e}}) {
15 console.log(2 ** 3);
16 }
17 } catch (e) {
18 console.log(e.name);
19 }
20})();
r2-p007 · Comma Expressions in Arguments
1// This line would be invalid if fixed incorrectly
2// Math.pow(1, 2, 3); // Rule does not fire (too many args)
3// 1 ** 2 ** 3; // Would be SyntaxError if mistakenly generated
4console.log('No trigger - comma in args invalid for Math.pow');
No trigger - comma in args invalid for Math.pow
r2-p008 · Temporal Dead Zone After Hoisting
1console.log(typeof base);
2console.log(typeof exp);
3var base = 2;
4var exp = 3;
5console.log(Math.pow(base, exp));
6base = 4;
7exp = 2;
8console.log(base ** exp);
--- orig.js	2026-10-22 14:27:02.739557878 -0400
+++ fixed.js	2026-10-22 14:27:05.358512341 -0400
@@ -2,7 +2,7 @@
 console.log(typeof exp);
 var base = 2;
 var exp = 3;
-console.log(Math.pow(base, exp));
+console.log(base**exp);
 base = 4;
 exp = 2;
 console.log(base ** exp);
undefined
undefined
8
16