diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 701b1bfb24983..5bd11fc4d3f57 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -2734,6 +2734,9 @@ namespace ts { case SyntaxKind.PropertyAccessExpression: return computePropertyAccess(node, subtreeFlags); + case SyntaxKind.ElementAccessExpression: + return computeElementAccess(node, subtreeFlags); + default: return computeOther(node, kind, subtreeFlags); } @@ -2742,17 +2745,21 @@ namespace ts { function computeCallExpression(node: CallExpression, subtreeFlags: TransformFlags) { let transformFlags = subtreeFlags; const expression = node.expression; - const expressionKind = expression.kind; if (node.typeArguments) { transformFlags |= TransformFlags.AssertTypeScript; } if (subtreeFlags & TransformFlags.ContainsSpread - || isSuperOrSuperProperty(expression, expressionKind)) { + || (expression.transformFlags & (TransformFlags.Super | TransformFlags.ContainsSuper))) { // If the this node contains a SpreadExpression, or is a super call, then it is an ES6 // node. transformFlags |= TransformFlags.AssertES2015; + // super property or element accesses could be inside lambdas, etc, and need a captured `this`, + // while super keyword for super calls (indicated by TransformFlags.Super) does not (since it can only be top-level in a constructor) + if (expression.transformFlags & TransformFlags.ContainsSuper) { + transformFlags |= TransformFlags.ContainsLexicalThis; + } } if (expression.kind === SyntaxKind.ImportKeyword) { @@ -2769,21 +2776,6 @@ namespace ts { return transformFlags & ~TransformFlags.ArrayLiteralOrCallOrNewExcludes; } - function isSuperOrSuperProperty(node: Node, kind: SyntaxKind) { - switch (kind) { - case SyntaxKind.SuperKeyword: - return true; - - case SyntaxKind.PropertyAccessExpression: - case SyntaxKind.ElementAccessExpression: - const expression = (node).expression; - const expressionKind = expression.kind; - return expressionKind === SyntaxKind.SuperKeyword; - } - - return false; - } - function computeNewExpression(node: NewExpression, subtreeFlags: TransformFlags) { let transformFlags = subtreeFlags; if (node.typeArguments) { @@ -2878,7 +2870,7 @@ namespace ts { } node.transformFlags = transformFlags | TransformFlags.HasComputedFlags; - return transformFlags & ~TransformFlags.NodeExcludes; + return transformFlags & ~TransformFlags.OuterExpressionExcludes; } function computeClassDeclaration(node: ClassDeclaration, subtreeFlags: TransformFlags) { @@ -3197,17 +3189,32 @@ namespace ts { function computePropertyAccess(node: PropertyAccessExpression, subtreeFlags: TransformFlags) { let transformFlags = subtreeFlags; - const expression = node.expression; - const expressionKind = expression.kind; // If a PropertyAccessExpression starts with a super keyword, then it is // ES6 syntax, and requires a lexical `this` binding. - if (expressionKind === SyntaxKind.SuperKeyword) { - transformFlags |= TransformFlags.ContainsLexicalThis; + if (transformFlags & TransformFlags.Super) { + transformFlags ^= TransformFlags.Super; + transformFlags |= TransformFlags.ContainsSuper; } node.transformFlags = transformFlags | TransformFlags.HasComputedFlags; - return transformFlags & ~TransformFlags.NodeExcludes; + return transformFlags & ~TransformFlags.PropertyAccessExcludes; + } + + function computeElementAccess(node: ElementAccessExpression, subtreeFlags: TransformFlags) { + let transformFlags = subtreeFlags; + const expression = node.expression; + const expressionFlags = expression.transformFlags; // We do not want to aggregate flags from the argument expression for super/this capturing + + // If an ElementAccessExpression starts with a super keyword, then it is + // ES6 syntax, and requires a lexical `this` binding. + if (expressionFlags & TransformFlags.Super) { + transformFlags &= ~TransformFlags.Super; + transformFlags |= TransformFlags.ContainsSuper; + } + + node.transformFlags = transformFlags | TransformFlags.HasComputedFlags; + return transformFlags & ~TransformFlags.PropertyAccessExcludes; } function computeVariableDeclaration(node: VariableDeclaration, subtreeFlags: TransformFlags) { @@ -3327,6 +3334,13 @@ namespace ts { transformFlags |= TransformFlags.AssertESNext | TransformFlags.AssertES2017; break; + case SyntaxKind.TypeAssertionExpression: + case SyntaxKind.AsExpression: + case SyntaxKind.PartiallyEmittedExpression: + // These nodes are TypeScript syntax. + transformFlags |= TransformFlags.AssertTypeScript; + excludeFlags = TransformFlags.OuterExpressionExcludes; + break; case SyntaxKind.PublicKeyword: case SyntaxKind.PrivateKeyword: case SyntaxKind.ProtectedKeyword: @@ -3335,8 +3349,6 @@ namespace ts { case SyntaxKind.ConstKeyword: case SyntaxKind.EnumDeclaration: case SyntaxKind.EnumMember: - case SyntaxKind.TypeAssertionExpression: - case SyntaxKind.AsExpression: case SyntaxKind.NonNullExpression: case SyntaxKind.ReadonlyKeyword: // These nodes are TypeScript syntax. @@ -3464,7 +3476,8 @@ namespace ts { case SyntaxKind.SuperKeyword: // This node is ES6 syntax. - transformFlags |= TransformFlags.AssertES2015; + transformFlags |= TransformFlags.AssertES2015 | TransformFlags.Super; + excludeFlags = TransformFlags.OuterExpressionExcludes; // must be set to persist `Super` break; case SyntaxKind.ThisKeyword: @@ -3621,6 +3634,15 @@ namespace ts { case SyntaxKind.ObjectBindingPattern: case SyntaxKind.ArrayBindingPattern: return TransformFlags.BindingPatternExcludes; + case SyntaxKind.TypeAssertionExpression: + case SyntaxKind.AsExpression: + case SyntaxKind.PartiallyEmittedExpression: + case SyntaxKind.ParenthesizedExpression: + case SyntaxKind.SuperKeyword: + return TransformFlags.OuterExpressionExcludes; + case SyntaxKind.PropertyAccessExpression: + case SyntaxKind.ElementAccessExpression: + return TransformFlags.PropertyAccessExcludes; default: return TransformFlags.NodeExcludes; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 21fe9537424b2..5fb3d36920b54 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4448,6 +4448,8 @@ namespace ts { ContainsYield = 1 << 24, ContainsHoistedDeclarationOrCompletion = 1 << 25, ContainsDynamicImport = 1 << 26, + Super = 1 << 27, + ContainsSuper = 1 << 28, // Please leave this as 1 << 29. // It is the maximum bit we can set before we outgrow the size of a v8 small integer (SMI) on an x86 system. @@ -4468,7 +4470,9 @@ namespace ts { // Scope Exclusions // - Bitmasks that exclude flags from propagating out of a specific context // into the subtree flags of their container. - NodeExcludes = TypeScript | ES2015 | DestructuringAssignment | Generator | HasComputedFlags, + OuterExpressionExcludes = TypeScript | ES2015 | DestructuringAssignment | Generator | HasComputedFlags, + PropertyAccessExcludes = OuterExpressionExcludes | Super, + NodeExcludes = PropertyAccessExcludes | ContainsSuper, ArrowFunctionExcludes = NodeExcludes | ContainsDecorators | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRest, FunctionExcludes = NodeExcludes | ContainsDecorators | ContainsDefaultValueAssignments | ContainsCapturedLexicalThis | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRest, ConstructorExcludes = NodeExcludes | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRest, diff --git a/tests/baselines/reference/decoratorOnClassMethod12.js b/tests/baselines/reference/decoratorOnClassMethod12.js index 0063e0225bc44..494cb083a20f3 100644 --- a/tests/baselines/reference/decoratorOnClassMethod12.js +++ b/tests/baselines/reference/decoratorOnClassMethod12.js @@ -28,7 +28,6 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, }; var M; (function (M) { - var _this = this; var S = /** @class */ (function () { function S() { } diff --git a/tests/baselines/reference/superAccess2.js b/tests/baselines/reference/superAccess2.js index d3aac217e2229..de755361a16ca 100644 --- a/tests/baselines/reference/superAccess2.js +++ b/tests/baselines/reference/superAccess2.js @@ -35,7 +35,6 @@ var __extends = (this && this.__extends) || (function () { d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); -var _this = this; var P = /** @class */ (function () { function P() { } diff --git a/tests/baselines/reference/superAccessCastedCall.js b/tests/baselines/reference/superAccessCastedCall.js new file mode 100644 index 0000000000000..a4583b3e71042 --- /dev/null +++ b/tests/baselines/reference/superAccessCastedCall.js @@ -0,0 +1,54 @@ +//// [superAccessCastedCall.ts] +class Foo { + bar(): void {} +} + +class Bar extends Foo { + x: Number; + + constructor() { + super(); + this.x = 2; + } + + bar() { + super.bar(); + (super.bar as any)(); + } +} + +let b = new Bar(); +b.bar() + +//// [superAccessCastedCall.js] +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var Foo = /** @class */ (function () { + function Foo() { + } + Foo.prototype.bar = function () { }; + return Foo; +}()); +var Bar = /** @class */ (function (_super) { + __extends(Bar, _super); + function Bar() { + var _this = _super.call(this) || this; + _this.x = 2; + return _this; + } + Bar.prototype.bar = function () { + _super.prototype.bar.call(this); + _super.prototype.bar.call(this); + }; + return Bar; +}(Foo)); +var b = new Bar(); +b.bar(); diff --git a/tests/baselines/reference/superAccessCastedCall.symbols b/tests/baselines/reference/superAccessCastedCall.symbols new file mode 100644 index 0000000000000..83b9447c3f76d --- /dev/null +++ b/tests/baselines/reference/superAccessCastedCall.symbols @@ -0,0 +1,50 @@ +=== tests/cases/compiler/superAccessCastedCall.ts === +class Foo { +>Foo : Symbol(Foo, Decl(superAccessCastedCall.ts, 0, 0)) + + bar(): void {} +>bar : Symbol(Foo.bar, Decl(superAccessCastedCall.ts, 0, 11)) +} + +class Bar extends Foo { +>Bar : Symbol(Bar, Decl(superAccessCastedCall.ts, 2, 1)) +>Foo : Symbol(Foo, Decl(superAccessCastedCall.ts, 0, 0)) + + x: Number; +>x : Symbol(Bar.x, Decl(superAccessCastedCall.ts, 4, 23)) +>Number : Symbol(Number, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + + constructor() { + super(); +>super : Symbol(Foo, Decl(superAccessCastedCall.ts, 0, 0)) + + this.x = 2; +>this.x : Symbol(Bar.x, Decl(superAccessCastedCall.ts, 4, 23)) +>this : Symbol(Bar, Decl(superAccessCastedCall.ts, 2, 1)) +>x : Symbol(Bar.x, Decl(superAccessCastedCall.ts, 4, 23)) + } + + bar() { +>bar : Symbol(Bar.bar, Decl(superAccessCastedCall.ts, 10, 5)) + + super.bar(); +>super.bar : Symbol(Foo.bar, Decl(superAccessCastedCall.ts, 0, 11)) +>super : Symbol(Foo, Decl(superAccessCastedCall.ts, 0, 0)) +>bar : Symbol(Foo.bar, Decl(superAccessCastedCall.ts, 0, 11)) + + (super.bar as any)(); +>super.bar : Symbol(Foo.bar, Decl(superAccessCastedCall.ts, 0, 11)) +>super : Symbol(Foo, Decl(superAccessCastedCall.ts, 0, 0)) +>bar : Symbol(Foo.bar, Decl(superAccessCastedCall.ts, 0, 11)) + } +} + +let b = new Bar(); +>b : Symbol(b, Decl(superAccessCastedCall.ts, 18, 3)) +>Bar : Symbol(Bar, Decl(superAccessCastedCall.ts, 2, 1)) + +b.bar() +>b.bar : Symbol(Bar.bar, Decl(superAccessCastedCall.ts, 10, 5)) +>b : Symbol(b, Decl(superAccessCastedCall.ts, 18, 3)) +>bar : Symbol(Bar.bar, Decl(superAccessCastedCall.ts, 10, 5)) + diff --git a/tests/baselines/reference/superAccessCastedCall.types b/tests/baselines/reference/superAccessCastedCall.types new file mode 100644 index 0000000000000..72ee3c05a7ed9 --- /dev/null +++ b/tests/baselines/reference/superAccessCastedCall.types @@ -0,0 +1,59 @@ +=== tests/cases/compiler/superAccessCastedCall.ts === +class Foo { +>Foo : Foo + + bar(): void {} +>bar : () => void +} + +class Bar extends Foo { +>Bar : Bar +>Foo : Foo + + x: Number; +>x : Number +>Number : Number + + constructor() { + super(); +>super() : void +>super : typeof Foo + + this.x = 2; +>this.x = 2 : 2 +>this.x : Number +>this : this +>x : Number +>2 : 2 + } + + bar() { +>bar : () => void + + super.bar(); +>super.bar() : void +>super.bar : () => void +>super : Foo +>bar : () => void + + (super.bar as any)(); +>(super.bar as any)() : any +>(super.bar as any) : any +>super.bar as any : any +>super.bar : () => void +>super : Foo +>bar : () => void + } +} + +let b = new Bar(); +>b : Bar +>new Bar() : Bar +>Bar : typeof Bar + +b.bar() +>b.bar() : void +>b.bar : () => void +>b : Bar +>bar : () => void + diff --git a/tests/baselines/reference/superElementAccess.errors.txt b/tests/baselines/reference/superElementAccess.errors.txt new file mode 100644 index 0000000000000..e5d8c3ea5ad8f --- /dev/null +++ b/tests/baselines/reference/superElementAccess.errors.txt @@ -0,0 +1,44 @@ +tests/cases/compiler/superElementAccess.ts(7,9): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. +tests/cases/compiler/superElementAccess.ts(8,9): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. + + +==== tests/cases/compiler/superElementAccess.ts (2 errors) ==== + class MyBase { + m1(a: string) { return a; } + private p1() { } + m2: () => void = function () { } + d1: number = 42; + private d2: number = 42; + get value() {return 0 } + ~~~~~ +!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. + set value(v: number) { } + ~~~~~ +!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. + } + + + class MyDerived extends MyBase { + + foo() { + super["m1"]("hi"); // Should be allowed, method on base prototype + + var l2 = super["m1"].bind(this); // Should be allowed, can access properties as well as invoke + + var x: (a: string) => string = super["m1"]; // Should be allowed, can assign to var with compatible signature + + super["m2"].bind(this); // Should error, instance property, not a public instance member function + + super["p1"](); // Should error, private not public instance member function + + var l1 = super["d1"]; // Should error, instance data property not a public instance member function + + var l1 = super["d2"]; // Should error, instance data property not a public instance member function + + super["m1"] = function (a: string) { return ""; }; // Should be allowed, we will not restrict assignment + + super["value"] = 0; // Should error, instance data property not a public instance member function + + var z = super["value"]; // Should error, instance data property not a public instance member function + } + } \ No newline at end of file diff --git a/tests/baselines/reference/superElementAccess.js b/tests/baselines/reference/superElementAccess.js new file mode 100644 index 0000000000000..422b80109bb5b --- /dev/null +++ b/tests/baselines/reference/superElementAccess.js @@ -0,0 +1,84 @@ +//// [superElementAccess.ts] +class MyBase { + m1(a: string) { return a; } + private p1() { } + m2: () => void = function () { } + d1: number = 42; + private d2: number = 42; + get value() {return 0 } + set value(v: number) { } +} + + +class MyDerived extends MyBase { + + foo() { + super["m1"]("hi"); // Should be allowed, method on base prototype + + var l2 = super["m1"].bind(this); // Should be allowed, can access properties as well as invoke + + var x: (a: string) => string = super["m1"]; // Should be allowed, can assign to var with compatible signature + + super["m2"].bind(this); // Should error, instance property, not a public instance member function + + super["p1"](); // Should error, private not public instance member function + + var l1 = super["d1"]; // Should error, instance data property not a public instance member function + + var l1 = super["d2"]; // Should error, instance data property not a public instance member function + + super["m1"] = function (a: string) { return ""; }; // Should be allowed, we will not restrict assignment + + super["value"] = 0; // Should error, instance data property not a public instance member function + + var z = super["value"]; // Should error, instance data property not a public instance member function + } +} + +//// [superElementAccess.js] +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var MyBase = /** @class */ (function () { + function MyBase() { + this.m2 = function () { }; + this.d1 = 42; + this.d2 = 42; + } + MyBase.prototype.m1 = function (a) { return a; }; + MyBase.prototype.p1 = function () { }; + Object.defineProperty(MyBase.prototype, "value", { + get: function () { return 0; }, + set: function (v) { }, + enumerable: true, + configurable: true + }); + return MyBase; +}()); +var MyDerived = /** @class */ (function (_super) { + __extends(MyDerived, _super); + function MyDerived() { + return _super !== null && _super.apply(this, arguments) || this; + } + MyDerived.prototype.foo = function () { + _super.prototype["m1"].call(this, "hi"); // Should be allowed, method on base prototype + var l2 = (_a = _super.prototype["m1"]).bind.call(_a, this); // Should be allowed, can access properties as well as invoke + var x = _super.prototype["m1"]; // Should be allowed, can assign to var with compatible signature + (_b = _super.prototype["m2"]).bind.call(_b, this); // Should error, instance property, not a public instance member function + _super.prototype["p1"].call(this); // Should error, private not public instance member function + var l1 = _super.prototype["d1"]; // Should error, instance data property not a public instance member function + var l1 = _super.prototype["d2"]; // Should error, instance data property not a public instance member function + _super.prototype["m1"] = function (a) { return ""; }; // Should be allowed, we will not restrict assignment + _super.prototype["value"] = 0; // Should error, instance data property not a public instance member function + var z = _super.prototype["value"]; // Should error, instance data property not a public instance member function + var _a, _b; + }; + return MyDerived; +}(MyBase)); diff --git a/tests/baselines/reference/superElementAccess.symbols b/tests/baselines/reference/superElementAccess.symbols new file mode 100644 index 0000000000000..5da1450212b55 --- /dev/null +++ b/tests/baselines/reference/superElementAccess.symbols @@ -0,0 +1,91 @@ +=== tests/cases/compiler/superElementAccess.ts === +class MyBase { +>MyBase : Symbol(MyBase, Decl(superElementAccess.ts, 0, 0)) + + m1(a: string) { return a; } +>m1 : Symbol(MyBase.m1, Decl(superElementAccess.ts, 0, 14)) +>a : Symbol(a, Decl(superElementAccess.ts, 1, 7)) +>a : Symbol(a, Decl(superElementAccess.ts, 1, 7)) + + private p1() { } +>p1 : Symbol(MyBase.p1, Decl(superElementAccess.ts, 1, 31)) + + m2: () => void = function () { } +>m2 : Symbol(MyBase.m2, Decl(superElementAccess.ts, 2, 20)) + + d1: number = 42; +>d1 : Symbol(MyBase.d1, Decl(superElementAccess.ts, 3, 36)) + + private d2: number = 42; +>d2 : Symbol(MyBase.d2, Decl(superElementAccess.ts, 4, 20)) + + get value() {return 0 } +>value : Symbol(MyBase.value, Decl(superElementAccess.ts, 5, 28), Decl(superElementAccess.ts, 6, 27)) + + set value(v: number) { } +>value : Symbol(MyBase.value, Decl(superElementAccess.ts, 5, 28), Decl(superElementAccess.ts, 6, 27)) +>v : Symbol(v, Decl(superElementAccess.ts, 7, 14)) +} + + +class MyDerived extends MyBase { +>MyDerived : Symbol(MyDerived, Decl(superElementAccess.ts, 8, 1)) +>MyBase : Symbol(MyBase, Decl(superElementAccess.ts, 0, 0)) + + foo() { +>foo : Symbol(MyDerived.foo, Decl(superElementAccess.ts, 11, 32)) + + super["m1"]("hi"); // Should be allowed, method on base prototype +>super : Symbol(MyBase, Decl(superElementAccess.ts, 0, 0)) +>"m1" : Symbol(MyBase.m1, Decl(superElementAccess.ts, 0, 14)) + + var l2 = super["m1"].bind(this); // Should be allowed, can access properties as well as invoke +>l2 : Symbol(l2, Decl(superElementAccess.ts, 16, 11)) +>super["m1"].bind : Symbol(Function.bind, Decl(lib.d.ts, --, --)) +>super : Symbol(MyBase, Decl(superElementAccess.ts, 0, 0)) +>"m1" : Symbol(MyBase.m1, Decl(superElementAccess.ts, 0, 14)) +>bind : Symbol(Function.bind, Decl(lib.d.ts, --, --)) +>this : Symbol(MyDerived, Decl(superElementAccess.ts, 8, 1)) + + var x: (a: string) => string = super["m1"]; // Should be allowed, can assign to var with compatible signature +>x : Symbol(x, Decl(superElementAccess.ts, 18, 11)) +>a : Symbol(a, Decl(superElementAccess.ts, 18, 16)) +>super : Symbol(MyBase, Decl(superElementAccess.ts, 0, 0)) +>"m1" : Symbol(MyBase.m1, Decl(superElementAccess.ts, 0, 14)) + + super["m2"].bind(this); // Should error, instance property, not a public instance member function +>super["m2"].bind : Symbol(Function.bind, Decl(lib.d.ts, --, --)) +>super : Symbol(MyBase, Decl(superElementAccess.ts, 0, 0)) +>"m2" : Symbol(MyBase.m2, Decl(superElementAccess.ts, 2, 20)) +>bind : Symbol(Function.bind, Decl(lib.d.ts, --, --)) +>this : Symbol(MyDerived, Decl(superElementAccess.ts, 8, 1)) + + super["p1"](); // Should error, private not public instance member function +>super : Symbol(MyBase, Decl(superElementAccess.ts, 0, 0)) +>"p1" : Symbol(MyBase.p1, Decl(superElementAccess.ts, 1, 31)) + + var l1 = super["d1"]; // Should error, instance data property not a public instance member function +>l1 : Symbol(l1, Decl(superElementAccess.ts, 24, 11), Decl(superElementAccess.ts, 26, 11)) +>super : Symbol(MyBase, Decl(superElementAccess.ts, 0, 0)) +>"d1" : Symbol(MyBase.d1, Decl(superElementAccess.ts, 3, 36)) + + var l1 = super["d2"]; // Should error, instance data property not a public instance member function +>l1 : Symbol(l1, Decl(superElementAccess.ts, 24, 11), Decl(superElementAccess.ts, 26, 11)) +>super : Symbol(MyBase, Decl(superElementAccess.ts, 0, 0)) +>"d2" : Symbol(MyBase.d2, Decl(superElementAccess.ts, 4, 20)) + + super["m1"] = function (a: string) { return ""; }; // Should be allowed, we will not restrict assignment +>super : Symbol(MyBase, Decl(superElementAccess.ts, 0, 0)) +>"m1" : Symbol(MyBase.m1, Decl(superElementAccess.ts, 0, 14)) +>a : Symbol(a, Decl(superElementAccess.ts, 28, 32)) + + super["value"] = 0; // Should error, instance data property not a public instance member function +>super : Symbol(MyBase, Decl(superElementAccess.ts, 0, 0)) +>"value" : Symbol(MyBase.value, Decl(superElementAccess.ts, 5, 28), Decl(superElementAccess.ts, 6, 27)) + + var z = super["value"]; // Should error, instance data property not a public instance member function +>z : Symbol(z, Decl(superElementAccess.ts, 32, 11)) +>super : Symbol(MyBase, Decl(superElementAccess.ts, 0, 0)) +>"value" : Symbol(MyBase.value, Decl(superElementAccess.ts, 5, 28), Decl(superElementAccess.ts, 6, 27)) + } +} diff --git a/tests/baselines/reference/superElementAccess.types b/tests/baselines/reference/superElementAccess.types new file mode 100644 index 0000000000000..9fa75ec6bc4bb --- /dev/null +++ b/tests/baselines/reference/superElementAccess.types @@ -0,0 +1,115 @@ +=== tests/cases/compiler/superElementAccess.ts === +class MyBase { +>MyBase : MyBase + + m1(a: string) { return a; } +>m1 : (a: string) => string +>a : string +>a : string + + private p1() { } +>p1 : () => void + + m2: () => void = function () { } +>m2 : () => void +>function () { } : () => void + + d1: number = 42; +>d1 : number +>42 : 42 + + private d2: number = 42; +>d2 : number +>42 : 42 + + get value() {return 0 } +>value : number +>0 : 0 + + set value(v: number) { } +>value : number +>v : number +} + + +class MyDerived extends MyBase { +>MyDerived : MyDerived +>MyBase : MyBase + + foo() { +>foo : () => void + + super["m1"]("hi"); // Should be allowed, method on base prototype +>super["m1"]("hi") : string +>super["m1"] : (a: string) => string +>super : MyBase +>"m1" : "m1" +>"hi" : "hi" + + var l2 = super["m1"].bind(this); // Should be allowed, can access properties as well as invoke +>l2 : any +>super["m1"].bind(this) : any +>super["m1"].bind : (this: Function, thisArg: any, ...argArray: any[]) => any +>super["m1"] : (a: string) => string +>super : MyBase +>"m1" : "m1" +>bind : (this: Function, thisArg: any, ...argArray: any[]) => any +>this : this + + var x: (a: string) => string = super["m1"]; // Should be allowed, can assign to var with compatible signature +>x : (a: string) => string +>a : string +>super["m1"] : (a: string) => string +>super : MyBase +>"m1" : "m1" + + super["m2"].bind(this); // Should error, instance property, not a public instance member function +>super["m2"].bind(this) : any +>super["m2"].bind : (this: Function, thisArg: any, ...argArray: any[]) => any +>super["m2"] : () => void +>super : MyBase +>"m2" : "m2" +>bind : (this: Function, thisArg: any, ...argArray: any[]) => any +>this : this + + super["p1"](); // Should error, private not public instance member function +>super["p1"]() : void +>super["p1"] : () => void +>super : MyBase +>"p1" : "p1" + + var l1 = super["d1"]; // Should error, instance data property not a public instance member function +>l1 : number +>super["d1"] : number +>super : MyBase +>"d1" : "d1" + + var l1 = super["d2"]; // Should error, instance data property not a public instance member function +>l1 : number +>super["d2"] : number +>super : MyBase +>"d2" : "d2" + + super["m1"] = function (a: string) { return ""; }; // Should be allowed, we will not restrict assignment +>super["m1"] = function (a: string) { return ""; } : (a: string) => string +>super["m1"] : (a: string) => string +>super : MyBase +>"m1" : "m1" +>function (a: string) { return ""; } : (a: string) => string +>a : string +>"" : "" + + super["value"] = 0; // Should error, instance data property not a public instance member function +>super["value"] = 0 : 0 +>super["value"] : number +>super : MyBase +>"value" : "value" +>0 : 0 + + var z = super["value"]; // Should error, instance data property not a public instance member function +>z : number +>super["value"] : number +>super : MyBase +>"value" : "value" + } +} diff --git a/tests/baselines/reference/superErrors.js b/tests/baselines/reference/superErrors.js index 87d4e3bb85a29..952cb03fd80a5 100644 --- a/tests/baselines/reference/superErrors.js +++ b/tests/baselines/reference/superErrors.js @@ -63,7 +63,6 @@ var __extends = (this && this.__extends) || (function () { }; })(); function foo() { - var _this = this; // super in a non class context var x = _super.; var y = function () { return _super.; }; @@ -93,10 +92,7 @@ var RegisteredUser = /** @class */ (function (_super) { var x = function () { return _super.sayHello.call(_this); }; } // super call in a lambda in a function expression in a constructor - (function () { - var _this = this; - return function () { return _super.; }; - })(); + (function () { return function () { return _super.; }; })(); return _this; } RegisteredUser.prototype.sayHello = function () { @@ -108,13 +104,9 @@ var RegisteredUser = /** @class */ (function (_super) { var x = function () { return _super.sayHello.call(_this); }; } // super call in a lambda in a function expression in a constructor - (function () { - var _this = this; - return function () { return _super.; }; - })(); + (function () { return function () { return _super.; }; })(); }; RegisteredUser.staticFunction = function () { - var _this = this; // super in static functions var s = _super.; var x = function () { return _super.; }; diff --git a/tests/baselines/reference/superInLambdas.js b/tests/baselines/reference/superInLambdas.js index 653d3ae84c14b..9bb1a87e0ea76 100644 --- a/tests/baselines/reference/superInLambdas.js +++ b/tests/baselines/reference/superInLambdas.js @@ -133,7 +133,6 @@ var RegisteredUser3 = /** @class */ (function (_super) { return _this; } RegisteredUser3.prototype.sayHello = function () { - var _this = this; // super property in a nested lambda in a method var superName = function () { return function () { return function () { return _super.prototype.name; }; }; }; }; @@ -149,7 +148,6 @@ var RegisteredUser4 = /** @class */ (function (_super) { return _this; } RegisteredUser4.prototype.sayHello = function () { - var _this = this; // super in a nested lambda in a method var x = function () { return function () { return _super.prototype.; }; }; }; diff --git a/tests/baselines/reference/superPropertyAccess.js b/tests/baselines/reference/superPropertyAccess.js index cc9758a161736..8fa0984745c2a 100644 --- a/tests/baselines/reference/superPropertyAccess.js +++ b/tests/baselines/reference/superPropertyAccess.js @@ -69,15 +69,16 @@ var MyDerived = /** @class */ (function (_super) { } MyDerived.prototype.foo = function () { _super.prototype.m1.call(this, "hi"); // Should be allowed, method on base prototype - var l2 = _super.prototype.m1.bind(this); // Should be allowed, can access properties as well as invoke + var l2 = (_a = _super.prototype.m1).bind.call(_a, this); // Should be allowed, can access properties as well as invoke var x = _super.prototype.m1; // Should be allowed, can assign to var with compatible signature - _super.prototype.m2.bind(this); // Should error, instance property, not a public instance member function + (_b = _super.prototype.m2).bind.call(_b, this); // Should error, instance property, not a public instance member function _super.prototype.p1.call(this); // Should error, private not public instance member function var l1 = _super.prototype.d1; // Should error, instance data property not a public instance member function var l1 = _super.prototype.d2; // Should error, instance data property not a public instance member function _super.prototype.m1 = function (a) { return ""; }; // Should be allowed, we will not restrict assignment _super.prototype.value = 0; // Should error, instance data property not a public instance member function var z = _super.prototype.value; // Should error, instance data property not a public instance member function + var _a, _b; }; return MyDerived; }(MyBase)); diff --git a/tests/baselines/reference/superPropertyElementNoUnusedLexicalThisCapture.js b/tests/baselines/reference/superPropertyElementNoUnusedLexicalThisCapture.js new file mode 100644 index 0000000000000..126c123b40ddd --- /dev/null +++ b/tests/baselines/reference/superPropertyElementNoUnusedLexicalThisCapture.js @@ -0,0 +1,53 @@ +//// [superPropertyElementNoUnusedLexicalThisCapture.ts] +class A { x() {} } + +class B extends A { + constructor() { + super(); + } + foo() { + return () => { + super.x; + } + } + bar() { + return () => { + super["x"]; + } + } +} + +//// [superPropertyElementNoUnusedLexicalThisCapture.js] +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var A = /** @class */ (function () { + function A() { + } + A.prototype.x = function () { }; + return A; +}()); +var B = /** @class */ (function (_super) { + __extends(B, _super); + function B() { + return _super.call(this) || this; + } + B.prototype.foo = function () { + return function () { + _super.prototype.x; + }; + }; + B.prototype.bar = function () { + return function () { + _super.prototype["x"]; + }; + }; + return B; +}(A)); diff --git a/tests/baselines/reference/superPropertyElementNoUnusedLexicalThisCapture.symbols b/tests/baselines/reference/superPropertyElementNoUnusedLexicalThisCapture.symbols new file mode 100644 index 0000000000000..080268a074480 --- /dev/null +++ b/tests/baselines/reference/superPropertyElementNoUnusedLexicalThisCapture.symbols @@ -0,0 +1,33 @@ +=== tests/cases/compiler/superPropertyElementNoUnusedLexicalThisCapture.ts === +class A { x() {} } +>A : Symbol(A, Decl(superPropertyElementNoUnusedLexicalThisCapture.ts, 0, 0)) +>x : Symbol(A.x, Decl(superPropertyElementNoUnusedLexicalThisCapture.ts, 0, 9)) + +class B extends A { +>B : Symbol(B, Decl(superPropertyElementNoUnusedLexicalThisCapture.ts, 0, 18)) +>A : Symbol(A, Decl(superPropertyElementNoUnusedLexicalThisCapture.ts, 0, 0)) + + constructor() { + super(); +>super : Symbol(A, Decl(superPropertyElementNoUnusedLexicalThisCapture.ts, 0, 0)) + } + foo() { +>foo : Symbol(B.foo, Decl(superPropertyElementNoUnusedLexicalThisCapture.ts, 5, 5)) + + return () => { + super.x; +>super.x : Symbol(A.x, Decl(superPropertyElementNoUnusedLexicalThisCapture.ts, 0, 9)) +>super : Symbol(A, Decl(superPropertyElementNoUnusedLexicalThisCapture.ts, 0, 0)) +>x : Symbol(A.x, Decl(superPropertyElementNoUnusedLexicalThisCapture.ts, 0, 9)) + } + } + bar() { +>bar : Symbol(B.bar, Decl(superPropertyElementNoUnusedLexicalThisCapture.ts, 10, 5)) + + return () => { + super["x"]; +>super : Symbol(A, Decl(superPropertyElementNoUnusedLexicalThisCapture.ts, 0, 0)) +>"x" : Symbol(A.x, Decl(superPropertyElementNoUnusedLexicalThisCapture.ts, 0, 9)) + } + } +} diff --git a/tests/baselines/reference/superPropertyElementNoUnusedLexicalThisCapture.types b/tests/baselines/reference/superPropertyElementNoUnusedLexicalThisCapture.types new file mode 100644 index 0000000000000..37048f2f1d547 --- /dev/null +++ b/tests/baselines/reference/superPropertyElementNoUnusedLexicalThisCapture.types @@ -0,0 +1,39 @@ +=== tests/cases/compiler/superPropertyElementNoUnusedLexicalThisCapture.ts === +class A { x() {} } +>A : A +>x : () => void + +class B extends A { +>B : B +>A : A + + constructor() { + super(); +>super() : void +>super : typeof A + } + foo() { +>foo : () => () => void + + return () => { +>() => { super.x; } : () => void + + super.x; +>super.x : () => void +>super : A +>x : () => void + } + } + bar() { +>bar : () => () => void + + return () => { +>() => { super["x"]; } : () => void + + super["x"]; +>super["x"] : () => void +>super : A +>"x" : "x" + } + } +} diff --git a/tests/cases/compiler/superAccessCastedCall.ts b/tests/cases/compiler/superAccessCastedCall.ts new file mode 100644 index 0000000000000..98f154834e1be --- /dev/null +++ b/tests/cases/compiler/superAccessCastedCall.ts @@ -0,0 +1,20 @@ +class Foo { + bar(): void {} +} + +class Bar extends Foo { + x: Number; + + constructor() { + super(); + this.x = 2; + } + + bar() { + super.bar(); + (super.bar as any)(); + } +} + +let b = new Bar(); +b.bar() \ No newline at end of file diff --git a/tests/cases/compiler/superElementAccess.ts b/tests/cases/compiler/superElementAccess.ts new file mode 100644 index 0000000000000..1b7e3f456834a --- /dev/null +++ b/tests/cases/compiler/superElementAccess.ts @@ -0,0 +1,36 @@ + +class MyBase { + m1(a: string) { return a; } + private p1() { } + m2: () => void = function () { } + d1: number = 42; + private d2: number = 42; + get value() {return 0 } + set value(v: number) { } +} + + +class MyDerived extends MyBase { + + foo() { + super["m1"]("hi"); // Should be allowed, method on base prototype + + var l2 = super["m1"].bind(this); // Should be allowed, can access properties as well as invoke + + var x: (a: string) => string = super["m1"]; // Should be allowed, can assign to var with compatible signature + + super["m2"].bind(this); // Should error, instance property, not a public instance member function + + super["p1"](); // Should error, private not public instance member function + + var l1 = super["d1"]; // Should error, instance data property not a public instance member function + + var l1 = super["d2"]; // Should error, instance data property not a public instance member function + + super["m1"] = function (a: string) { return ""; }; // Should be allowed, we will not restrict assignment + + super["value"] = 0; // Should error, instance data property not a public instance member function + + var z = super["value"]; // Should error, instance data property not a public instance member function + } +} \ No newline at end of file diff --git a/tests/cases/compiler/superPropertyElementNoUnusedLexicalThisCapture.ts b/tests/cases/compiler/superPropertyElementNoUnusedLexicalThisCapture.ts new file mode 100644 index 0000000000000..b5e40b7ceff64 --- /dev/null +++ b/tests/cases/compiler/superPropertyElementNoUnusedLexicalThisCapture.ts @@ -0,0 +1,17 @@ +class A { x() {} } + +class B extends A { + constructor() { + super(); + } + foo() { + return () => { + super.x; + } + } + bar() { + return () => { + super["x"]; + } + } +} \ No newline at end of file