@@ -376,8 +376,8 @@ namespace ts {
376376 const moduleAugmentation = <ModuleDeclaration>moduleName.parent;
377377 if (moduleAugmentation.symbol.valueDeclaration !== moduleAugmentation) {
378378 // this is a combined symbol for multiple augmentations within the same file.
379- // its symbol already has accumulated information for all declarations
380- // so we need to add it just once - do the work only for first declaration
379+ // its symbol already has accumulated information for all declarations
380+ // so we need to add it just once - do the work only for first declaration
381381 Debug.assert(moduleAugmentation.symbol.declarations.length > 1);
382382 return;
383383 }
@@ -386,7 +386,7 @@ namespace ts {
386386 mergeSymbolTable(globals, moduleAugmentation.symbol.exports);
387387 }
388388 else {
389- // find a module that about to be augmented
389+ // find a module that about to be augmented
390390 let mainModule = resolveExternalModuleNameWorker(moduleName, moduleName, Diagnostics.Invalid_module_name_in_augmentation_module_0_cannot_be_found);
391391 if (!mainModule) {
392392 return;
@@ -810,7 +810,7 @@ namespace ts {
810810 }
811811
812812 // No static member is present.
813- // Check if we're in an instance method and look for a relevant instance member.
813+ // Check if we're in an instance method and look for a relevant instance member.
814814 if (location === container && !(location.flags & NodeFlags.Static)) {
815815 const instanceType = (<InterfaceType>getDeclaredTypeOfSymbol(classSymbol)).thisType;
816816 if (getPropertyOfType(instanceType, name)) {
@@ -1161,7 +1161,7 @@ namespace ts {
11611161 return getMergedSymbol(sourceFile.symbol);
11621162 }
11631163 if (moduleNotFoundError) {
1164- // report errors only if it was requested
1164+ // report errors only if it was requested
11651165 error(moduleReferenceLiteral, Diagnostics.File_0_is_not_a_module, sourceFile.fileName);
11661166 }
11671167 return undefined;
@@ -7115,14 +7115,10 @@ namespace ts {
71157115 return false;
71167116 }
71177117
7118- function isSuperPropertyAccess(node: Node) {
7119- return node.kind === SyntaxKind.PropertyAccessExpression
7120- && (<PropertyAccessExpression>node).expression.kind === SyntaxKind.SuperKeyword;
7121- }
7122-
7123- function isSuperElementAccess(node: Node) {
7124- return node.kind === SyntaxKind.ElementAccessExpression
7125- && (<ElementAccessExpression>node).expression.kind === SyntaxKind.SuperKeyword;
7118+ function isSuperPropertyOrElementAccess(node: Node) {
7119+ return (node.kind === SyntaxKind.PropertyAccessExpression
7120+ || node.kind === SyntaxKind.ElementAccessExpression)
7121+ && (<PropertyAccessExpression | ElementAccessExpression>node).expression.kind === SyntaxKind.SuperKeyword;
71267122 }
71277123
71287124 function checkSuperExpression(node: Node): Type {
@@ -7177,8 +7173,63 @@ namespace ts {
71777173 getNodeLinks(node).flags |= nodeCheckFlag;
71787174
71797175 // Due to how we emit async functions, we need to specialize the emit for an async method that contains a `super` reference.
7176+ // This is due to the fact that we emit the body of an async function inside of a generator function. As generator
7177+ // functions cannot reference `super`, we emit a helper inside of the method body, but outside of the generator. This helper
7178+ // uses an arrow function, which is permitted to reference `super`.
7179+ //
7180+ // There are two primary ways we can access `super` from within an async method. The first is getting the value of a property
7181+ // or indexed access on super, either as part of a right-hand-side expression or call expression. The second is when setting the value
7182+ // of a property or indexed access, either as part of an assignment expression or destructuring assignment.
7183+ //
7184+ // The simplest case is reading a value, in which case we will emit something like the following:
7185+ //
7186+ // // ts
7187+ // ...
7188+ // async asyncMethod() {
7189+ // let x = await super.asyncMethod();
7190+ // return x;
7191+ // }
7192+ // ...
7193+ //
7194+ // // js
7195+ // ...
7196+ // asyncMethod() {
7197+ // const _super = name => super[name];
7198+ // return __awaiter(this, arguments, Promise, function *() {
7199+ // let x = yield _super("asyncMethod").call(this);
7200+ // return x;
7201+ // });
7202+ // }
7203+ // ...
7204+ //
7205+ // The more complex case is when we wish to assign a value, especially as part of a destructuring assignment. As both cases
7206+ // are legal in ES6, but also likely less frequent, we emit the same more complex helper for both scenarios:
7207+ //
7208+ // // ts
7209+ // ...
7210+ // async asyncMethod(ar: Promise<any[]>) {
7211+ // [super.a, super.b] = await ar;
7212+ // }
7213+ // ...
7214+ //
7215+ // // js
7216+ // ...
7217+ // asyncMethod(ar) {
7218+ // const _super = (function (geti, seti) {
7219+ // const cache = Object.create(null);
7220+ // return name => cache[name] || (cache[name] = { get value() { return geti(name); }, set value(v) { seti(name, v); } });
7221+ // })(name => super[name], (name, value) => super[name] = value);
7222+ // return __awaiter(this, arguments, Promise, function *() {
7223+ // [_super("a").value, _super("b").value] = yield ar;
7224+ // });
7225+ // }
7226+ // ...
7227+ //
7228+ // This helper creates an object with a "value" property that wraps the `super` property or indexed access for both get and set.
7229+ // This is required for destructuring assignments, as a call expression cannot be used as the target of a destructuring assignment
7230+ // while a property access can.
71807231 if (container.kind === SyntaxKind.MethodDeclaration && container.flags & NodeFlags.Async) {
7181- if ((isSuperPropertyAccess( node.parent) || isSuperElementAccess(node.parent) ) && isAssignmentTarget(node.parent)) {
7232+ if (isSuperPropertyOrElementAccess( node.parent) && isAssignmentTarget(node.parent)) {
71827233 getNodeLinks(container).flags |= NodeCheckFlags.AsyncMethodWithSuperBinding;
71837234 }
71847235 else {
@@ -14224,10 +14275,10 @@ namespace ts {
1422414275 if (isAmbientExternalModule) {
1422514276 if (isExternalModuleAugmentation(node)) {
1422614277 // body of the augmentation should be checked for consistency only if augmentation was applied to its target (either global scope or module)
14227- // otherwise we'll be swamped in cascading errors.
14278+ // otherwise we'll be swamped in cascading errors.
1422814279 // We can detect if augmentation was applied using following rules:
1422914280 // - augmentation for a global scope is always applied
14230- // - augmentation for some external module is applied if symbol for augmentation is merged (it was combined with target module).
14281+ // - augmentation for some external module is applied if symbol for augmentation is merged (it was combined with target module).
1423114282 const checkBody = isGlobalAugmentation || (getSymbolOfNode(node).flags & SymbolFlags.Merged);
1423214283 if (checkBody) {
1423314284 // body of ambient external module is always a module block
0 commit comments