mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge pull request #6077 from Microsoft/superInObjectLiterals
allow usage of 'super' in object literal expressions
This commit is contained in:
+54
-34
@@ -7209,17 +7209,14 @@ namespace ts {
|
||||
|
||||
function checkSuperExpression(node: Node): Type {
|
||||
const isCallExpression = node.parent.kind === SyntaxKind.CallExpression && (<CallExpression>node.parent).expression === node;
|
||||
const classDeclaration = getContainingClass(node);
|
||||
const classType = classDeclaration && <InterfaceType>getDeclaredTypeOfSymbol(getSymbolOfNode(classDeclaration));
|
||||
const baseClassType = classType && getBaseTypes(classType)[0];
|
||||
|
||||
let container = getSuperContainer(node, /*includeFunctions*/ true);
|
||||
let container = getSuperContainer(node, /*stopOnFunctions*/ true);
|
||||
let needToCaptureLexicalThis = false;
|
||||
|
||||
if (!isCallExpression) {
|
||||
// adjust the container reference in case if super is used inside arrow functions with arbitrary deep nesting
|
||||
while (container && container.kind === SyntaxKind.ArrowFunction) {
|
||||
container = getSuperContainer(container, /*includeFunctions*/ true);
|
||||
container = getSuperContainer(container, /*stopOnFunctions*/ true);
|
||||
needToCaptureLexicalThis = languageVersion < ScriptTarget.ES6;
|
||||
}
|
||||
}
|
||||
@@ -7227,43 +7224,66 @@ namespace ts {
|
||||
const canUseSuperExpression = isLegalUsageOfSuperExpression(container);
|
||||
let nodeCheckFlag: NodeCheckFlags = 0;
|
||||
|
||||
// always set NodeCheckFlags for 'super' expression node
|
||||
if (canUseSuperExpression) {
|
||||
if ((container.flags & NodeFlags.Static) || isCallExpression) {
|
||||
nodeCheckFlag = NodeCheckFlags.SuperStatic;
|
||||
}
|
||||
else {
|
||||
nodeCheckFlag = NodeCheckFlags.SuperInstance;
|
||||
}
|
||||
|
||||
getNodeLinks(node).flags |= nodeCheckFlag;
|
||||
|
||||
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 -
|
||||
// in this case they should also use correct lexical this
|
||||
captureLexicalThis(node.parent, container);
|
||||
}
|
||||
}
|
||||
|
||||
if (!baseClassType) {
|
||||
if (!classDeclaration || !getClassExtendsHeritageClauseElement(classDeclaration)) {
|
||||
error(node, Diagnostics.super_can_only_be_referenced_in_a_derived_class);
|
||||
}
|
||||
return unknownType;
|
||||
}
|
||||
|
||||
if (!canUseSuperExpression) {
|
||||
if (container && container.kind === SyntaxKind.ComputedPropertyName) {
|
||||
// issue more specific error if super is used in computed property name
|
||||
// class A { foo() { return "1" }}
|
||||
// class B {
|
||||
// [super.foo()]() {}
|
||||
// }
|
||||
let current = node;
|
||||
while (current && current !== container && current.kind !== SyntaxKind.ComputedPropertyName) {
|
||||
current = current.parent;
|
||||
}
|
||||
if (current && current.kind === SyntaxKind.ComputedPropertyName) {
|
||||
error(node, Diagnostics.super_cannot_be_referenced_in_a_computed_property_name);
|
||||
}
|
||||
else if (isCallExpression) {
|
||||
error(node, Diagnostics.Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors);
|
||||
}
|
||||
else if (!container || !container.parent || !(isClassLike(container.parent) || container.parent.kind === SyntaxKind.ObjectLiteralExpression)) {
|
||||
error(node, Diagnostics.super_can_only_be_referenced_in_members_of_derived_classes_or_object_literal_expressions);
|
||||
}
|
||||
else {
|
||||
error(node, Diagnostics.super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class);
|
||||
}
|
||||
return unknownType;
|
||||
}
|
||||
|
||||
if ((container.flags & NodeFlags.Static) || isCallExpression) {
|
||||
nodeCheckFlag = NodeCheckFlags.SuperStatic;
|
||||
}
|
||||
else {
|
||||
nodeCheckFlag = NodeCheckFlags.SuperInstance;
|
||||
}
|
||||
|
||||
getNodeLinks(node).flags |= nodeCheckFlag;
|
||||
|
||||
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 -
|
||||
// in this case they should also use correct lexical this
|
||||
captureLexicalThis(node.parent, container);
|
||||
}
|
||||
|
||||
if (container.parent.kind === SyntaxKind.ObjectLiteralExpression) {
|
||||
if (languageVersion < ScriptTarget.ES6) {
|
||||
error(node, Diagnostics.super_is_only_allowed_in_members_of_object_literal_expressions_when_option_target_is_ES2015_or_higher);
|
||||
return unknownType;
|
||||
}
|
||||
else {
|
||||
// for object literal assume that type of 'super' is 'any'
|
||||
return anyType;
|
||||
}
|
||||
}
|
||||
|
||||
// at this point the only legal case for parent is ClassLikeDeclaration
|
||||
const classLikeDeclaration = <ClassLikeDeclaration>container.parent;
|
||||
const classType = <InterfaceType>getDeclaredTypeOfSymbol(getSymbolOfNode(classLikeDeclaration));
|
||||
const baseClassType = classType && getBaseTypes(classType)[0];
|
||||
if (!baseClassType) {
|
||||
if (!getClassExtendsHeritageClauseElement(classLikeDeclaration)) {
|
||||
error(node, Diagnostics.super_can_only_be_referenced_in_a_derived_class);
|
||||
}
|
||||
return unknownType;
|
||||
}
|
||||
|
||||
@@ -7293,8 +7313,8 @@ namespace ts {
|
||||
// - In a constructor, instance member function, instance member accessor, or instance member variable initializer where this references a derived class instance
|
||||
// - In a static member function or static member accessor
|
||||
|
||||
// topmost container must be something that is directly nested in the class declaration
|
||||
if (container && isClassLike(container.parent)) {
|
||||
// topmost container must be something that is directly nested in the class declaration\object literal expression
|
||||
if (isClassLike(container.parent) || container.parent.kind === SyntaxKind.ObjectLiteralExpression) {
|
||||
if (container.flags & NodeFlags.Static) {
|
||||
return container.kind === SyntaxKind.MethodDeclaration ||
|
||||
container.kind === SyntaxKind.MethodSignature ||
|
||||
|
||||
@@ -1759,6 +1759,14 @@
|
||||
"category": "Error",
|
||||
"code": 2658
|
||||
},
|
||||
"'super' is only allowed in members of object literal expressions when option 'target' is 'ES2015' or higher.": {
|
||||
"category": "Error",
|
||||
"code": 2659
|
||||
},
|
||||
"'super' can only be referenced in members of derived classes or object literal expressions.": {
|
||||
"category": "Error",
|
||||
"code": 2660
|
||||
},
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
"code": 4000
|
||||
|
||||
+26
-28
@@ -775,26 +775,38 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
export function getSuperContainer(node: Node, includeFunctions: boolean): Node {
|
||||
/**
|
||||
* Given an super call\property node returns a closest node where either
|
||||
* - super call\property is legal in the node and not legal in the parent node the node.
|
||||
* i.e. super call is legal in constructor but not legal in the class body.
|
||||
* - node is arrow function (so caller might need to call getSuperContainer in case if he needs to climb higher)
|
||||
* - super call\property is definitely illegal in the node (but might be legal in some subnode)
|
||||
* i.e. super property access is illegal in function declaration but can be legal in the statement list
|
||||
*/
|
||||
export function getSuperContainer(node: Node, stopOnFunctions: boolean): Node {
|
||||
while (true) {
|
||||
node = node.parent;
|
||||
if (!node) return node;
|
||||
if (!node) {
|
||||
return node;
|
||||
}
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ComputedPropertyName:
|
||||
// If the grandparent node is an object literal (as opposed to a class),
|
||||
// then the computed property is not a 'super' container.
|
||||
// A computed property name in a class needs to be a super container
|
||||
// so that we can error on it.
|
||||
if (isClassLike(node.parent.parent)) {
|
||||
return node;
|
||||
}
|
||||
// If this is a computed property, then the parent should not
|
||||
// make it a super container. The parent might be a property
|
||||
// in an object literal, like a method or accessor. But in order for
|
||||
// such a parent to be a super container, the reference must be in
|
||||
// the *body* of the container.
|
||||
node = node.parent;
|
||||
break;
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
if (!stopOnFunctions) {
|
||||
continue;
|
||||
}
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
case SyntaxKind.PropertySignature:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
return node;
|
||||
case SyntaxKind.Decorator:
|
||||
// Decorators are always applied outside of the body of a class or method.
|
||||
if (node.parent.kind === SyntaxKind.Parameter && isClassElement(node.parent.parent)) {
|
||||
@@ -808,20 +820,6 @@ namespace ts {
|
||||
node = node.parent;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
if (!includeFunctions) {
|
||||
continue;
|
||||
}
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
case SyntaxKind.PropertySignature:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user