Skip to content

Commit 3e0c84e

Browse files
committed
PR feedback
1 parent 6084dec commit 3e0c84e

File tree

1 file changed

+67
-16
lines changed

1 file changed

+67
-16
lines changed

src/compiler/checker.ts

Lines changed: 67 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)