From 93dbcf006f3855c20f02e587970add1744cf32d1 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Mon, 26 Jan 2015 18:42:17 -0800 Subject: [PATCH 1/6] Contextually type parameters in super calls using type arguments on the base class. --- src/compiler/checker.ts | 31 +++++++++++++-- .../superCallArgsMustMatch.errors.txt | 29 ++++++++++++++ .../reference/superCallArgsMustMatch.types | 38 ------------------- .../superCallParameterContextualTyping1.js | 35 +++++++++++++++++ .../superCallParameterContextualTyping1.types | 34 +++++++++++++++++ ...rCallParameterContextualTyping2.errors.txt | 17 +++++++++ .../superCallParameterContextualTyping2.js | 34 +++++++++++++++++ .../superCallParameterContextualTyping1.ts | 11 ++++++ .../superCallParameterContextualTyping2.ts | 11 ++++++ ...ntextuallyTypedArrowFunctionInSuperCall.ts | 20 ++++++++++ 10 files changed, 219 insertions(+), 41 deletions(-) create mode 100644 tests/baselines/reference/superCallArgsMustMatch.errors.txt delete mode 100644 tests/baselines/reference/superCallArgsMustMatch.types create mode 100644 tests/baselines/reference/superCallParameterContextualTyping1.js create mode 100644 tests/baselines/reference/superCallParameterContextualTyping1.types create mode 100644 tests/baselines/reference/superCallParameterContextualTyping2.errors.txt create mode 100644 tests/baselines/reference/superCallParameterContextualTyping2.js create mode 100644 tests/cases/conformance/expressions/contextualTyping/superCallParameterContextualTyping1.ts create mode 100644 tests/cases/conformance/expressions/contextualTyping/superCallParameterContextualTyping2.ts create mode 100644 tests/cases/fourslash/quickInfoForContextuallyTypedArrowFunctionInSuperCall.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e5624fb8916f0..6887421ba326d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5978,11 +5978,36 @@ module ts { return args; } + // In a 'super' call, type arguments are not provided within the CallExpression node itself. + // Instead, they must be fetched from the class declaration's base type node. + function getEffectiveTypeArguments(callExpression: CallExpression): TypeNode[] { + if (callExpression.expression.kind === SyntaxKind.SuperKeyword) { + // TODO (drosen): 1) Discuss if checking needs to be done at this point. + // 2) Have a test where type arguments are not provided on the base class. + // 3) Have a test where the base class is not generic. + var containingClass = getAncestor(callExpression, SyntaxKind.ClassDeclaration); + var baseClassTypeNode = getClassBaseTypeNode(containingClass); + return baseClassTypeNode.typeArguments; + } + else { + // Ordinary case - simple function invocation. + return (callExpression).typeArguments; + } + } + function resolveCall(node: CallLikeExpression, signatures: Signature[], candidatesOutArray: Signature[]): Signature { var isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression; - var typeArguments = isTaggedTemplate ? undefined : (node).typeArguments; - forEach(typeArguments, checkSourceElement); + var typeArguments: TypeNode[]; + + if (!isTaggedTemplate) { + typeArguments = getEffectiveTypeArguments(node); + + // We already perform checking on the type arguments on the class declaration itself. + if ((node).expression.kind !== SyntaxKind.SuperKeyword) { + forEach(typeArguments, checkSourceElement); + } + } var candidates = candidatesOutArray || []; // collectCandidates fills up the candidates array directly @@ -6248,7 +6273,7 @@ module ts { // Another error has already been reported return resolveErrorCall(node); } - + // Technically, this signatures list may be incomplete. We are taking the apparent type, // but we are not including call signatures that may have been added to the Object or // Function interface, since they have none by default. This is a bit of a leap of faith diff --git a/tests/baselines/reference/superCallArgsMustMatch.errors.txt b/tests/baselines/reference/superCallArgsMustMatch.errors.txt new file mode 100644 index 0000000000000..e9a665acd1f87 --- /dev/null +++ b/tests/baselines/reference/superCallArgsMustMatch.errors.txt @@ -0,0 +1,29 @@ +tests/cases/compiler/superCallArgsMustMatch.ts(15,15): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. + + +==== tests/cases/compiler/superCallArgsMustMatch.ts (1 errors) ==== + class T5{ + + public foo: T; + + constructor(public bar: T) { } + + } + + + + class T6 extends T5{ + + constructor() { + + super("hi"); // Should error, base constructor has type T for first arg, which is fixed as number in the extends clause + ~~~~ +!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. + + var x: number = this.foo; + + } + + } + + \ No newline at end of file diff --git a/tests/baselines/reference/superCallArgsMustMatch.types b/tests/baselines/reference/superCallArgsMustMatch.types deleted file mode 100644 index c2019881d9436..0000000000000 --- a/tests/baselines/reference/superCallArgsMustMatch.types +++ /dev/null @@ -1,38 +0,0 @@ -=== tests/cases/compiler/superCallArgsMustMatch.ts === -class T5{ ->T5 : T5 ->T : T - - public foo: T; ->foo : T ->T : T - - constructor(public bar: T) { } ->bar : T ->T : T - -} - - - -class T6 extends T5{ ->T6 : T6 ->T5 : T5 - - constructor() { - - super("hi"); // Should error, base constructor has type T for first arg, which is fixed as number in the extends clause ->super("hi") : void ->super : typeof T5 - - var x: number = this.foo; ->x : number ->this.foo : number ->this : T6 ->foo : number - - } - -} - - diff --git a/tests/baselines/reference/superCallParameterContextualTyping1.js b/tests/baselines/reference/superCallParameterContextualTyping1.js new file mode 100644 index 0000000000000..b11d62d62c8ba --- /dev/null +++ b/tests/baselines/reference/superCallParameterContextualTyping1.js @@ -0,0 +1,35 @@ +//// [superCallParameterContextualTyping1.ts] + +class A { + constructor(private map: (value: T1) => T2) { + + } +} + +class B extends A { + // Ensure 'value' is of type 'number (and not '{}') by using its 'toExponential()' method. + constructor() { super(value => String(value.toExponential())); } +} + + +//// [superCallParameterContextualTyping1.js] +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var A = (function () { + function A(map) { + this.map = map; + } + return A; +})(); +var B = (function (_super) { + __extends(B, _super); + // Ensure 'value' is of type 'number (and not '{}') by using its 'toExponential()' method. + function B() { + _super.call(this, function (value) { return String(value.toExponential()); }); + } + return B; +})(A); diff --git a/tests/baselines/reference/superCallParameterContextualTyping1.types b/tests/baselines/reference/superCallParameterContextualTyping1.types new file mode 100644 index 0000000000000..23aa3147997f3 --- /dev/null +++ b/tests/baselines/reference/superCallParameterContextualTyping1.types @@ -0,0 +1,34 @@ +=== tests/cases/conformance/expressions/contextualTyping/superCallParameterContextualTyping1.ts === + +class A { +>A : A +>T1 : T1 +>T2 : T2 + + constructor(private map: (value: T1) => T2) { +>map : (value: T1) => T2 +>value : T1 +>T1 : T1 +>T2 : T2 + + } +} + +class B extends A { +>B : B +>A : A + + // Ensure 'value' is of type 'number (and not '{}') by using its 'toExponential()' method. + constructor() { super(value => String(value.toExponential())); } +>super(value => String(value.toExponential())) : void +>super : typeof A +>value => String(value.toExponential()) : (value: number) => string +>value : number +>String(value.toExponential()) : string +>String : StringConstructor +>value.toExponential() : string +>value.toExponential : (fractionDigits?: number) => string +>value : number +>toExponential : (fractionDigits?: number) => string +} + diff --git a/tests/baselines/reference/superCallParameterContextualTyping2.errors.txt b/tests/baselines/reference/superCallParameterContextualTyping2.errors.txt new file mode 100644 index 0000000000000..a1e89d41efc39 --- /dev/null +++ b/tests/baselines/reference/superCallParameterContextualTyping2.errors.txt @@ -0,0 +1,17 @@ +tests/cases/conformance/expressions/contextualTyping/superCallParameterContextualTyping2.ts(10,43): error TS2349: Cannot invoke an expression whose type lacks a call signature. + + +==== tests/cases/conformance/expressions/contextualTyping/superCallParameterContextualTyping2.ts (1 errors) ==== + + class A { + constructor(private map: (value: T1) => T2) { + + } + } + + class C extends A { + // Ensure 'value' is not of type 'any' by invoking it with type arguments. + constructor() { super(value => String(value())); } + ~~~~~~~~~~~~~~~ +!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. + } \ No newline at end of file diff --git a/tests/baselines/reference/superCallParameterContextualTyping2.js b/tests/baselines/reference/superCallParameterContextualTyping2.js new file mode 100644 index 0000000000000..61e8b94f00f5c --- /dev/null +++ b/tests/baselines/reference/superCallParameterContextualTyping2.js @@ -0,0 +1,34 @@ +//// [superCallParameterContextualTyping2.ts] + +class A { + constructor(private map: (value: T1) => T2) { + + } +} + +class C extends A { + // Ensure 'value' is not of type 'any' by invoking it with type arguments. + constructor() { super(value => String(value())); } +} + +//// [superCallParameterContextualTyping2.js] +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var A = (function () { + function A(map) { + this.map = map; + } + return A; +})(); +var C = (function (_super) { + __extends(C, _super); + // Ensure 'value' is not of type 'any' by invoking it with type arguments. + function C() { + _super.call(this, function (value) { return String(value()); }); + } + return C; +})(A); diff --git a/tests/cases/conformance/expressions/contextualTyping/superCallParameterContextualTyping1.ts b/tests/cases/conformance/expressions/contextualTyping/superCallParameterContextualTyping1.ts new file mode 100644 index 0000000000000..7bcde9a695560 --- /dev/null +++ b/tests/cases/conformance/expressions/contextualTyping/superCallParameterContextualTyping1.ts @@ -0,0 +1,11 @@ + +class A { + constructor(private map: (value: T1) => T2) { + + } +} + +class B extends A { + // Ensure 'value' is of type 'number (and not '{}') by using its 'toExponential()' method. + constructor() { super(value => String(value.toExponential())); } +} diff --git a/tests/cases/conformance/expressions/contextualTyping/superCallParameterContextualTyping2.ts b/tests/cases/conformance/expressions/contextualTyping/superCallParameterContextualTyping2.ts new file mode 100644 index 0000000000000..32b4337494629 --- /dev/null +++ b/tests/cases/conformance/expressions/contextualTyping/superCallParameterContextualTyping2.ts @@ -0,0 +1,11 @@ + +class A { + constructor(private map: (value: T1) => T2) { + + } +} + +class C extends A { + // Ensure 'value' is not of type 'any' by invoking it with type arguments. + constructor() { super(value => String(value())); } +} \ No newline at end of file diff --git a/tests/cases/fourslash/quickInfoForContextuallyTypedArrowFunctionInSuperCall.ts b/tests/cases/fourslash/quickInfoForContextuallyTypedArrowFunctionInSuperCall.ts new file mode 100644 index 0000000000000..6a5e71bd4a0b4 --- /dev/null +++ b/tests/cases/fourslash/quickInfoForContextuallyTypedArrowFunctionInSuperCall.ts @@ -0,0 +1,20 @@ +/// + +////class A { +//// constructor(private map: (value: T1) => T2) { +//// +//// } +////} +//// +////class B extends A { +//// constructor() { super(va/*1*/lue => String(va/*2*/lue.toExpone/*3*/ntial())); } +////} + +goTo.marker('1'); +verify.quickInfoIs('(var) value: number'); + +goTo.marker('2'); +verify.quickInfoIs('(var) value: number'); + +goTo.marker('3'); +verify.quickInfoIs('(method) Number.toExponential(fractionDigits?: number): string'); \ No newline at end of file From 4646d6355859fa59fe52ab8801e6c686ff9f0748 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 27 Jan 2015 13:28:32 -0800 Subject: [PATCH 2/6] Fixed fourslash test. --- .../quickInfoForContextuallyTypedArrowFunctionInSuperCall.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cases/fourslash/quickInfoForContextuallyTypedArrowFunctionInSuperCall.ts b/tests/cases/fourslash/quickInfoForContextuallyTypedArrowFunctionInSuperCall.ts index 6a5e71bd4a0b4..e24a484979aa3 100644 --- a/tests/cases/fourslash/quickInfoForContextuallyTypedArrowFunctionInSuperCall.ts +++ b/tests/cases/fourslash/quickInfoForContextuallyTypedArrowFunctionInSuperCall.ts @@ -11,10 +11,10 @@ ////} goTo.marker('1'); -verify.quickInfoIs('(var) value: number'); +verify.quickInfoIs('(parameter) value: number'); goTo.marker('2'); -verify.quickInfoIs('(var) value: number'); +verify.quickInfoIs('(parameter) value: number'); goTo.marker('3'); verify.quickInfoIs('(method) Number.toExponential(fractionDigits?: number): string'); \ No newline at end of file From 8ee09dbe6ebdcd18c3208936b6226c712a0050ea Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 27 Jan 2015 13:36:10 -0800 Subject: [PATCH 3/6] Addressed Jason's pedantic correction over the wording of a comment. --- .../baselines/reference/superCallArgsMustMatch.errors.txt | 6 ++++-- tests/baselines/reference/superCallArgsMustMatch.js | 8 ++++++-- tests/cases/compiler/superCallArgsMustMatch.ts | 4 +++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/tests/baselines/reference/superCallArgsMustMatch.errors.txt b/tests/baselines/reference/superCallArgsMustMatch.errors.txt index e9a665acd1f87..06758b44fe696 100644 --- a/tests/baselines/reference/superCallArgsMustMatch.errors.txt +++ b/tests/baselines/reference/superCallArgsMustMatch.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/superCallArgsMustMatch.ts(15,15): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. +tests/cases/compiler/superCallArgsMustMatch.ts(17,15): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. ==== tests/cases/compiler/superCallArgsMustMatch.ts (1 errors) ==== @@ -16,7 +16,9 @@ tests/cases/compiler/superCallArgsMustMatch.ts(15,15): error TS2345: Argument of constructor() { - super("hi"); // Should error, base constructor has type T for first arg, which is fixed as number in the extends clause + // Should error; base constructor has type T for first arg, + // which is instantiated with 'number' in the extends clause + super("hi"); ~~~~ !!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. diff --git a/tests/baselines/reference/superCallArgsMustMatch.js b/tests/baselines/reference/superCallArgsMustMatch.js index 0b772fd39d857..e38c519ead988 100644 --- a/tests/baselines/reference/superCallArgsMustMatch.js +++ b/tests/baselines/reference/superCallArgsMustMatch.js @@ -13,7 +13,9 @@ class T6 extends T5{ constructor() { - super("hi"); // Should error, base constructor has type T for first arg, which is fixed as number in the extends clause + // Should error; base constructor has type T for first arg, + // which is instantiated with 'number' in the extends clause + super("hi"); var x: number = this.foo; @@ -39,7 +41,9 @@ var T5 = (function () { var T6 = (function (_super) { __extends(T6, _super); function T6() { - _super.call(this, "hi"); // Should error, base constructor has type T for first arg, which is fixed as number in the extends clause + // Should error; base constructor has type T for first arg, + // which is instantiated with 'number' in the extends clause + _super.call(this, "hi"); var x = this.foo; } return T6; diff --git a/tests/cases/compiler/superCallArgsMustMatch.ts b/tests/cases/compiler/superCallArgsMustMatch.ts index a27aff3919bf9..5407c3301faed 100644 --- a/tests/cases/compiler/superCallArgsMustMatch.ts +++ b/tests/cases/compiler/superCallArgsMustMatch.ts @@ -12,7 +12,9 @@ class T6 extends T5{ constructor() { - super("hi"); // Should error, base constructor has type T for first arg, which is fixed as number in the extends clause + // Should error; base constructor has type T for first arg, + // which is instantiated with 'number' in the extends clause + super("hi"); var x: number = this.foo; From 40796b2c6d64b1d3b304b33ece97bd6893437762 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 27 Jan 2015 14:42:39 -0800 Subject: [PATCH 4/6] Added more tests. --- ...IncorrectNumberOfTypeArguments1.errors.txt | 19 +++++++++++ ...eButWithIncorrectNumberOfTypeArguments1.js | 32 +++++++++++++++++ ...ericTypeButWithNoTypeArguments1.errors.txt | 19 +++++++++++ ...sFromGenericTypeButWithNoTypeArguments1.js | 32 +++++++++++++++++ ...enericTypeButWithTypeArguments1.errors.txt | 19 +++++++++++ ...ivesNonGenericTypeButWithTypeArguments1.js | 32 +++++++++++++++++ ...CallFromClassThatHasNoBaseType1.errors.txt | 16 +++++++++ .../superCallFromClassThatHasNoBaseType1.js | 25 ++++++++++++++ .../superCallFromFunction1.errors.txt | 10 ++++++ .../reference/superCallFromFunction1.js | 10 ++++++ .../reference/superNewCall1.errors.txt | 23 +++++++++++++ tests/baselines/reference/superNewCall1.js | 34 +++++++++++++++++++ ...eButWithIncorrectNumberOfTypeArguments1.ts | 10 ++++++ ...sFromGenericTypeButWithNoTypeArguments1.ts | 10 ++++++ ...ivesNonGenericTypeButWithTypeArguments1.ts | 10 ++++++ .../superCallFromClassThatHasNoBaseType1.ts | 10 ++++++ .../cases/compiler/superCallFromFunction1.ts | 4 +++ tests/cases/compiler/superNewCall1.ts | 12 +++++++ 18 files changed, 327 insertions(+) create mode 100644 tests/baselines/reference/superCallFromClassThatDerivesFromGenericTypeButWithIncorrectNumberOfTypeArguments1.errors.txt create mode 100644 tests/baselines/reference/superCallFromClassThatDerivesFromGenericTypeButWithIncorrectNumberOfTypeArguments1.js create mode 100644 tests/baselines/reference/superCallFromClassThatDerivesFromGenericTypeButWithNoTypeArguments1.errors.txt create mode 100644 tests/baselines/reference/superCallFromClassThatDerivesFromGenericTypeButWithNoTypeArguments1.js create mode 100644 tests/baselines/reference/superCallFromClassThatDerivesNonGenericTypeButWithTypeArguments1.errors.txt create mode 100644 tests/baselines/reference/superCallFromClassThatDerivesNonGenericTypeButWithTypeArguments1.js create mode 100644 tests/baselines/reference/superCallFromClassThatHasNoBaseType1.errors.txt create mode 100644 tests/baselines/reference/superCallFromClassThatHasNoBaseType1.js create mode 100644 tests/baselines/reference/superCallFromFunction1.errors.txt create mode 100644 tests/baselines/reference/superCallFromFunction1.js create mode 100644 tests/baselines/reference/superNewCall1.errors.txt create mode 100644 tests/baselines/reference/superNewCall1.js create mode 100644 tests/cases/compiler/superCallFromClassThatDerivesFromGenericTypeButWithIncorrectNumberOfTypeArguments1.ts create mode 100644 tests/cases/compiler/superCallFromClassThatDerivesFromGenericTypeButWithNoTypeArguments1.ts create mode 100644 tests/cases/compiler/superCallFromClassThatDerivesNonGenericTypeButWithTypeArguments1.ts create mode 100644 tests/cases/compiler/superCallFromClassThatHasNoBaseType1.ts create mode 100644 tests/cases/compiler/superCallFromFunction1.ts create mode 100644 tests/cases/compiler/superNewCall1.ts diff --git a/tests/baselines/reference/superCallFromClassThatDerivesFromGenericTypeButWithIncorrectNumberOfTypeArguments1.errors.txt b/tests/baselines/reference/superCallFromClassThatDerivesFromGenericTypeButWithIncorrectNumberOfTypeArguments1.errors.txt new file mode 100644 index 0000000000000..14905b224ad84 --- /dev/null +++ b/tests/baselines/reference/superCallFromClassThatDerivesFromGenericTypeButWithIncorrectNumberOfTypeArguments1.errors.txt @@ -0,0 +1,19 @@ +tests/cases/compiler/superCallFromClassThatDerivesFromGenericTypeButWithIncorrectNumberOfTypeArguments1.ts(8,17): error TS2314: Generic type 'A' requires 2 type argument(s). +tests/cases/compiler/superCallFromClassThatDerivesFromGenericTypeButWithIncorrectNumberOfTypeArguments1.ts(9,21): error TS2335: 'super' can only be referenced in a derived class. + + +==== tests/cases/compiler/superCallFromClassThatDerivesFromGenericTypeButWithIncorrectNumberOfTypeArguments1.ts (2 errors) ==== + + class A { + constructor(private map: (value: T1) => T2) { + + } + } + + class B extends A { + ~~~~~~~~~ +!!! error TS2314: Generic type 'A' requires 2 type argument(s). + constructor() { super(value => String(value)); } + ~~~~~ +!!! error TS2335: 'super' can only be referenced in a derived class. + } \ No newline at end of file diff --git a/tests/baselines/reference/superCallFromClassThatDerivesFromGenericTypeButWithIncorrectNumberOfTypeArguments1.js b/tests/baselines/reference/superCallFromClassThatDerivesFromGenericTypeButWithIncorrectNumberOfTypeArguments1.js new file mode 100644 index 0000000000000..92abed0d66dbc --- /dev/null +++ b/tests/baselines/reference/superCallFromClassThatDerivesFromGenericTypeButWithIncorrectNumberOfTypeArguments1.js @@ -0,0 +1,32 @@ +//// [superCallFromClassThatDerivesFromGenericTypeButWithIncorrectNumberOfTypeArguments1.ts] + +class A { + constructor(private map: (value: T1) => T2) { + + } +} + +class B extends A { + constructor() { super(value => String(value)); } +} + +//// [superCallFromClassThatDerivesFromGenericTypeButWithIncorrectNumberOfTypeArguments1.js] +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var A = (function () { + function A(map) { + this.map = map; + } + return A; +})(); +var B = (function (_super) { + __extends(B, _super); + function B() { + _super.call(this, function (value) { return String(value); }); + } + return B; +})(A); diff --git a/tests/baselines/reference/superCallFromClassThatDerivesFromGenericTypeButWithNoTypeArguments1.errors.txt b/tests/baselines/reference/superCallFromClassThatDerivesFromGenericTypeButWithNoTypeArguments1.errors.txt new file mode 100644 index 0000000000000..d402272df1bf9 --- /dev/null +++ b/tests/baselines/reference/superCallFromClassThatDerivesFromGenericTypeButWithNoTypeArguments1.errors.txt @@ -0,0 +1,19 @@ +tests/cases/compiler/superCallFromClassThatDerivesFromGenericTypeButWithNoTypeArguments1.ts(8,17): error TS2314: Generic type 'A' requires 2 type argument(s). +tests/cases/compiler/superCallFromClassThatDerivesFromGenericTypeButWithNoTypeArguments1.ts(9,21): error TS2335: 'super' can only be referenced in a derived class. + + +==== tests/cases/compiler/superCallFromClassThatDerivesFromGenericTypeButWithNoTypeArguments1.ts (2 errors) ==== + + class A { + constructor(private map: (value: T1) => T2) { + + } + } + + class B extends A { + ~ +!!! error TS2314: Generic type 'A' requires 2 type argument(s). + constructor() { super(value => String(value)); } + ~~~~~ +!!! error TS2335: 'super' can only be referenced in a derived class. + } \ No newline at end of file diff --git a/tests/baselines/reference/superCallFromClassThatDerivesFromGenericTypeButWithNoTypeArguments1.js b/tests/baselines/reference/superCallFromClassThatDerivesFromGenericTypeButWithNoTypeArguments1.js new file mode 100644 index 0000000000000..7e3c61e6690dd --- /dev/null +++ b/tests/baselines/reference/superCallFromClassThatDerivesFromGenericTypeButWithNoTypeArguments1.js @@ -0,0 +1,32 @@ +//// [superCallFromClassThatDerivesFromGenericTypeButWithNoTypeArguments1.ts] + +class A { + constructor(private map: (value: T1) => T2) { + + } +} + +class B extends A { + constructor() { super(value => String(value)); } +} + +//// [superCallFromClassThatDerivesFromGenericTypeButWithNoTypeArguments1.js] +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var A = (function () { + function A(map) { + this.map = map; + } + return A; +})(); +var B = (function (_super) { + __extends(B, _super); + function B() { + _super.call(this, function (value) { return String(value); }); + } + return B; +})(A); diff --git a/tests/baselines/reference/superCallFromClassThatDerivesNonGenericTypeButWithTypeArguments1.errors.txt b/tests/baselines/reference/superCallFromClassThatDerivesNonGenericTypeButWithTypeArguments1.errors.txt new file mode 100644 index 0000000000000..8bbf8b87cd310 --- /dev/null +++ b/tests/baselines/reference/superCallFromClassThatDerivesNonGenericTypeButWithTypeArguments1.errors.txt @@ -0,0 +1,19 @@ +tests/cases/compiler/superCallFromClassThatDerivesNonGenericTypeButWithTypeArguments1.ts(8,17): error TS2315: Type 'A' is not generic. +tests/cases/compiler/superCallFromClassThatDerivesNonGenericTypeButWithTypeArguments1.ts(9,21): error TS2335: 'super' can only be referenced in a derived class. + + +==== tests/cases/compiler/superCallFromClassThatDerivesNonGenericTypeButWithTypeArguments1.ts (2 errors) ==== + + class A { + constructor(private map: (value: number) => string) { + + } + } + + class B extends A { + ~~~~~~~~~~~~~~~~~ +!!! error TS2315: Type 'A' is not generic. + constructor() { super(value => String(value)); } + ~~~~~ +!!! error TS2335: 'super' can only be referenced in a derived class. + } \ No newline at end of file diff --git a/tests/baselines/reference/superCallFromClassThatDerivesNonGenericTypeButWithTypeArguments1.js b/tests/baselines/reference/superCallFromClassThatDerivesNonGenericTypeButWithTypeArguments1.js new file mode 100644 index 0000000000000..b48d5bb7f58f8 --- /dev/null +++ b/tests/baselines/reference/superCallFromClassThatDerivesNonGenericTypeButWithTypeArguments1.js @@ -0,0 +1,32 @@ +//// [superCallFromClassThatDerivesNonGenericTypeButWithTypeArguments1.ts] + +class A { + constructor(private map: (value: number) => string) { + + } +} + +class B extends A { + constructor() { super(value => String(value)); } +} + +//// [superCallFromClassThatDerivesNonGenericTypeButWithTypeArguments1.js] +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var A = (function () { + function A(map) { + this.map = map; + } + return A; +})(); +var B = (function (_super) { + __extends(B, _super); + function B() { + _super.call(this, function (value) { return String(value); }); + } + return B; +})(A); diff --git a/tests/baselines/reference/superCallFromClassThatHasNoBaseType1.errors.txt b/tests/baselines/reference/superCallFromClassThatHasNoBaseType1.errors.txt new file mode 100644 index 0000000000000..bac5abad00467 --- /dev/null +++ b/tests/baselines/reference/superCallFromClassThatHasNoBaseType1.errors.txt @@ -0,0 +1,16 @@ +tests/cases/compiler/superCallFromClassThatHasNoBaseType1.ts(9,21): error TS2335: 'super' can only be referenced in a derived class. + + +==== tests/cases/compiler/superCallFromClassThatHasNoBaseType1.ts (1 errors) ==== + + class A { + constructor(private map: (value: number) => string) { + + } + } + + class B { + constructor() { super(value => String(value)); } + ~~~~~ +!!! error TS2335: 'super' can only be referenced in a derived class. + } \ No newline at end of file diff --git a/tests/baselines/reference/superCallFromClassThatHasNoBaseType1.js b/tests/baselines/reference/superCallFromClassThatHasNoBaseType1.js new file mode 100644 index 0000000000000..7818aed7ff855 --- /dev/null +++ b/tests/baselines/reference/superCallFromClassThatHasNoBaseType1.js @@ -0,0 +1,25 @@ +//// [superCallFromClassThatHasNoBaseType1.ts] + +class A { + constructor(private map: (value: number) => string) { + + } +} + +class B { + constructor() { super(value => String(value)); } +} + +//// [superCallFromClassThatHasNoBaseType1.js] +var A = (function () { + function A(map) { + this.map = map; + } + return A; +})(); +var B = (function () { + function B() { + _super.call(this, function (value) { return String(value); }); + } + return B; +})(); diff --git a/tests/baselines/reference/superCallFromFunction1.errors.txt b/tests/baselines/reference/superCallFromFunction1.errors.txt new file mode 100644 index 0000000000000..374a3aeb16cb4 --- /dev/null +++ b/tests/baselines/reference/superCallFromFunction1.errors.txt @@ -0,0 +1,10 @@ +tests/cases/compiler/superCallFromFunction1.ts(3,5): error TS2335: 'super' can only be referenced in a derived class. + + +==== tests/cases/compiler/superCallFromFunction1.ts (1 errors) ==== + + function foo() { + super(value => String(value)); + ~~~~~ +!!! error TS2335: 'super' can only be referenced in a derived class. + } \ No newline at end of file diff --git a/tests/baselines/reference/superCallFromFunction1.js b/tests/baselines/reference/superCallFromFunction1.js new file mode 100644 index 0000000000000..a7fcbaaeff0d5 --- /dev/null +++ b/tests/baselines/reference/superCallFromFunction1.js @@ -0,0 +1,10 @@ +//// [superCallFromFunction1.ts] + +function foo() { + super(value => String(value)); +} + +//// [superCallFromFunction1.js] +function foo() { + _super.call(this, function (value) { return String(value); }); +} diff --git a/tests/baselines/reference/superNewCall1.errors.txt b/tests/baselines/reference/superNewCall1.errors.txt new file mode 100644 index 0000000000000..2b104e7d647d3 --- /dev/null +++ b/tests/baselines/reference/superNewCall1.errors.txt @@ -0,0 +1,23 @@ +tests/cases/compiler/superNewCall1.ts(9,5): error TS2377: Constructors for derived classes must contain a 'super' call. +tests/cases/compiler/superNewCall1.ts(10,9): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature. + + +==== tests/cases/compiler/superNewCall1.ts (2 errors) ==== + + class A { + constructor(private map: (value: T1) => T2) { + + } + } + + class B extends A { + constructor() { + ~~~~~~~~~~~~~~~ + new super(value => String(value)); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature. + } + ~~~~~ +!!! error TS2377: Constructors for derived classes must contain a 'super' call. + } \ No newline at end of file diff --git a/tests/baselines/reference/superNewCall1.js b/tests/baselines/reference/superNewCall1.js new file mode 100644 index 0000000000000..d9b74ac508017 --- /dev/null +++ b/tests/baselines/reference/superNewCall1.js @@ -0,0 +1,34 @@ +//// [superNewCall1.ts] + +class A { + constructor(private map: (value: T1) => T2) { + + } +} + +class B extends A { + constructor() { + new super(value => String(value)); + } +} + +//// [superNewCall1.js] +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var A = (function () { + function A(map) { + this.map = map; + } + return A; +})(); +var B = (function (_super) { + __extends(B, _super); + function B() { + new _super.prototype(function (value) { return String(value); }); + } + return B; +})(A); diff --git a/tests/cases/compiler/superCallFromClassThatDerivesFromGenericTypeButWithIncorrectNumberOfTypeArguments1.ts b/tests/cases/compiler/superCallFromClassThatDerivesFromGenericTypeButWithIncorrectNumberOfTypeArguments1.ts new file mode 100644 index 0000000000000..d633ccb018fc7 --- /dev/null +++ b/tests/cases/compiler/superCallFromClassThatDerivesFromGenericTypeButWithIncorrectNumberOfTypeArguments1.ts @@ -0,0 +1,10 @@ + +class A { + constructor(private map: (value: T1) => T2) { + + } +} + +class B extends A { + constructor() { super(value => String(value)); } +} \ No newline at end of file diff --git a/tests/cases/compiler/superCallFromClassThatDerivesFromGenericTypeButWithNoTypeArguments1.ts b/tests/cases/compiler/superCallFromClassThatDerivesFromGenericTypeButWithNoTypeArguments1.ts new file mode 100644 index 0000000000000..c09fb37db2d09 --- /dev/null +++ b/tests/cases/compiler/superCallFromClassThatDerivesFromGenericTypeButWithNoTypeArguments1.ts @@ -0,0 +1,10 @@ + +class A { + constructor(private map: (value: T1) => T2) { + + } +} + +class B extends A { + constructor() { super(value => String(value)); } +} \ No newline at end of file diff --git a/tests/cases/compiler/superCallFromClassThatDerivesNonGenericTypeButWithTypeArguments1.ts b/tests/cases/compiler/superCallFromClassThatDerivesNonGenericTypeButWithTypeArguments1.ts new file mode 100644 index 0000000000000..99755d87fbf23 --- /dev/null +++ b/tests/cases/compiler/superCallFromClassThatDerivesNonGenericTypeButWithTypeArguments1.ts @@ -0,0 +1,10 @@ + +class A { + constructor(private map: (value: number) => string) { + + } +} + +class B extends A { + constructor() { super(value => String(value)); } +} \ No newline at end of file diff --git a/tests/cases/compiler/superCallFromClassThatHasNoBaseType1.ts b/tests/cases/compiler/superCallFromClassThatHasNoBaseType1.ts new file mode 100644 index 0000000000000..5f030bd5562bd --- /dev/null +++ b/tests/cases/compiler/superCallFromClassThatHasNoBaseType1.ts @@ -0,0 +1,10 @@ + +class A { + constructor(private map: (value: number) => string) { + + } +} + +class B { + constructor() { super(value => String(value)); } +} \ No newline at end of file diff --git a/tests/cases/compiler/superCallFromFunction1.ts b/tests/cases/compiler/superCallFromFunction1.ts new file mode 100644 index 0000000000000..81874204e1af8 --- /dev/null +++ b/tests/cases/compiler/superCallFromFunction1.ts @@ -0,0 +1,4 @@ + +function foo() { + super(value => String(value)); +} \ No newline at end of file diff --git a/tests/cases/compiler/superNewCall1.ts b/tests/cases/compiler/superNewCall1.ts new file mode 100644 index 0000000000000..b3792d55221dd --- /dev/null +++ b/tests/cases/compiler/superNewCall1.ts @@ -0,0 +1,12 @@ + +class A { + constructor(private map: (value: T1) => T2) { + + } +} + +class B extends A { + constructor() { + new super(value => String(value)); + } +} \ No newline at end of file From 9d8319dc79b206eb62bcbd98138dd41dbd67854e Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 27 Jan 2015 14:55:42 -0800 Subject: [PATCH 5/6] Perform checking, document function. --- src/compiler/checker.ts | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6887421ba326d..8eb834c63a47c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5978,16 +5978,21 @@ module ts { return args; } - // In a 'super' call, type arguments are not provided within the CallExpression node itself. - // Instead, they must be fetched from the class declaration's base type node. + /** + * In a 'super' call, type arguments are not provided within the CallExpression node itself. + * Instead, they must be fetched from the class declaration's base type node. + * + * If 'node' is a 'super' call (e.g. super(...), new super(...)), then we attempt to fetch + * the type arguments off the containing class's first heritage clause (if one exists). Note that if + * type arguments are supplied on the 'super' call, they are ignored (though this is syntactically incorrect). + * + * In all other cases, the call's explicit type arguments are returned. + */ function getEffectiveTypeArguments(callExpression: CallExpression): TypeNode[] { if (callExpression.expression.kind === SyntaxKind.SuperKeyword) { - // TODO (drosen): 1) Discuss if checking needs to be done at this point. - // 2) Have a test where type arguments are not provided on the base class. - // 3) Have a test where the base class is not generic. var containingClass = getAncestor(callExpression, SyntaxKind.ClassDeclaration); - var baseClassTypeNode = getClassBaseTypeNode(containingClass); - return baseClassTypeNode.typeArguments; + var baseClassTypeNode = containingClass && getClassBaseTypeNode(containingClass); + return baseClassTypeNode && baseClassTypeNode.typeArguments; } else { // Ordinary case - simple function invocation. From 0ffa722e23a14f281debebd8d0612dfc66909ddd Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 27 Jan 2015 14:57:38 -0800 Subject: [PATCH 6/6] Removed superfluous type assertion. --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8eb834c63a47c..732acf1843b0b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5996,7 +5996,7 @@ module ts { } else { // Ordinary case - simple function invocation. - return (callExpression).typeArguments; + return callExpression.typeArguments; } }