Skip to content

Commit 109f18b

Browse files
Copilotjakebailey
andauthored
Fix async arrow this capture in static field emit (#4103)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: jakebailey <5341706+jakebailey@users.noreply.github.com>
1 parent 503ea95 commit 109f18b

5 files changed

Lines changed: 51 additions & 0 deletions

File tree

internal/printer/emitflags.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const (
2727
EFAsyncFunctionBody // The node was originally an async function body.
2828
EFNoLexicalArguments // Do not capture `arguments` for this arrow function. Set on arrows lowered from class static blocks, where `arguments` is an error; preserves Strada's emit behavior.
2929
EFTransformPrivateStaticElements // Indicates static private elements in a file or class should be transformed regardless of --target (used by esDecorators transform).
30+
EFNoLexicalThis // Do not capture `this` for this node's subtree. Set on relocated static initializers, where `this` is handled by the class fields transform.
3031
)
3132

3233
const (

internal/transformers/estransforms/async.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,11 @@ func (tx *asyncTransformer) visit(node *ast.Node) *ast.Node {
136136
cleanup := tx.descendInto(node)
137137
defer cleanup()
138138

139+
if tx.EmitContext().EmitFlags(node)&printer.EFNoLexicalThis != 0 && tx.inHasLexicalThisContext() {
140+
tx.setContextFlag(asyncContextHasLexicalThis, false)
141+
defer tx.setContextFlag(asyncContextHasLexicalThis, true)
142+
}
143+
139144
if node.SubtreeFacts()&(ast.SubtreeContainsAnyAwait|ast.SubtreeContainsAwait) == 0 {
140145
return tx.fallbackVisitor(node)
141146
}

internal/transformers/estransforms/classfields.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,6 +1415,7 @@ func (tx *classFieldsTransformer) transformClassStaticBlockDeclaration(node *ast
14151415
arrowFunction.AsArrowFunction().Body.AsBlock().Statements.Loc = node.AsClassStaticBlockDeclaration().Body.AsBlock().Statements.Loc
14161416
tx.EmitContext().SetOriginal(iife, node)
14171417
tx.EmitContext().AssignSourceMapRange(iife, node)
1418+
tx.EmitContext().AddEmitFlags(arrowFunction, printer.EFNoLexicalThis)
14181419
return iife
14191420
}
14201421
return nil
@@ -2712,6 +2713,9 @@ func (tx *classFieldsTransformer) generateInitializedPropertyExpressionsOrClassS
27122713
func (tx *classFieldsTransformer) transformProperty(property *ast.PropertyDeclaration, receiver *ast.Expression) *ast.Expression {
27132714
savedCurrentClassElement := tx.currentClassElement
27142715
transformed := tx.transformPropertyWorker(property, receiver)
2716+
if transformed != nil && ast.HasStaticModifier(property.AsNode()) {
2717+
tx.EmitContext().AddEmitFlags(transformed, printer.EFNoLexicalThis)
2718+
}
27152719
if transformed != nil && ast.HasStaticModifier(property.AsNode()) &&
27162720
tx.lexicalEnvironment != nil && tx.lexicalEnvironment.data != nil && tx.lexicalEnvironment.data.facts != 0 {
27172721
// capture the lexical environment for the member
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//// [tests/cases/compiler/asyncArrowStaticFieldThis.ts] ////
2+
3+
//// [asyncArrowStaticFieldThis.ts]
4+
namespace NS {
5+
export class C {
6+
static h = async () => 1;
7+
static i = async () => this.h;
8+
}
9+
}
10+
11+
12+
//// [asyncArrowStaticFieldThis.js]
13+
"use strict";
14+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
15+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
16+
return new (P || (P = Promise))(function (resolve, reject) {
17+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
18+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
19+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
20+
step((generator = generator.apply(thisArg, _arguments || [])).next());
21+
});
22+
};
23+
var NS;
24+
(function (NS) {
25+
var _a;
26+
class C {
27+
}
28+
_a = C;
29+
C.h = () => __awaiter(void 0, void 0, void 0, function* () { return 1; });
30+
C.i = () => __awaiter(void 0, void 0, void 0, function* () { return _a.h; });
31+
NS.C = C;
32+
})(NS || (NS = {}));
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// @target: es2015
2+
// @noTypesAndSymbols: true
3+
4+
namespace NS {
5+
export class C {
6+
static h = async () => 1;
7+
static i = async () => this.h;
8+
}
9+
}

0 commit comments

Comments
 (0)