8000 Merge pull request #6077 from Microsoft/superInObjectLiterals · johnangularjs/TypeScript@bb1e5ab · GitHub
[go: up one dir, main page]

Skip to content

Commit bb1e5ab

Browse files
committed
Merge pull request microsoft#6077 from Microsoft/superInObjectLiterals
allow usage of 'super' in object literal expressions
2 parents 09d2233 + ae7d687 commit bb1e5ab

29 files changed

+966
-127
lines changed

src/compiler/checker.ts

Lines changed: 52 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7209,61 +7209,81 @@ namespace ts {
72097209

72107210
function checkSuperExpression(node: Node): Type {
72117211
const isCallExpression = node.parent.kind === SyntaxKind.CallExpression && (<CallExpression>node.parent).expression === node;
7212-
const classDeclaration = getContainingClass(node);
7213-
const classType = classDeclaration && <InterfaceType>getDeclaredTypeOfSymbol(getSymbolOfNode(classDeclaration));
7214-
const baseClassType = classType && getBaseTypes(classType)[0];
72157212

7216-
let container = getSuperContainer(node, /*includeFunctions*/ true);
7213+
let container = getSuperContainer(node, /*stopOnFunctions*/ true);
72177214
let needToCaptureLexicalThis = false;
72187215

72197216
if (!isCallExpression) {
72207217
// adjust the container reference in case if super is used inside arrow functions with arbitrary deep nesting
72217218
while (container && container.kind === SyntaxKind.ArrowFunction) {
7222-
container = getSuperContainer(container, /*includeFunctions*/ true);
7219+
container = getSuperContainer(container, /*stopOnFunctions*/ true);
72237220
needToCaptureLexicalThis = languageVersion < ScriptTarget.ES6;
72247221
}
72257222
}
72267223

72277224
const canUseSuperExpression = isLegalUsageOfSuperExpression(container);
72287225
let nodeCheckFlag: NodeCheckFlags = 0;
72297226

7230-
// always set NodeCheckFlags for 'super' expression node
7231-
if (canUseSuperExpression) {
7232-
if ((container.flags & NodeFlags.Static) || isCallExpression) {
7233-
nodeCheckFlag = NodeCheckFlags.SuperStatic;
7227+
if (!canUseSuperExpression) {
7228+
// issue more specific error if super is used in computed property name
7229+
// class A { foo() { return "1" }}
7230+
// class B {
7231+
// [super.foo()]() {}
7232+
// }
7233+
let current = node;
7234+
while (current && current !== container && current.kind !== SyntaxKind.ComputedPropertyName) {
7235+
current = current.parent;
7236+
}
7237+
if (current && current.kind === SyntaxKind.ComputedPropertyName) {
7238+
error(node, Diagnostics.super_cannot_be_referenced_in_a_computed_property_name);
7239+
}
7240+
else if (isCallExpression) {
7241+
error(node, Diagnostics.Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors);
7242+
}
7243+
else if (!container || !container.parent || !(isClassLike(container.parent) || container.parent.kind === SyntaxKind.ObjectLiteralExpression)) {
7244+
error(node, Diagnostics.super_can_only_be_referenced_in_members_of_derived_classes_or_object_literal_expressions);
72347245
}
72357246
else {
7236-
nodeCheckFlag = NodeCheckFlags.SuperInstance;
7247+
error(node, Diagnostics.super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class);
72377248
}
7249+
return unknownType;
7250+
}
72387251

7239-
getNodeLinks(node).flags |= nodeCheckFlag;
7240-
7241-
if (needToCaptureLexicalThis) {
7242-
// call expressions are allowed only in constructors so they should a F438 lways capture correct 'this'
7243-
// super property access expressions can also appear in arrow functions -
7244-
// in this case they should also use correct lexical this
7245-
captureLexicalThis(node.parent, container);
7246-
}
7252+
if ((container.flags & NodeFlags.Static) || isCallExpression) {
7253+
nodeCheckFlag = NodeCheckFlags.SuperStatic;
7254+
}
7255+
else {
7256+
nodeCheckFlag = NodeCheckFlags.SuperInstance;
72477257
}
72487258

7249-
if (!baseClassType) {
7250-
if (!classDeclaration || !getClassExtendsHeritageClauseElement(classDeclaration)) {
7251-
error(node, Diagnostics.super_can_only_be_referenced_in_a_derived_class);
7252-
}
7253-
return unknownType;
7259+
getNodeLinks(node).flags |= nodeCheckFlag;
7260+
7261+
if (needToCaptureLexicalThis) {
7262+
// call expressions are allowed only in constructors so they should always capture correct 'this'
7263+
// super property access expressions can also appear in arrow functions -
7264+
// in this case they should also use correct lexical this
7265+
captureLexicalThis(node.parent, container);
72547266
}
72557267

7256-
if (!canUseSuperExpression) {
7257-
if (container && container.kind === SyntaxKind.ComputedPropertyName) {
7258-
error(node, Diagnostics.super_cannot_be_referenced_in_a_computed_property_name);
7259-
}
7260-
else if (isCallExpression) {
7261-
error(node, Diagnostics.Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors);
7268+
if (container.parent.kind === SyntaxKind.ObjectLiteralExpression) {
7269+
if (languageVersion < ScriptTarget.ES6) {
7270+
error(node, Diagnostics.super_is_only_allowed_in_members_of_object_literal_expressions_when_option_target_is_ES2015_or_higher);
7271+
return unknownType;
72627272
}
72637273
else {
7264-
error(node, Diagnostics.super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class);
7274+
// for object literal assume that type of 'super' is 'any'
7275+
return anyType;
72657276
}
7277+
}
72667278

7279+
// at this point the only legal case for parent is ClassLikeDeclaration
7280+
const classLikeDeclaration = <ClassLikeDeclaration>container.parent;
7281+
const classType = <InterfaceType>getDeclaredTypeOfSymbol(getSymbolOfNode(classLikeDeclaration));
7282+
const baseClassType = classType && getBaseTypes(classType)[0];
7283+
if (!baseClassType) {
7284+
if (!getClassExtendsHeritageClauseElement(classLikeDeclaration)) {
7285+
error(node, Diagnostics.super_can_only_be_referenced_in_a_derived_class);
7286+
}
72677287
return unknownType;
72687288
}
72697289

@@ -7293,8 +7313,8 @@ namespace ts {
72937313
// - In a constructor, instance member function, instance member accessor, or instance member variable initializer where this references a derived class instance
72947314
// - In a static member function or static member accessor
72957315

7296-
// topmost container must be something that is directly nested in the class declaration
7297-
if (container && isClassLike(container.parent)) {
7316+
// topmost container must be something that is directly nested in the class declaration\object literal expression
7317+
if (isClassLike(container.parent) || container.parent.kind === SyntaxKind.ObjectLiteralExpression) {
72987318
if (container.flags & NodeFlags.Static) {
72997319
return container.kind === SyntaxKind.MethodDeclaration ||
73007320
container.kind === SyntaxKind.MethodSignature ||

src/compiler/diagnosticMessages.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1759,6 +1759,14 @@
17591759
"category": "Error",
17601760
"code": 2658
17611761
},
1762+
"'super' is only allowed in members of object literal expressions when option 'target' is 'ES2015' or higher.": {
1763+
"category": "Error",
1764+
"code": 2659
1765+
},
1766+
"'super' can only be referenced in members of derived classes or object literal expressions.": {
1767+
"category": "Error",
1768+
"code": 2660
1769+
},
17621770
"Import declaration '{0}' is using private name '{1}'.": {
17631771
"category": "Error",
17641772
"code": 4000

src/compiler/utilities.ts

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -775,43 +775,28 @@ namespace ts {
775775
}
776776
}
777777

778-
export function getSuperContainer(node: Node, includeFunctions: boolean): Node {
778+
/**
779+
* Given an super call\property node returns a closest node where either
780+
* - super call\property is legal in the node and not legal in the parent node the node.
781+
* i.e. super call is legal in constructor but not legal in the class body.
782+
* - node is arrow function (so caller might need to call getSuperContainer in case if he needs to climb higher)
783+
* - super call\property is definitely illegal in the node (but might be legal in some subnode)
784+
* i.e. super property access is illegal in function declaration but can be legal in the statement list
785+
*/
786+
export function getSuperContainer(node: Node, stopOnFunctions: boolean): Node {
779787
while (true) {
780788
node = node.parent;
781-
if (!node) return node;
789+
if (!node) {
790+
return node;
791+
}
782792
switch (node.kind) {
783793
case SyntaxKind.ComputedPropertyName:
784-
// If the grandparent node is an object literal (as opposed to a class),
785-
// then the computed property is not a 'super' container.
786-
// A computed property name in a class needs to be a super container
787-
// so that we can error on it.
788-
if (isClassLike(node.parent.parent)) {
789-
return node;
790-
}
791-
// If this is a computed property, then the parent should not
792-
// make it a super container. The parent might be a property
793-
// in an object literal, like a method or accessor. But in order for
794-
// such a parent to be a super container, the reference must be in
795-
// the *body* of the container.
796794
node = node.parent;
797795
break;
798-
case SyntaxKind.Decorator:
799-
// Decorators are always applied outside of the body of a class or method.
800-
if (node.parent.kind === SyntaxKind.Parameter && isClassElement(node.parent.parent)) {
801-
// If the decorator's parent is a Parameter, we resolve the this container from
802-
// the grandparent class declaration.
803-
node = node.parent.parent;
804-
}
805-
else if (isClassElement(node.parent)) {
806-
// If the decorator's parent is a class element, we resolve the 'this' container
807-
// from the parent class declaration.
808-
node = node.parent;
809-
}
810-
break;
811796
case SyntaxKind.FunctionDeclaration:
812797
case SyntaxKind.FunctionExpression:
813798
case SyntaxKind.ArrowFunction:
814-
if (!includeFunctions) {
799+
if (!stopOnFunctions) {
815800
continue;
816801
}
817802
case SyntaxKind.PropertyDeclaration:
@@ -822,6 +807,19 @@ namespace ts {
822807
case SyntaxKind.GetAccessor:
823808
case SyntaxKind.SetAccessor:
824809
return node;
810+
case SyntaxKind.Decorator:
811+
// Decorators are always applied outside of the body of a class or method.
812+
if (node.parent.kind === SyntaxKind.Parameter && isClassElement(node.parent.parent)) {
813+
// If the decorator's parent is a Parameter, we resolve the this container from
814+
// the grandparent class declaration.
815+
node = node.parent.parent;
816+
}
817+
else if (isClassElement(node.parent)) {
818+
// If the decorator's parent is a class element, we resolve the 'this' container
819+
// from the parent class declaration.
820+
node = node.parent;
821+
}
822+
break;
825823
}
826824
}
827825
}

src/services/services.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5779,7 +5779,7 @@ namespace ts {
57795779
}
57805780

57815781
function getReferencesForSuperKeyword(superKeyword: Node): ReferencedSymbol[] {
5782-
let searchSpaceNode = getSuperContainer(superKeyword, /*includeFunctions*/ false);
5782+
let searchSpaceNode = getSuperContainer(superKeyword, /*stopOnFunctions*/ false);
57835783
if (!searchSpaceNode) {
57845784
return undefined;
57855785
}
@@ -5814,7 +5814,7 @@ namespace ts {
58145814
return;
58155815
}
58165816

5817-
const container = getSuperContainer(node, /*includeFunctions*/ false);
5817+
const container = getSuperContainer(node, /*stopOnFunctions*/ false);
58185818

58195819
// If we have a 'super' container, we must have an enclosing class.
58205820
// Now make sure the owning class is the same as the search-space

tests/baselines/reference/computedPropertyNames30_ES5.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
tests/cases/conformance/es6/computedProperties/computedPropertyNames30_ES5.ts(11,19): error TS2337: Super calls are not permitted outside constructors or in nested functions inside constructors.
1+
tests/cases/conformance/es6/computedProperties/computedPropertyNames30_ES5.ts(11,19): error TS2466: 'super' cannot be referenced in a computed property name.
22

33

44
==== tests/cases/conformance/es6/computedProperties/computedPropertyNames30_ES5.ts (1 errors) ====
@@ -14,7 +14,7 @@ tests/cases/conformance/es6/computedProperties/computedPropertyNames30_ES5.ts(11
1414
//treatment of other similar violations.
1515
[(super(), "prop")]() { }
1616
~~~~~
17-
!!! error TS2337: Super calls are not permitted outside constructors or in nested functions inside constructors.
17+
!!! error TS2466: 'super' cannot be referenced in a computed property name.
1818
};
1919
}
2020
}

tests/baselines/reference/computedPropertyNames30_ES6.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
tests/cases/conformance/es6/computedProperties/computedPropertyNames30_ES6.ts(11,19): error TS2337: Super calls are not permitted outside constructors or in nested functions inside constructors.
1+
tests/cases/conformance/es6/computedProperties/computedPropertyNames30_ES6.ts(11,19): error TS2466: 'super' cannot be referenced in a computed property name.
22

33

44
==== tests/cases/conformance/es6/computedProperties/computedPropertyNames30_ES6.ts (1 errors) ====
@@ -14,7 +14,7 @@ tests/cases/conformance/es6/computedProperties/computedPropertyNames30_ES6.ts(11
1414
//treatment of other similar violations.
1515
[(super(), "prop")]() { }
1616
~~~~~
17-
!!! error TS2337: Super calls are not permitted outside constructors or in nested functions inside constructors.
17+
!!! error TS2466: 'super' cannot be referenced in a computed property name.
1818
};
1919
}
2020
}

tests/baselines/reference/decoratorOnClassMethod12.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
tests/cases/conformance/decorators/class/method/decoratorOnClassMethod12.ts(6,10): error TS2338: 'super' property access is permitted only in a constructor, member function, or member accessor of a derived class.
1+
tests/cases/conformance/decorators/class/method/decoratorOnClassMethod12.ts(6,10): error TS2660: 'super' can only be referenced in members of derived classes or object literal expressions.
22

33

44
==== tests/cases/conformance/decorators/class/method/decoratorOnClassMethod12.ts (1 errors) ====
@@ -9,7 +9,7 @@ tests/cases/conformance/decorators/class/method/decoratorOnClassMethod12.ts(6,10
99
class C extends S {
1010
@super.decorator
1111
~~~~~
12-
!!! error TS2338: 'super' property access is permitted only in a constructor, member function, or member accessor of a derived class.
12+
!!! error TS2660: 'super' can only be referenced in members of derived classes or object literal expressions.
1313
method() { }
1414
}
1515
}

tests/baselines/reference/emitThisInSuperMethodCall.errors.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
tests/cases/compiler/emitThisInSuperMethodCall.ts(10,17): error TS2338: 'super' property access is permitted only in a constructor, member function, or member accessor of a derived class.
2-
tests/cases/compiler/emitThisInSuperMethodCall.ts(17,17): error TS2338: 'super' property access is permitted only in a constructor, member function, or member accessor of a derived class.
3-
tests/cases/compiler/emitThisInSuperMethodCall.ts(23,13): error TS2338: 'super' property access is permitted only in a constructor, member function, or member accessor of a derived class.
1+
tests/cases/compiler/emitThisInSuperMethodCall.ts(10,17): error TS2660: 'super' can only be referenced in members of derived classes or object literal expressions.
2+
tests/cases/compiler/emitThisInSuperMethodCall.ts(17,17): error TS2660: 'super' can only be referenced in members of derived classes or object literal expressions.
3+
tests/cases/compiler/emitThisInSuperMethodCall.ts(23,13): error TS2660: 'super' can only be referenced in members of derived classes or object literal expressions.
44

55

66
==== tests/cases/compiler/emitThisInSuperMethodCall.ts (3 errors) ====
@@ -15,7 +15,7 @@ tests/cases/compiler/emitThisInSuperMethodCall.ts(23,13): error TS2338: 'super'
1515
function inner() {
1616
super.sayHello();
1717
~~~~~
18-
!!! error TS2338: 'super' property access is permitted only in a constructor, member function, or member accessor of a derived class.
18+
!!! error TS2660: 'super' can only be referenced in members of derived classes or object literal expressions.
1919
}
2020
};
2121
}
@@ -24,15 +24,15 @@ tests/cases/compiler/emitThisInSuperMethodCall.ts(23,13): error TS2338: 'super'
2424
() => {
2525
super.sayHello();
2626
~~~~~
27-
!!! error TS2338: 'super' property access is permitted only in a constructor, member function, or member accessor of a derived class.
27+
!!! error TS2660: 'super' can only be referenced in members of derived classes or object literal expressions.
2828
}
2929
}
3030
}
3131
h() {
3232
function inner() {
3333
super.sayHello();
3434
~~~~~
35-
!!! error TS2338: 'super' property access is permitted only in a constructor, member function, or member accessor of a derived class.
35+
!!! error TS2660: 'super' can only be referenced in members of derived classes or object literal expressions.
3636
}
3737
}
3838
}

0 commit comments

Comments
 (0)
0