biome style/useConsistentArrowReturn
labelled safe
Analysis Nemotron 3 Super
The rule flags arrow functions with a block body containing only a single return statement.
Fix: Replace the block body with a concise arrow body by removing braces and the return keyword, wrapping the returned expression in parentheses if needed to avoid parsing ambiguities (e.g., object literals become ({ ... }) and comma-separated expressions remain grouped).
9 hazards
- Rewriting `() => { return expr, expr; }` as `() => (expr, expr)` changes evaluation order if the comma expression relies on left-to-right side effects being visible before the fix (though value is same, timing of side effects may differ in debuggers or proxies).
- If the returned expression is an object literal like `{ a: 1 }`, omitting parentheses during rewrite would cause a parse error (`{` interpreted as block start), but the fix adds them—however, if the original code relied on automatic semicolon insertion after the block, adding parentheses could alter ASI boundaries in edge cases involving newlines.
- When the arrow function is used as a constructor via `new`, the concise form may incorrectly return the wrapped expression instead of the newly created instance (though arrow functions aren’t constructible, this is more theoretical; if mistakenly called via `Reflect.construct`, behavior diverges).
- If the return expression contains a `yield` (in generator context), rewriting breaks because arrow functions cannot be generators, but the rule doesn’t fire on generators anyway—still, if misapplied due to incorrect parsing, it would invalidate syntax.
- In non-strict mode, if the function body contained a `with` statement (invalid in strict), but the rule doesn’t fire on multi-statement bodies, so not applicable—however, if a single `return with (x) {}` existed, the fix would preserve it, but `with` is deprecated and rarely used.
- If the returned expression is a class declaration like `class C {}`, rewriting as `() => class C {}` is fine, but if the original relied on the block creating a lexical scope for `let`/`const` inside (which it doesn’t—returns don’t create scopes), no issue arises.
- If the arrow function’s body had a trailing comment after `return` (e.g., `return x; // note`), the rule stays silent per documentation, so no fix is applied—thus no hazard from comment loss in fired cases.
- If the function is part of a larger expression like `x = () => { return y }()`, the fix changes precedence grouping; however, since the arrow function call is immediate, the value is unchanged, but if the return expression were itself a function call with side effects, the timing of evaluation relative to outer expressions remains identical due to call semantics.
- In TypeScript or JSX contexts, if the arrow function returns a JSX element like `<div />`, rewriting as `() => (<div />)` is valid, but if the original block had a comment or directive (excluded), no issue—however, tools that rely on block-body structure for formatting may reformat incorrectly post-fix.
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | fix ok | Regular Expression with Unicode Flag | Rewriting changes regex literal precedence due to missing grouping parentheses when followed by operators. |
| r1-p003 | fix ok prediction off | This Binding in Method Extraction | Removing block braces does not affect arrow function's lexical this, but exposes reliance on outer this via closure. |
| r1-p004 | fix ok | Function Declaration Inside Switch Case | Rule fires on inner arrow function; rewriting changes temporal dead zone behavior if return expr uses let from case scope. |
| r1-p005 | silent | Yield in Return Expression (Generator Context) | Rule does not fire on generators, but simulating misfire shows syntax error if arrow function incorrectly rewritten to contain yield. |
| r1-p006 | fix ok | Name Collision Across Scopes After Move | Rewriting moves arrow function to outer scope, causing it to capture a different variable due to shadowing. |
| r1-p007 | fix ok | Class Declaration Returned | Rule rewrites return of class declaration; though semantically safe, we verify no scoping issues arise from removed block. |
| r1-p008 | fix ok | __proto__ Key in Object Literal | Rule rewrites object literal return; ensures __proto__ key is preserved and not interpreted as actual proto setter. |
| r2-p001 | fix ok | Constructor Use with Reflect.construct | When the arrow function is used as a constructor via new or Reflect.construct, the concise form may incorrectly return the wrapped expression instead of honoring construction semantics. |
| r2-p002 | fix ok | Order of Evaluation with Side Effects | order of evaluation when expressions are merged, duplicated or deleted (side effects run twice or never) |
| r2-p003 | invalid | With Statement in Non-Strict Mode (Single Return) | In non-strict mode, if the function body contained a `with` statement (invalid in strict), but the rule doesn’t fire on multi-statement bodies, so not applicable—however, if a single `return with (x) |
| r2-p004 | silent prediction off | Exceptions Thrown Inside Rewritten Code | exceptions thrown inside the code the fix removes or rewrites |
| r2-p005 | fix ok | Comma Expression Evaluation Order | Rewriting `() => { return expr, expr; }` as `() => (expr, expr)` changes evaluation order if the comma expression relies on left-to-right side effects being visible before the fix (though value is sam |
| r2-p006 | fix ok | Object.defineProperty Side Effects | getters, setters and Object.defineProperty side effects |
| r2-p007 | fix ok | Function Declaration Inside Block/Switch/Label | function declarations inside blocks, switch cases, labeled statements |
| r2-p008 | fix ok | Strict vs Sloppy Mode Semantics | strict vs sloppy mode semantics |
Sources
r1-p001 · Regular Expression with Unicode Flag
1const pattern = 'ab';
2const matchIt = s => {
3 return new RegExp(pattern, 'u').test(s);
4};
5console.log(matchIt('áb'));
--- orig.js 2026-10-17 17:00:25.936783184 -0400 +++ fixed.js 2026-10-17 17:00:26.230786855 -0400 @@ -1,5 +1,3 @@ const pattern = 'ab'; -const matchIt = s => { - return new RegExp(pattern, 'u').test(s); -}; +const matchIt = s => new RegExp(pattern, 'u').test(s); console.log(matchIt('áb'));
false
r1-p003 · This Binding in Method Extraction
1const obj = {
2 value: 42,
3 getValue: function() {
4 return () => { return this.value; };
5 }
6};
7const fn = obj.getValue();
8console.log(fn()); // Should print 42
--- orig.js 2026-10-17 17:00:26.397788940 -0400 +++ fixed.js 2026-10-17 17:00:26.663792261 -0400 @@ -1,7 +1,7 @@ const obj = { value: 42, getValue: function() { - return () => { return this.value; }; + return () => this.value; } }; const fn = obj.getValue();
42
r1-p004 · Function Declaration Inside Switch Case
1switch (1) {
2 case 1:
3 let x = 10;
4 const getX = () => { return x; };
5 break;
6}
7try {
8 console.log(getX());
9} catch (e) {
10 console.log(e.name + ': ' + e.message);
11}
--- orig.js 2026-10-17 17:00:26.840794471 -0400 +++ fixed.js 2026-10-17 17:00:27.111797854 -0400 @@ -1,7 +1,7 @@ switch (1) { case 1: let x = 10; - const getX = () => { return x; }; + const getX = () => x; break; } try {
ReferenceError: getX is not defined
r1-p005 · Yield in Return Expression (Generator Context)
1function* gen() {
2 yield 1;
3}
4const g = gen();
5console.log(g.next().value);
1
r1-p006 · Name Collision Across Scopes After Move
1let x = 1;
2{
3 let x = 2;
4 const getX = () => { return x; };
5 console.log(getX()); // Prints 2
6}
7console.log(getX()); // After rewrite: prints 1 (outer x)
--- orig.js 2026-10-17 17:00:27.501802721 -0400 +++ fixed.js 2026-10-17 17:00:27.764806004 -0400 @@ -1,7 +1,7 @@ let x = 1; { let x = 2; - const getX = () => { return x; }; + const getX = () => x; console.log(getX()); // Prints 2 } console.log(getX()); // After rewrite: prints 1 (outer x)
2
r1-p007 · Class Declaration Returned
1const makeClass = () => {
2 return class {
3 constructor() { this.x = 1; }
4 };
5};
6const C = makeClass();
7const c = new C();
8console.log(c.x);
--- orig.js 2026-10-17 17:00:27.937808163 -0400 +++ fixed.js 2026-10-17 17:00:28.216811643 -0400 @@ -1,8 +1,6 @@ -const makeClass = () => { - return class { +const makeClass = () => class { constructor() { this.x = 1; } }; -}; const C = makeClass(); const c = new C(); console.log(c.x);
1
r1-p008 · __proto__ Key in Object Literal
1const makeObj = () => {
2 return { __proto__: null, a: 1 };
3};
4const o = makeObj();
5console.log(o.__proto__ === null && o.a === 1);
--- orig.js 2026-10-17 17:00:28.387813776 -0400 +++ fixed.js 2026-10-17 17:00:28.662817207 -0400 @@ -1,5 +1,3 @@ -const makeObj = () => { - return { __proto__: null, a: 1 }; -}; +const makeObj = () => ({ __proto__: null, a: 1 }); const o = makeObj(); console.log(o.__proto__ === null && o.a === 1);
false
r2-p001 · Constructor Use with Reflect.construct
1const Target = class {
2 constructor(x) { this.value = x; }
3};
4let madeViaNew = null;
5try {
6 madeViaNew = new Target(1);
7} catch (_) {}
8console.log('madeViaNew:', madeViaNew ? madeViaNew.value : 'none');
9
10// Arrow function returning class - rule triggers here
11const makeTarget = (cls) => { return cls; };
12let madeViaConstruct = null;
13try {
14 // Simulate incorrect construction attempt using Reflect.construct
15 madeViaConstruct = Reflect.construct(makeTarget([Target]), []);
16} catch (e) {
17 console.error(e.name + ': ' + e.message);
18}
19if (madeViaConstruct && madeViaConstruct.value !== undefined) {
20 console.log('madeViaConstruct.value:', madeViaConstruct.value);
21} else if (madeViaConstruct instanceof Target) {
22 console.log('madeViaConstruct is instance:', madeViaConstruct.value);
23} else {
24 console.log('madeViaConstruct:', madeViaConstruct);
25}
--- orig.js 2026-10-17 17:00:36.839919001 -0400 +++ fixed.js 2026-10-17 17:00:37.127922579 -0400 @@ -8,7 +8,7 @@ console.log('madeViaNew:', madeViaNew ? madeViaNew.value : 'none'); // Arrow function returning class - rule triggers here -const makeTarget = (cls) => { return cls; }; +const makeTarget = (cls) => cls; let madeViaConstruct = null; try { // Simulate incorrect construction attempt using Reflect.construct
madeViaNew: 1 madeViaConstruct: null
r2-p002 · Order of Evaluation with Side Effects
1let log = '';
2const side = (msg) => {
3 log += msg;
4 return msg.length;
5};
6
7// Arrow with comma expression - rule triggers
8const getVals = () => { return side('a'), side('b'); };
9
10const first = getVals();
11log += '|';
12const second = getVals();
13console.log('log:', log);
14console.log('first:', first);
15console.log('second:', second);
--- orig.js 2026-10-17 17:00:37.291924616 -0400 +++ fixed.js 2026-10-17 17:00:37.578928180 -0400 @@ -5,7 +5,7 @@ }; // Arrow with comma expression - rule triggers -const getVals = () => { return side('a'), side('b'); }; +const getVals = () => (side('a'), side('b')); const first = getVals(); log += '|';
log: ab|ab first: 1 second: 1
r2-p003 · With Statement in Non-Strict Mode (Single Return) (generated program does not parse: /home/sun/dev/diaghunt/runs/2026-10-17T21-00-1)
1(function(){
2 'use sloppy mode';
3 const obj = { x: 42 };
4 let result;
5 try {
6 // Not triggering rule because with statement makes it not a simple return
7 // But we show what happens if someone tried
8 result = (() => { with(obj) { return x; } })();
9 } catch (e) {
10 result = e.name + ': ' + e.message;
11 }
12 console.log('result:', result);
13})();
r2-p004 · Exceptions Thrown Inside Rewritten Code
1let threw = false;
2let errorMsg = '';
3
4// Arrow function that throws - rule triggers
5const risky = () => { throw new Error('fail'); };
6
7try {
8 risky();
9} catch (e) {
10 threw = true;
11 errorMsg = e.name + ': ' + e.message;
12}
13console.log('threw:', threw);
14console.log('error:', errorMsg);
threw: true error: Error: fail
r2-p005 · Comma Expression Evaluation Order
1let trace = '';
2const step = (label) => {
3 trace += label;
4 return label.charCodeAt(0);
5};
6
7// Comma return - rule triggers here
8const seq = () => { return step('A'), step('B'); };
9
10const val = seq();
11console.log('trace:', trace);
12console.log('value:', val);
--- orig.js 2026-10-17 17:00:38.030933795 -0400 +++ fixed.js 2026-10-17 17:00:38.302937171 -0400 @@ -5,7 +5,7 @@ }; // Comma return - rule triggers here -const seq = () => { return step('A'), step('B'); }; +const seq = () => (step('A'), step('B')); const val = seq(); console.log('trace:', trace);
trace: AB value: 66
r2-p006 · Object.defineProperty Side Effects
1let defined = false;
2let value = 99;
3const target = {};
4
5// Define a setter with side effect
6Object.defineProperty(target, 'prop', {
7 set(v) {
8 defined = true;
9 value = v * 2;
10 }
11});
12
13// Arrow returning object literal - rule triggers
14const makeObj = (v) => { return { prop: v }; };
15
16makeObj(5);
17console.log('defined:', defined);
18console.log('value:', value);
--- orig.js 2026-10-17 17:00:38.468939232 -0400 +++ fixed.js 2026-10-17 17:00:38.734942535 -0400 @@ -11,7 +11,7 @@ }); // Arrow returning object literal - rule triggers -const makeObj = (v) => { return { prop: v }; }; +const makeObj = (v) => ({ prop: v }); makeObj(5); console.log('defined:', defined);
defined: false value: 99
r2-p007 · Function Declaration Inside Block/Switch/Label
1{ // Block scope
2 let x = 1;
3 // Arrow in block - rule triggers
4 const inc = () => { return x + 1; };
5 x = inc();
6 console.log('block x:', x);
7}
8
9switch(1) {
10 case 1:
11 let y = 2;
12 // Arrow in case - rule triggers
13 const double = (z) => { return z * 2; };
14 y = double(y);
15 console.log('case y:', y);
16 break;
17}
18
19label: {
20 let z = 3;
21 // Arrow in labeled block
22 const addTen = () => { return z + 10; };
23 z = addTen();
24 console.log('labeled z:', z);
25 break label;
26}
--- orig.js 2026-10-17 17:00:38.896944546 -0400 +++ fixed.js 2026-10-17 17:00:39.187948158 -0400 @@ -1,7 +1,7 @@ { // Block scope let x = 1; // Arrow in block - rule triggers - const inc = () => { return x + 1; }; + const inc = () => x + 1; x = inc(); console.log('block x:', x); } @@ -10,7 +10,7 @@ case 1: let y = 2; // Arrow in case - rule triggers - const double = (z) => { return z * 2; }; + const double = (z) => z * 2; y = double(y); console.log('case y:', y); break; @@ -19,7 +19,7 @@ label: { let z = 3; // Arrow in labeled block - const addTen = () => { return z + 10; }; + const addTen = () => z + 10; z = addTen(); console.log('labeled z:', z); break label;
block x: 2 case y: 4 labeled z: 13
r2-p008 · Strict vs Sloppy Mode Semantics
1(function(){
2 'use strict';
3 let strictLog = '';
4 const strictFn = () => { return strictLog += 's'; };
5 strictFn();
6 console.log('strict:', strictLog);
7})();
8
9(function(){
10 // sloppy mode
11 let sloppyLog = '';
12 const sloppyFn = () => { return sloppyLog += 'S'; };
13 sloppyFn();
14 console.log('sloppy:', sloppyLog);
15})();
--- orig.js 2026-10-17 17:00:39.356950255 -0400 +++ fixed.js 2026-10-17 17:00:39.629953642 -0400 @@ -1,7 +1,7 @@ (function(){ 'use strict'; let strictLog = ''; - const strictFn = () => { return strictLog += 's'; }; + const strictFn = () => strictLog += 's'; strictFn(); console.log('strict:', strictLog); })(); @@ -9,7 +9,7 @@ (function(){ // sloppy mode let sloppyLog = ''; - const sloppyFn = () => { return sloppyLog += 'S'; }; + const sloppyFn = () => sloppyLog += 'S'; sloppyFn(); console.log('sloppy:', sloppyLog); })();
strict: s sloppy: S