From fa6773e685e2c1f19d6e35cb12f06edfa9c31ad5 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 18 Aug 2017 11:00:46 +0200 Subject: [PATCH 1/4] Type parameters from class should not be in scope in base class expression --- src/compiler/checker.ts | 12 +++++++++++- src/compiler/diagnosticMessages.json | 4 ++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1c41be84ba741..d5518eee3da49 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1016,7 +1016,17 @@ namespace ts { } } break; - + case SyntaxKind.ExpressionWithTypeArguments: + if (lastLocation === (location).expression && (location.parent).token === SyntaxKind.ExtendsKeyword) { + const container = location.parent.parent; + if (isClassLike(container) && (result = lookup(getSymbolOfNode(container).members, name, meaning & SymbolFlags.Type))) { + if (nameNotFoundMessage) { + error(errorLocation, Diagnostics.Base_class_expressions_cannot_reference_class_type_parameters); + } + return undefined; + } + } + break; // It is not legal to reference a class's own type parameters from a computed property name that // belongs to the class. For example: // diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 77e7f7e7b6246..049483fdb8f3f 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1912,6 +1912,10 @@ "category": "Error", "code": 2560 }, + "Base class expressions cannot reference class type parameters.": { + "category": "Error", + "code": 2561 + }, "JSX element attributes type '{0}' may not be a union type.": { "category": "Error", "code": 2600 From 35addce79ede5c2f439623401a0fcc2d58943215 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 19 Aug 2017 09:46:02 +0200 Subject: [PATCH 2/4] Add comment --- src/compiler/checker.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d5518eee3da49..3c1ed9a94921e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1017,6 +1017,7 @@ namespace ts { } break; case SyntaxKind.ExpressionWithTypeArguments: + // The type parameters of a class are not in scope in the base class expression. if (lastLocation === (location).expression && (location.parent).token === SyntaxKind.ExtendsKeyword) { const container = location.parent.parent; if (isClassLike(container) && (result = lookup(getSymbolOfNode(container).members, name, meaning & SymbolFlags.Type))) { From 049b33693633b5dc5970db230b28fff492efcce0 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 19 Aug 2017 09:46:09 +0200 Subject: [PATCH 3/4] Accept new baselines --- .../reference/inheritFromGenericTypeParameter.errors.txt | 4 ++-- .../reference/typeParameterAsBaseClass.errors.txt | 4 ++-- .../reference/typeParameterAsBaseType.errors.txt | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/baselines/reference/inheritFromGenericTypeParameter.errors.txt b/tests/baselines/reference/inheritFromGenericTypeParameter.errors.txt index 08d138f2e5ddc..c043e37575c9a 100644 --- a/tests/baselines/reference/inheritFromGenericTypeParameter.errors.txt +++ b/tests/baselines/reference/inheritFromGenericTypeParameter.errors.txt @@ -1,11 +1,11 @@ -tests/cases/compiler/inheritFromGenericTypeParameter.ts(1,20): error TS2693: 'T' only refers to a type, but is being used as a value here. +tests/cases/compiler/inheritFromGenericTypeParameter.ts(1,20): error TS2304: Cannot find name 'T'. tests/cases/compiler/inheritFromGenericTypeParameter.ts(2,24): error TS2312: An interface may only extend a class or another interface. ==== tests/cases/compiler/inheritFromGenericTypeParameter.ts (2 errors) ==== class C extends T { } ~ -!!! error TS2693: 'T' only refers to a type, but is being used as a value here. +!!! error TS2304: Cannot find name 'T'. interface I extends T { } ~ !!! error TS2312: An interface may only extend a class or another interface. \ No newline at end of file diff --git a/tests/baselines/reference/typeParameterAsBaseClass.errors.txt b/tests/baselines/reference/typeParameterAsBaseClass.errors.txt index e633a6dd39669..dec7f7f2a4a24 100644 --- a/tests/baselines/reference/typeParameterAsBaseClass.errors.txt +++ b/tests/baselines/reference/typeParameterAsBaseClass.errors.txt @@ -1,11 +1,11 @@ -tests/cases/compiler/typeParameterAsBaseClass.ts(1,20): error TS2693: 'T' only refers to a type, but is being used as a value here. +tests/cases/compiler/typeParameterAsBaseClass.ts(1,20): error TS2304: Cannot find name 'T'. tests/cases/compiler/typeParameterAsBaseClass.ts(2,24): error TS2422: A class may only implement another class or interface. ==== tests/cases/compiler/typeParameterAsBaseClass.ts (2 errors) ==== class C extends T {} ~ -!!! error TS2693: 'T' only refers to a type, but is being used as a value here. +!!! error TS2304: Cannot find name 'T'. class C2 implements T {} ~ !!! error TS2422: A class may only implement another class or interface. \ No newline at end of file diff --git a/tests/baselines/reference/typeParameterAsBaseType.errors.txt b/tests/baselines/reference/typeParameterAsBaseType.errors.txt index c16b16d0b1a45..835b236994867 100644 --- a/tests/baselines/reference/typeParameterAsBaseType.errors.txt +++ b/tests/baselines/reference/typeParameterAsBaseType.errors.txt @@ -1,5 +1,5 @@ -tests/cases/conformance/types/typeParameters/typeParameterAsBaseType.ts(4,20): error TS2693: 'T' only refers to a type, but is being used as a value here. -tests/cases/conformance/types/typeParameters/typeParameterAsBaseType.ts(5,24): error TS2693: 'U' only refers to a type, but is being used as a value here. +tests/cases/conformance/types/typeParameters/typeParameterAsBaseType.ts(4,20): error TS2304: Cannot find name 'T'. +tests/cases/conformance/types/typeParameters/typeParameterAsBaseType.ts(5,24): error TS2304: Cannot find name 'U'. tests/cases/conformance/types/typeParameters/typeParameterAsBaseType.ts(7,24): error TS2312: An interface may only extend a class or another interface. tests/cases/conformance/types/typeParameters/typeParameterAsBaseType.ts(8,28): error TS2312: An interface may only extend a class or another interface. @@ -10,10 +10,10 @@ tests/cases/conformance/types/typeParameters/typeParameterAsBaseType.ts(8,28): e class C extends T { } ~ -!!! error TS2693: 'T' only refers to a type, but is being used as a value here. +!!! error TS2304: Cannot find name 'T'. class C2 extends U { } ~ -!!! error TS2693: 'U' only refers to a type, but is being used as a value here. +!!! error TS2304: Cannot find name 'U'. interface I extends T { } ~ From 914d428ff12a7c7c8a7c2fc778a83810b852bd5f Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 19 Aug 2017 09:53:46 +0200 Subject: [PATCH 4/4] Add regression test --- .../baseExpressionTypeParameters.errors.txt | 19 +++++++ .../reference/baseExpressionTypeParameters.js | 50 +++++++++++++++++++ .../compiler/baseExpressionTypeParameters.ts | 13 +++++ 3 files changed, 82 insertions(+) create mode 100644 tests/baselines/reference/baseExpressionTypeParameters.errors.txt create mode 100644 tests/baselines/reference/baseExpressionTypeParameters.js create mode 100644 tests/cases/compiler/baseExpressionTypeParameters.ts diff --git a/tests/baselines/reference/baseExpressionTypeParameters.errors.txt b/tests/baselines/reference/baseExpressionTypeParameters.errors.txt new file mode 100644 index 0000000000000..4fa8f2f6d3dbb --- /dev/null +++ b/tests/baselines/reference/baseExpressionTypeParameters.errors.txt @@ -0,0 +1,19 @@ +tests/cases/compiler/baseExpressionTypeParameters.ts(10,27): error TS2561: Base class expressions cannot reference class type parameters. + + +==== tests/cases/compiler/baseExpressionTypeParameters.ts (1 errors) ==== + // Repro from #17829 + + function base() { + class Base { + static prop: T; + } + return Base; + } + + class Gen extends base() {} // Error, T not in scope + ~ +!!! error TS2561: Base class expressions cannot reference class type parameters. + class Spec extends Gen {} + + Spec.prop; \ No newline at end of file diff --git a/tests/baselines/reference/baseExpressionTypeParameters.js b/tests/baselines/reference/baseExpressionTypeParameters.js new file mode 100644 index 0000000000000..a3a77cbc6e347 --- /dev/null +++ b/tests/baselines/reference/baseExpressionTypeParameters.js @@ -0,0 +1,50 @@ +//// [baseExpressionTypeParameters.ts] +// Repro from #17829 + +function base() { + class Base { + static prop: T; + } + return Base; +} + +class Gen extends base() {} // Error, T not in scope +class Spec extends Gen {} + +Spec.prop; + +//// [baseExpressionTypeParameters.js] +// Repro from #17829 +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 __()); + }; +})(); +function base() { + var Base = /** @class */ (function () { + function Base() { + } + return Base; + }()); + return Base; +} +var Gen = /** @class */ (function (_super) { + __extends(Gen, _super); + function Gen() { + return _super !== null && _super.apply(this, arguments) || this; + } + return Gen; +}(base())); // Error, T not in scope +var Spec = /** @class */ (function (_super) { + __extends(Spec, _super); + function Spec() { + return _super !== null && _super.apply(this, arguments) || this; + } + return Spec; +}(Gen)); +Spec.prop; diff --git a/tests/cases/compiler/baseExpressionTypeParameters.ts b/tests/cases/compiler/baseExpressionTypeParameters.ts new file mode 100644 index 0000000000000..ca864f9a7f00f --- /dev/null +++ b/tests/cases/compiler/baseExpressionTypeParameters.ts @@ -0,0 +1,13 @@ +// Repro from #17829 + +function base() { + class Base { + static prop: T; + } + return Base; +} + +class Gen extends base() {} // Error, T not in scope +class Spec extends Gen {} + +Spec.prop; \ No newline at end of file