mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-10 18:04:18 -05:00
Support for assignment/destructuring using super in an async method
This commit is contained in:
@@ -6902,6 +6902,16 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
function isSuperPropertyAccess(node: Node) {
|
||||
return node.kind === SyntaxKind.PropertyAccessExpression
|
||||
&& (<PropertyAccessExpression>node).expression.kind === SyntaxKind.SuperKeyword;
|
||||
}
|
||||
|
||||
function isSuperElementAccess(node: Node) {
|
||||
return node.kind === SyntaxKind.ElementAccessExpression
|
||||
&& (<ElementAccessExpression>node).expression.kind === SyntaxKind.SuperKeyword;
|
||||
}
|
||||
|
||||
function checkSuperExpression(node: Node): Type {
|
||||
const isCallExpression = node.parent.kind === SyntaxKind.CallExpression && (<CallExpression>node.parent).expression === node;
|
||||
const classDeclaration = getContainingClass(node);
|
||||
@@ -6935,7 +6945,12 @@ namespace ts {
|
||||
|
||||
// Due to how we emit async functions, we need to specialize the emit for an async method that contains a `super` reference.
|
||||
if (container.kind === SyntaxKind.MethodDeclaration && container.flags & NodeFlags.Async) {
|
||||
getNodeLinks(container).flags |= NodeCheckFlags.AsyncMethodWithSuper;
|
||||
if ((isSuperPropertyAccess(node.parent) || isSuperElementAccess(node.parent)) && isAssignmentTarget(node.parent)) {
|
||||
getNodeLinks(container).flags |= NodeCheckFlags.AsyncMethodWithSuperBinding;
|
||||
}
|
||||
else {
|
||||
getNodeLinks(container).flags |= NodeCheckFlags.AsyncMethodWithSuper;
|
||||
}
|
||||
}
|
||||
|
||||
if (needToCaptureLexicalThis) {
|
||||
|
||||
@@ -2126,6 +2126,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
return;
|
||||
}
|
||||
|
||||
if (languageVersion === ScriptTarget.ES6 &&
|
||||
node.expression.kind === SyntaxKind.SuperKeyword &&
|
||||
isInAsyncMethodWithSuperInES6(node)) {
|
||||
const name = <StringLiteral>createSynthesizedNode(SyntaxKind.StringLiteral);
|
||||
name.text = node.name.text;
|
||||
emitSuperAccessInAsyncMethod(node.expression, name);
|
||||
return;
|
||||
}
|
||||
|
||||
emit(node.expression);
|
||||
const indentedBeforeDot = indentIfOnDifferentLines(node, node.expression, node.dotToken);
|
||||
|
||||
@@ -2207,6 +2216,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
if (tryEmitConstantValue(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (languageVersion === ScriptTarget.ES6 &&
|
||||
node.expression.kind === SyntaxKind.SuperKeyword &&
|
||||
isInAsyncMethodWithSuperInES6(node)) {
|
||||
emitSuperAccessInAsyncMethod(node.expression, node.argumentExpression);
|
||||
return;
|
||||
}
|
||||
|
||||
emit(node.expression);
|
||||
write("[");
|
||||
emit(node.argumentExpression);
|
||||
@@ -2292,10 +2309,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
&& (<ElementAccessExpression>node).expression.kind === SyntaxKind.SuperKeyword;
|
||||
}
|
||||
|
||||
function isInAsyncMethodWithSuperInES6(node: CallExpression) {
|
||||
function isInAsyncMethodWithSuperInES6(node: Node) {
|
||||
if (languageVersion === ScriptTarget.ES6) {
|
||||
const container = getSuperContainer(node, /*includeFunctions*/ false);
|
||||
if (container && resolver.getNodeCheckFlags(container) & NodeCheckFlags.AsyncMethodWithSuper) {
|
||||
if (container && resolver.getNodeCheckFlags(container) & (NodeCheckFlags.AsyncMethodWithSuper | NodeCheckFlags.AsyncMethodWithSuperBinding)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -2303,10 +2320,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
return false;
|
||||
}
|
||||
|
||||
function emitSuperAccessInAsyncMethod(node: Expression) {
|
||||
function emitSuperAccessInAsyncMethod(superNode: Node, argumentExpression: Expression) {
|
||||
const container = getSuperContainer(superNode, /*includeFunctions*/ false);
|
||||
const isSuperBinding = resolver.getNodeCheckFlags(container) & NodeCheckFlags.AsyncMethodWithSuperBinding;
|
||||
write("_super(");
|
||||
emit(node);
|
||||
write(")");
|
||||
emit(argumentExpression);
|
||||
write(isSuperBinding ? ").value" : ")");
|
||||
}
|
||||
|
||||
function emitCallExpression(node: CallExpression) {
|
||||
@@ -2323,26 +2342,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
superCall = true;
|
||||
}
|
||||
else {
|
||||
if (isSuperPropertyAccess(expression)) {
|
||||
superCall = true;
|
||||
if (isInAsyncMethodWithSuperInES6(node)) {
|
||||
isAsyncMethodWithSuper = true;
|
||||
const name = <StringLiteral>createSynthesizedNode(SyntaxKind.StringLiteral);
|
||||
name.text = expression.name.text;
|
||||
emitSuperAccessInAsyncMethod(name);
|
||||
}
|
||||
}
|
||||
else if (isSuperElementAccess(expression)) {
|
||||
superCall = true;
|
||||
if (isInAsyncMethodWithSuperInES6(node)) {
|
||||
isAsyncMethodWithSuper = true;
|
||||
emitSuperAccessInAsyncMethod(expression.argumentExpression);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isAsyncMethodWithSuper) {
|
||||
emit(expression);
|
||||
}
|
||||
superCall = isSuperPropertyAccess(expression) || isSuperElementAccess(expression);
|
||||
isAsyncMethodWithSuper = superCall && isInAsyncMethodWithSuperInES6(node);
|
||||
emit(expression);
|
||||
}
|
||||
|
||||
if (superCall && (languageVersion < ScriptTarget.ES6 || isAsyncMethodWithSuper)) {
|
||||
@@ -4497,8 +4499,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
increaseIndent();
|
||||
writeLine();
|
||||
|
||||
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.AsyncMethodWithSuper) {
|
||||
write("const _super = name => super[name];");
|
||||
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.AsyncMethodWithSuperBinding) {
|
||||
writeLines(`
|
||||
const _super = (function (geti, seti) {
|
||||
const cache = Object.create(null);
|
||||
return name => cache[name] || (cache[name] = { get value() { return geti(name); }, set value(v) { seti(name, v); } });
|
||||
})(name => super[name], (name, value) => super[name] = value);`);
|
||||
writeLine();
|
||||
}
|
||||
else if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.AsyncMethodWithSuper) {
|
||||
write(`const _super = name => super[name];`);
|
||||
writeLine();
|
||||
}
|
||||
|
||||
|
||||
@@ -2023,13 +2023,14 @@ namespace ts {
|
||||
SuperStatic = 0x00000200, // Static 'super' reference
|
||||
ContextChecked = 0x00000400, // Contextual types have been assigned
|
||||
AsyncMethodWithSuper = 0x00000800,
|
||||
CaptureArguments = 0x00001000, // Lexical 'arguments' used in body (for async functions)
|
||||
AsyncMethodWithSuperBinding = 0x00001000,
|
||||
CaptureArguments = 0x00002000, // Lexical 'arguments' used in body (for async functions)
|
||||
|
||||
// Values for enum members have been computed, and any errors have been reported for them.
|
||||
EnumValuesComputed = 0x00002000,
|
||||
BlockScopedBindingInLoop = 0x00004000,
|
||||
LexicalModuleMergesWithClass = 0x00008000, // Instantiated lexical module declaration is merged with a previous class declaration.
|
||||
LoopWithBlockScopedBindingCapturedInFunction = 0x00010000, // Loop that contains block scoped variable captured in closure
|
||||
EnumValuesComputed = 0x00004000,
|
||||
BlockScopedBindingInLoop = 0x00008000,
|
||||
LexicalModuleMergesWithClass = 0x00010000, // Instantiated lexical module declaration is merged with a previous class declaration.
|
||||
LoopWithBlockScopedBindingCapturedInFunction = 0x00020000, // Loop that contains block scoped variable captured in closure
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
||||
@@ -5,9 +5,48 @@ class A {
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
async y() {
|
||||
// async method with only call/get on 'super' does not require a binding
|
||||
async simple() {
|
||||
// call with property access
|
||||
super.x();
|
||||
|
||||
// call with element access
|
||||
super["x"]();
|
||||
|
||||
// property access (read)
|
||||
const a = super.x;
|
||||
|
||||
// element access (read)
|
||||
const b = super["x"];
|
||||
}
|
||||
|
||||
// async method with assignment/destructuring on 'super' requires a binding
|
||||
async advanced() {
|
||||
const f = () => {};
|
||||
|
||||
// call with property access
|
||||
super.x();
|
||||
|
||||
// call with element access
|
||||
super["x"]();
|
||||
|
||||
// property access (read)
|
||||
const a = super.x;
|
||||
|
||||
// element access (read)
|
||||
const b = super["x"];
|
||||
|
||||
// property access (assign)
|
||||
super.x = f;
|
||||
|
||||
// element access (assign)
|
||||
super["x"] = f;
|
||||
|
||||
// destructuring assign with property access
|
||||
({ f: super.x } = { f });
|
||||
|
||||
// destructuring assign with element access
|
||||
({ f: super["x"] } = { f });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +56,44 @@ class A {
|
||||
}
|
||||
}
|
||||
class B extends A {
|
||||
y() {
|
||||
// async method with only call/get on 'super' does not require a binding
|
||||
simple() {
|
||||
const _super = name => super[name];
|
||||
return __awaiter(this, void 0, Promise, function* () {
|
||||
// call with property access
|
||||
_super("x").call(this);
|
||||
// call with element access
|
||||
_super("x").call(this);
|
||||
// property access (read)
|
||||
const a = _super("x");
|
||||
// element access (read)
|
||||
const b = _super("x");
|
||||
});
|
||||
}
|
||||
// async method with assignment/destructuring on 'super' requires a binding
|
||||
advanced() {
|
||||
const _super = (function (geti, seti) {
|
||||
const cache = Object.create(null);
|
||||
return name => cache[name] || (cache[name] = { get value() { return geti(name); }, set value(v) { seti(name, v); } });
|
||||
})(name => super[name], (name, value) => super[name] = value);
|
||||
return __awaiter(this, void 0, Promise, function* () {
|
||||
const f = () => { };
|
||||
// call with property access
|
||||
_super("x").value.call(this);
|
||||
// call with element access
|
||||
_super("x").value.call(this);
|
||||
// property access (read)
|
||||
const a = _super("x").value;
|
||||
// element access (read)
|
||||
const b = _super("x").value;
|
||||
// property access (assign)
|
||||
_super("x").value = f;
|
||||
// element access (assign)
|
||||
_super("x").value = f;
|
||||
// destructuring assign with property access
|
||||
({ f: _super("x").value } = { f });
|
||||
// destructuring assign with element access
|
||||
({ f: _super("x").value } = { f });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,16 +11,92 @@ class B extends A {
|
||||
>B : Symbol(B, Decl(asyncMethodWithSuper_es6.ts, 3, 1))
|
||||
>A : Symbol(A, Decl(asyncMethodWithSuper_es6.ts, 0, 0))
|
||||
|
||||
async y() {
|
||||
>y : Symbol(y, Decl(asyncMethodWithSuper_es6.ts, 5, 19))
|
||||
// async method with only call/get on 'super' does not require a binding
|
||||
async simple() {
|
||||
>simple : Symbol(simple, Decl(asyncMethodWithSuper_es6.ts, 5, 19))
|
||||
|
||||
// call with property access
|
||||
super.x();
|
||||
>super.x : Symbol(A.x, Decl(asyncMethodWithSuper_es6.ts, 0, 9))
|
||||
>super : Symbol(A, Decl(asyncMethodWithSuper_es6.ts, 0, 0))
|
||||
>x : Symbol(A.x, Decl(asyncMethodWithSuper_es6.ts, 0, 9))
|
||||
|
||||
// call with element access
|
||||
super["x"]();
|
||||
>super : Symbol(A, Decl(asyncMethodWithSuper_es6.ts, 0, 0))
|
||||
>"x" : Symbol(A.x, Decl(asyncMethodWithSuper_es6.ts, 0, 9))
|
||||
|
||||
// property access (read)
|
||||
const a = super.x;
|
||||
>a : Symbol(a, Decl(asyncMethodWithSuper_es6.ts, 15, 13))
|
||||
>super.x : Symbol(A.x, Decl(asyncMethodWithSuper_es6.ts, 0, 9))
|
||||
>super : Symbol(A, Decl(asyncMethodWithSuper_es6.ts, 0, 0))
|
||||
>x : Symbol(A.x, Decl(asyncMethodWithSuper_es6.ts, 0, 9))
|
||||
|
||||
// element access (read)
|
||||
const b = super["x"];
|
||||
>b : Symbol(b, Decl(asyncMethodWithSuper_es6.ts, 18, 13))
|
||||
>super : Symbol(A, Decl(asyncMethodWithSuper_es6.ts, 0, 0))
|
||||
>"x" : Symbol(A.x, Decl(asyncMethodWithSuper_es6.ts, 0, 9))
|
||||
}
|
||||
|
||||
// async method with assignment/destructuring on 'super' requires a binding
|
||||
async advanced() {
|
||||
>advanced : Symbol(advanced, Decl(asyncMethodWithSuper_es6.ts, 19, 5))
|
||||
|
||||
const f = () => {};
|
||||
>f : Symbol(f, Decl(asyncMethodWithSuper_es6.ts, 23, 13))
|
||||
|
||||
// call with property access
|
||||
super.x();
|
||||
>super.x : Symbol(A.x, Decl(asyncMethodWithSuper_es6.ts, 0, 9))
|
||||
>super : Symbol(A, Decl(asyncMethodWithSuper_es6.ts, 0, 0))
|
||||
>x : Symbol(A.x, Decl(asyncMethodWithSuper_es6.ts, 0, 9))
|
||||
|
||||
// call with element access
|
||||
super["x"]();
|
||||
>super : Symbol(A, Decl(asyncMethodWithSuper_es6.ts, 0, 0))
|
||||
>"x" : Symbol(A.x, Decl(asyncMethodWithSuper_es6.ts, 0, 9))
|
||||
|
||||
// property access (read)
|
||||
const a = super.x;
|
||||
>a : Symbol(a, Decl(asyncMethodWithSuper_es6.ts, 32, 13))
|
||||
>super.x : Symbol(A.x, Decl(asyncMethodWithSuper_es6.ts, 0, 9))
|
||||
>super : Symbol(A, Decl(asyncMethodWithSuper_es6.ts, 0, 0))
|
||||
>x : Symbol(A.x, Decl(asyncMethodWithSuper_es6.ts, 0, 9))
|
||||
|
||||
// element access (read)
|
||||
const b = super["x"];
|
||||
>b : Symbol(b, Decl(asyncMethodWithSuper_es6.ts, 35, 13))
|
||||
>super : Symbol(A, Decl(asyncMethodWithSuper_es6.ts, 0, 0))
|
||||
>"x" : Symbol(A.x, Decl(asyncMethodWithSuper_es6.ts, 0, 9))
|
||||
|
||||
// property access (assign)
|
||||
super.x = f;
|
||||
>super.x : Symbol(A.x, Decl(asyncMethodWithSuper_es6.ts, 0, 9))
|
||||
>super : Symbol(A, Decl(asyncMethodWithSuper_es6.ts, 0, 0))
|
||||
>x : Symbol(A.x, Decl(asyncMethodWithSuper_es6.ts, 0, 9))
|
||||
>f : Symbol(f, Decl(asyncMethodWithSuper_es6.ts, 23, 13))
|
||||
|
||||
// element access (assign)
|
||||
super["x"] = f;
|
||||
>super : Symbol(A, Decl(asyncMethodWithSuper_es6.ts, 0, 0))
|
||||
>"x" : Symbol(A.x, Decl(asyncMethodWithSuper_es6.ts, 0, 9))
|
||||
>f : Symbol(f, Decl(asyncMethodWithSuper_es6.ts, 23, 13))
|
||||
|
||||
// destructuring assign with property access
|
||||
({ f: super.x } = { f });
|
||||
>f : Symbol(f, Decl(asyncMethodWithSuper_es6.ts, 44, 10))
|
||||
>super.x : Symbol(A.x, Decl(asyncMethodWithSuper_es6.ts, 0, 9))
|
||||
>super : Symbol(A, Decl(asyncMethodWithSuper_es6.ts, 0, 0))
|
||||
>x : Symbol(A.x, Decl(asyncMethodWithSuper_es6.ts, 0, 9))
|
||||
>f : Symbol(f, Decl(asyncMethodWithSuper_es6.ts, 44, 27))
|
||||
|
||||
// destructuring assign with element access
|
||||
({ f: super["x"] } = { f });
|
||||
>f : Symbol(f, Decl(asyncMethodWithSuper_es6.ts, 47, 10))
|
||||
>super : Symbol(A, Decl(asyncMethodWithSuper_es6.ts, 0, 0))
|
||||
>"x" : Symbol(A.x, Decl(asyncMethodWithSuper_es6.ts, 0, 9))
|
||||
>f : Symbol(f, Decl(asyncMethodWithSuper_es6.ts, 47, 30))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,19 +11,113 @@ class B extends A {
|
||||
>B : B
|
||||
>A : A
|
||||
|
||||
async y() {
|
||||
>y : () => Promise<void>
|
||||
// async method with only call/get on 'super' does not require a binding
|
||||
async simple() {
|
||||
>simple : () => Promise<void>
|
||||
|
||||
// call with property access
|
||||
super.x();
|
||||
>super.x() : void
|
||||
>super.x : () => void
|
||||
>super : A
|
||||
>x : () => void
|
||||
|
||||
// call with element access
|
||||
super["x"]();
|
||||
>super["x"]() : void
|
||||
>super["x"] : () => void
|
||||
>super : A
|
||||
>"x" : string
|
||||
|
||||
// property access (read)
|
||||
const a = super.x;
|
||||
>a : () => void
|
||||
>super.x : () => void
|
||||
>super : A
|
||||
>x : () => void
|
||||
|
||||
// element access (read)
|
||||
const b = super["x"];
|
||||
>b : () => void
|
||||
>super["x"] : () => void
|
||||
>super : A
|
||||
>"x" : string
|
||||
}
|
||||
|
||||
// async method with assignment/destructuring on 'super' requires a binding
|
||||
async advanced() {
|
||||
>advanced : () => Promise<void>
|
||||
|
||||
const f = () => {};
|
||||
>f : () => void
|
||||
>() => {} : () => void
|
||||
|
||||
// call with property access
|
||||
super.x();
|
||||
>super.x() : void
|
||||
>super.x : () => void
|
||||
>super : A
|
||||
>x : () => void
|
||||
|
||||
// call with element access
|
||||
super["x"]();
|
||||
>super["x"]() : void
|
||||
>super["x"] : () => void
|
||||
>super : A
|
||||
>"x" : string
|
||||
|
||||
// property access (read)
|
||||
const a = super.x;
|
||||
>a : () => void
|
||||
>super.x : () => void
|
||||
>super : A
|
||||
>x : () => void
|
||||
|
||||
// element access (read)
|
||||
const b = super["x"];
|
||||
>b : () => void
|
||||
>super["x"] : () => void
|
||||
>super : A
|
||||
>"x" : string
|
||||
|
||||
// property access (assign)
|
||||
super.x = f;
|
||||
>super.x = f : () => void
|
||||
>super.x : () => void
|
||||
>super : A
|
||||
>x : () => void
|
||||
>f : () => void
|
||||
|
||||
// element access (assign)
|
||||
super["x"] = f;
|
||||
>super["x"] = f : () => void
|
||||
>super["x"] : () => void
|
||||
>super : A
|
||||
>"x" : string
|
||||
>f : () => void
|
||||
|
||||
// destructuring assign with property access
|
||||
({ f: super.x } = { f });
|
||||
>({ f: super.x } = { f }) : { f: () => void; }
|
||||
>{ f: super.x } = { f } : { f: () => void; }
|
||||
>{ f: super.x } : { f: () => void; }
|
||||
>f : () => void
|
||||
>super.x : () => void
|
||||
>super : A
|
||||
>x : () => void
|
||||
>{ f } : { f: () => void; }
|
||||
>f : () => void
|
||||
|
||||
// destructuring assign with element access
|
||||
({ f: super["x"] } = { f });
|
||||
>({ f: super["x"] } = { f }) : { f: () => void; }
|
||||
>{ f: super["x"] } = { f } : { f: () => void; }
|
||||
>{ f: super["x"] } : { f: () => void; }
|
||||
>f : () => void
|
||||
>super["x"] : () => void
|
||||
>super : A
|
||||
>"x" : string
|
||||
>{ f } : { f: () => void; }
|
||||
>f : () => void
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,47 @@ class A {
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
async y() {
|
||||
// async method with only call/get on 'super' does not require a binding
|
||||
async simple() {
|
||||
// call with property access
|
||||
super.x();
|
||||
|
||||
// call with element access
|
||||
super["x"]();
|
||||
|
||||
// property access (read)
|
||||
const a = super.x;
|
||||
|
||||
// element access (read)
|
||||
const b = super["x"];
|
||||
}
|
||||
|
||||
// async method with assignment/destructuring on 'super' requires a binding
|
||||
async advanced() {
|
||||
const f = () => {};
|
||||
|
||||
// call with property access
|
||||
super.x();
|
||||
|
||||
// call with element access
|
||||
super["x"]();
|
||||
|
||||
// property access (read)
|
||||
const a = super.x;
|
||||
|
||||
// element access (read)
|
||||
const b = super["x"];
|
||||
|
||||
// property access (assign)
|
||||
super.x = f;
|
||||
|
||||
// element access (assign)
|
||||
super["x"] = f;
|
||||
|
||||
// destructuring assign with property access
|
||||
({ f: super.x } = { f });
|
||||
|
||||
// destructuring assign with element access
|
||||
({ f: super["x"] } = { f });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user