Merge pull request #5870 from Microsoft/alternateFixSuperInAsyncMethod

Fix super in async method
This commit is contained in:
Ron Buckton 2016-01-26 13:04:06 -08:00
commit 2b1fd8c419
17 changed files with 538 additions and 42 deletions

View file

@ -376,8 +376,8 @@ namespace ts {
const moduleAugmentation = <ModuleDeclaration>moduleName.parent;
if (moduleAugmentation.symbol.valueDeclaration !== moduleAugmentation) {
// this is a combined symbol for multiple augmentations within the same file.
// its symbol already has accumulated information for all declarations
// so we need to add it just once - do the work only for first declaration
// its symbol already has accumulated information for all declarations
// so we need to add it just once - do the work only for first declaration
Debug.assert(moduleAugmentation.symbol.declarations.length > 1);
return;
}
@ -386,7 +386,7 @@ namespace ts {
mergeSymbolTable(globals, moduleAugmentation.symbol.exports);
}
else {
// find a module that about to be augmented
// find a module that about to be augmented
let mainModule = resolveExternalModuleNameWorker(moduleName, moduleName, Diagnostics.Invalid_module_name_in_augmentation_module_0_cannot_be_found);
if (!mainModule) {
return;
@ -812,7 +812,7 @@ namespace ts {
}
// No static member is present.
// Check if we're in an instance method and look for a relevant instance member.
// Check if we're in an instance method and look for a relevant instance member.
if (location === container && !(location.flags & NodeFlags.Static)) {
const instanceType = (<InterfaceType>getDeclaredTypeOfSymbol(classSymbol)).thisType;
if (getPropertyOfType(instanceType, name)) {
@ -1163,7 +1163,7 @@ namespace ts {
return getMergedSymbol(sourceFile.symbol);
}
if (moduleNotFoundError) {
// report errors only if it was requested
// report errors only if it was requested
error(moduleReferenceLiteral, Diagnostics.File_0_is_not_a_module, sourceFile.fileName);
}
return undefined;
@ -7147,7 +7147,6 @@ namespace ts {
if (node.parserContextFlags & ParserContextFlags.Await) {
getNodeLinks(container).flags |= NodeCheckFlags.CaptureArguments;
getNodeLinks(node).flags |= NodeCheckFlags.LexicalArguments;
}
}
@ -7379,6 +7378,71 @@ namespace ts {
getNodeLinks(node).flags |= nodeCheckFlag;
// Due to how we emit async functions, we need to specialize the emit for an async method that contains a `super` reference.
// This is due to the fact that we emit the body of an async function inside of a generator function. As generator
// functions cannot reference `super`, we emit a helper inside of the method body, but outside of the generator. This helper
// uses an arrow function, which is permitted to reference `super`.
//
// There are two primary ways we can access `super` from within an async method. The first is getting the value of a property
// or indexed access on super, either as part of a right-hand-side expression or call expression. The second is when setting the value
// of a property or indexed access, either as part of an assignment expression or destructuring assignment.
//
// The simplest case is reading a value, in which case we will emit something like the following:
//
// // ts
// ...
// async asyncMethod() {
// let x = await super.asyncMethod();
// return x;
// }
// ...
//
// // js
// ...
// asyncMethod() {
// const _super = name => super[name];
// return __awaiter(this, arguments, Promise, function *() {
// let x = yield _super("asyncMethod").call(this);
// return x;
// });
// }
// ...
//
// The more complex case is when we wish to assign a value, especially as part of a destructuring assignment. As both cases
// are legal in ES6, but also likely less frequent, we emit the same more complex helper for both scenarios:
//
// // ts
// ...
// async asyncMethod(ar: Promise<any[]>) {
// [super.a, super.b] = await ar;
// }
// ...
//
// // js
// ...
// asyncMethod(ar) {
// 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, arguments, Promise, function *() {
// [_super("a").value, _super("b").value] = yield ar;
// });
// }
// ...
//
// This helper creates an object with a "value" property that wraps the `super` property or indexed access for both get and set.
// This is required for destructuring assignments, as a call expression cannot be used as the target of a destructuring assignment
// while a property access can.
if (container.kind === SyntaxKind.MethodDeclaration && container.flags & NodeFlags.Async) {
if (isSuperPropertyOrElementAccess(node.parent) && isAssignmentTarget(node.parent)) {
getNodeLinks(container).flags |= NodeCheckFlags.AsyncMethodWithSuperBinding;
}
else {
getNodeLinks(container).flags |= NodeCheckFlags.AsyncMethodWithSuper;
}
}
if (needToCaptureLexicalThis) {
// call expressions are allowed only in constructors so they should always capture correct 'this'
// super property access expressions can also appear in arrow functions -
@ -14426,10 +14490,10 @@ namespace ts {
if (isAmbientExternalModule) {
if (isExternalModuleAugmentation(node)) {
// body of the augmentation should be checked for consistency only if augmentation was applied to its target (either global scope or module)
// otherwise we'll be swamped in cascading errors.
// otherwise we'll be swamped in cascading errors.
// We can detect if augmentation was applied using following rules:
// - augmentation for a global scope is always applied
// - augmentation for some external module is applied if symbol for augmentation is merged (it was combined with target module).
// - augmentation for some external module is applied if symbol for augmentation is merged (it was combined with target module).
const checkBody = isGlobalAugmentation || (getSymbolOfNode(node).flags & SymbolFlags.Merged);
if (checkBody) {
// body of ambient external module is always a module block

View file

@ -324,7 +324,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.call(thisArg, _arguments)).next());
step((generator = generator.apply(thisArg, _arguments)).next());
});
};`;
@ -1488,11 +1488,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
}
function emitExpressionIdentifier(node: Identifier) {
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.LexicalArguments) {
write("_arguments");
return;
}
const container = resolver.getReferencedExportContainer(node);
if (container) {
if (container.kind === SyntaxKind.SourceFile) {
@ -2122,6 +2117,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
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 +2211,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
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);
@ -2282,23 +2294,47 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
write(")");
}
function isInAsyncMethodWithSuperInES6(node: Node) {
if (languageVersion === ScriptTarget.ES6) {
const container = getSuperContainer(node, /*includeFunctions*/ false);
if (container && resolver.getNodeCheckFlags(container) & (NodeCheckFlags.AsyncMethodWithSuper | NodeCheckFlags.AsyncMethodWithSuperBinding)) {
return true;
}
}
return false;
}
function emitSuperAccessInAsyncMethod(superNode: Node, argumentExpression: Expression) {
const container = getSuperContainer(superNode, /*includeFunctions*/ false);
const isSuperBinding = resolver.getNodeCheckFlags(container) & NodeCheckFlags.AsyncMethodWithSuperBinding;
write("_super(");
emit(argumentExpression);
write(isSuperBinding ? ").value" : ")");
}
function emitCallExpression(node: CallExpression) {
if (languageVersion < ScriptTarget.ES6 && hasSpreadElement(node.arguments)) {
emitCallWithSpread(node);
return;
}
const expression = node.expression;
let superCall = false;
if (node.expression.kind === SyntaxKind.SuperKeyword) {
emitSuper(node.expression);
let isAsyncMethodWithSuper = false;
if (expression.kind === SyntaxKind.SuperKeyword) {
emitSuper(expression);
superCall = true;
}
else {
emit(node.expression);
superCall = node.expression.kind === SyntaxKind.PropertyAccessExpression && (<PropertyAccessExpression>node.expression).expression.kind === SyntaxKind.SuperKeyword;
superCall = isSuperPropertyOrElementAccess(expression);
isAsyncMethodWithSuper = superCall && isInAsyncMethodWithSuperInES6(node);
emit(expression);
}
if (superCall && languageVersion < ScriptTarget.ES6) {
if (superCall && (languageVersion < ScriptTarget.ES6 || isAsyncMethodWithSuper)) {
write(".call(");
emitThis(node.expression);
emitThis(expression);
if (node.arguments.length) {
write(", ");
emitCommaList(node.arguments);
@ -4470,6 +4506,20 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
write(" {");
increaseIndent();
writeLine();
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();
}
write("return");
}
@ -4489,12 +4539,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
}
// Emit the call to __awaiter.
if (hasLexicalArguments) {
write(", function* (_arguments)");
}
else {
write(", function* ()");
}
write(", function* ()");
// Emit the signature and body for the inner generator function.
emitFunctionBody(node);

View file

@ -2058,14 +2058,15 @@ namespace ts {
SuperInstance = 0x00000100, // Instance 'super' reference
SuperStatic = 0x00000200, // Static 'super' reference
ContextChecked = 0x00000400, // Contextual types have been assigned
LexicalArguments = 0x00000800,
CaptureArguments = 0x00001000, // Lexical 'arguments' used in body (for async functions)
AsyncMethodWithSuper = 0x00000800, // An async method that reads a value from a member of 'super'.
AsyncMethodWithSuperBinding = 0x00001000, // An async method that assigns a value to a member of 'super'.
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 */

View file

@ -850,6 +850,16 @@ namespace ts {
}
}
/**
* Determines whether a node is a property or element access expression for super.
*/
export function isSuperPropertyOrElementAccess(node: Node) {
return (node.kind === SyntaxKind.PropertyAccessExpression
|| node.kind === SyntaxKind.ElementAccessExpression)
&& (<PropertyAccessExpression | ElementAccessExpression>node).expression.kind === SyntaxKind.SuperKeyword;
}
export function getEntityNameFromTypeNode(node: TypeNode): EntityName | Expression {
if (node) {
switch (node.kind) {

View file

@ -11,6 +11,6 @@ class C {
class C {
method() {
function other() { }
var fn = () => __awaiter(this, arguments, Promise, function* (_arguments) { return yield other.apply(this, _arguments); });
var fn = () => __awaiter(this, arguments, Promise, function* () { return yield other.apply(this, arguments); });
}
}

View file

@ -45,7 +45,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.call(thisArg, _arguments)).next());
step((generator = generator.apply(thisArg, _arguments)).next());
});
};
function f0() {

View file

@ -45,7 +45,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.call(thisArg, _arguments)).next());
step((generator = generator.apply(thisArg, _arguments)).next());
});
};
function f0() {

View file

@ -21,7 +21,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.call(thisArg, _arguments)).next());
step((generator = generator.apply(thisArg, _arguments)).next());
});
};
import { a } from './a';
@ -36,7 +36,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.call(thisArg, _arguments)).next());
step((generator = generator.apply(thisArg, _arguments)).next());
});
};
import { b } from './b';

View file

@ -21,7 +21,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.call(thisArg, _arguments)).next());
step((generator = generator.apply(thisArg, _arguments)).next());
});
};
const task_1 = require("./task");

View file

@ -0,0 +1,99 @@
//// [asyncMethodWithSuper_es6.ts]
class A {
x() {
}
}
class B extends A {
// 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 });
}
}
//// [asyncMethodWithSuper_es6.js]
class A {
x() {
}
}
class B extends A {
// 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 });
});
}
}

View file

@ -0,0 +1,102 @@
=== tests/cases/conformance/async/es6/asyncMethodWithSuper_es6.ts ===
class A {
>A : Symbol(A, Decl(asyncMethodWithSuper_es6.ts, 0, 0))
x() {
>x : Symbol(x, Decl(asyncMethodWithSuper_es6.ts, 0, 9))
}
}
class B extends A {
>B : Symbol(B, Decl(asyncMethodWithSuper_es6.ts, 3, 1))
>A : Symbol(A, Decl(asyncMethodWithSuper_es6.ts, 0, 0))
// 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))
}
}

View file

@ -0,0 +1,123 @@
=== tests/cases/conformance/async/es6/asyncMethodWithSuper_es6.ts ===
class A {
>A : A
x() {
>x : () => void
}
}
class B extends A {
>B : B
>A : A
// 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
}
}

View file

@ -11,7 +11,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.call(thisArg, _arguments)).next());
step((generator = generator.apply(thisArg, _arguments)).next());
});
};
function f() {

View file

@ -36,7 +36,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.call(thisArg, _arguments)).next());
step((generator = generator.apply(thisArg, _arguments)).next());
});
};
// async function without return type annotation - error

View file

@ -34,7 +34,7 @@ var Bar = (function (_super) {
_super.apply(this, arguments);
}
Bar.prototype[symbol] = function () {
return _super.prototype[symbol]();
return _super.prototype[symbol].call(this);
};
return Bar;
}(Foo));

View file

@ -34,7 +34,7 @@ var Bar = (function (_super) {
_super.apply(this, arguments);
}
Bar[symbol] = function () {
return _super[symbol]();
return _super[symbol].call(this);
};
return Bar;
}(Foo));

View file

@ -0,0 +1,52 @@
// @target: ES6
// @noEmitHelpers: true
class A {
x() {
}
}
class B extends A {
// 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 });
}
}