From 58ed72fd9a4750defbcd65fa45e55e8fdd20b3ed Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Tue, 4 Oct 2016 06:06:28 -0700 Subject: [PATCH] Fixes #10624 --- src/compiler/checker.ts | 4 ++- .../classDeclaredBeforeClassFactory.js | 30 +++++++++++++++++ .../classDeclaredBeforeClassFactory.symbols | 13 ++++++++ .../classDeclaredBeforeClassFactory.types | 15 +++++++++ .../reference/classExpression3.errors.txt | 15 --------- .../reference/classExpression3.symbols | 26 +++++++++++++++ .../reference/classExpression3.types | 33 +++++++++++++++++++ .../reference/classExpressionES63.errors.txt | 15 --------- .../reference/classExpressionES63.symbols | 26 +++++++++++++++ .../reference/classExpressionES63.types | 33 +++++++++++++++++++ ...singPropertiesOfClassExpression.errors.txt | 5 +-- .../classDeclaredBeforeClassFactory.ts | 6 ++++ 12 files changed, 186 insertions(+), 35 deletions(-) create mode 100644 tests/baselines/reference/classDeclaredBeforeClassFactory.js create mode 100644 tests/baselines/reference/classDeclaredBeforeClassFactory.symbols create mode 100644 tests/baselines/reference/classDeclaredBeforeClassFactory.types delete mode 100644 tests/baselines/reference/classExpression3.errors.txt create mode 100644 tests/baselines/reference/classExpression3.symbols create mode 100644 tests/baselines/reference/classExpression3.types delete mode 100644 tests/baselines/reference/classExpressionES63.errors.txt create mode 100644 tests/baselines/reference/classExpressionES63.symbols create mode 100644 tests/baselines/reference/classExpressionES63.types create mode 100644 tests/cases/compiler/classDeclaredBeforeClassFactory.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f24f72491b0..3c7ff7112e0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17114,7 +17114,9 @@ namespace ts { checkTypeAssignableTo(staticType, getTypeWithoutSignatures(staticBaseType), node.name || node, Diagnostics.Class_static_side_0_incorrectly_extends_base_class_static_side_1); - if (baseType.symbol.valueDeclaration && !isInAmbientContext(baseType.symbol.valueDeclaration)) { + if (baseType.symbol.valueDeclaration && + !isInAmbientContext(baseType.symbol.valueDeclaration) && + baseType.symbol.valueDeclaration.kind === SyntaxKind.ClassDeclaration) { if (!isBlockScopedNameDeclaredBeforeUse(baseType.symbol.valueDeclaration, node)) { error(baseTypeNode, Diagnostics.A_class_must_be_declared_after_its_base_class); } diff --git a/tests/baselines/reference/classDeclaredBeforeClassFactory.js b/tests/baselines/reference/classDeclaredBeforeClassFactory.js new file mode 100644 index 00000000000..3dd1e7a4aaf --- /dev/null +++ b/tests/baselines/reference/classDeclaredBeforeClassFactory.js @@ -0,0 +1,30 @@ +//// [classDeclaredBeforeClassFactory.ts] +// Should be OK due to hoisting +class Derived extends makeBaseClass() {} + +function makeBaseClass() { + return class Base {}; +} + + +//// [classDeclaredBeforeClassFactory.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +// Should be OK due to hoisting +var Derived = (function (_super) { + __extends(Derived, _super); + function Derived() { + return _super.apply(this, arguments) || this; + } + return Derived; +}(makeBaseClass())); +function makeBaseClass() { + return (function () { + function Base() { + } + return Base; + }()); +} diff --git a/tests/baselines/reference/classDeclaredBeforeClassFactory.symbols b/tests/baselines/reference/classDeclaredBeforeClassFactory.symbols new file mode 100644 index 00000000000..cf23402c3b4 --- /dev/null +++ b/tests/baselines/reference/classDeclaredBeforeClassFactory.symbols @@ -0,0 +1,13 @@ +=== tests/cases/compiler/classDeclaredBeforeClassFactory.ts === +// Should be OK due to hoisting +class Derived extends makeBaseClass() {} +>Derived : Symbol(Derived, Decl(classDeclaredBeforeClassFactory.ts, 0, 0)) +>makeBaseClass : Symbol(makeBaseClass, Decl(classDeclaredBeforeClassFactory.ts, 1, 40)) + +function makeBaseClass() { +>makeBaseClass : Symbol(makeBaseClass, Decl(classDeclaredBeforeClassFactory.ts, 1, 40)) + + return class Base {}; +>Base : Symbol(Base, Decl(classDeclaredBeforeClassFactory.ts, 4, 10)) +} + diff --git a/tests/baselines/reference/classDeclaredBeforeClassFactory.types b/tests/baselines/reference/classDeclaredBeforeClassFactory.types new file mode 100644 index 00000000000..0fc2437381f --- /dev/null +++ b/tests/baselines/reference/classDeclaredBeforeClassFactory.types @@ -0,0 +1,15 @@ +=== tests/cases/compiler/classDeclaredBeforeClassFactory.ts === +// Should be OK due to hoisting +class Derived extends makeBaseClass() {} +>Derived : Derived +>makeBaseClass() : Base +>makeBaseClass : () => typeof Base + +function makeBaseClass() { +>makeBaseClass : () => typeof Base + + return class Base {}; +>class Base {} : typeof Base +>Base : typeof Base +} + diff --git a/tests/baselines/reference/classExpression3.errors.txt b/tests/baselines/reference/classExpression3.errors.txt deleted file mode 100644 index 2a7a2e160f1..00000000000 --- a/tests/baselines/reference/classExpression3.errors.txt +++ /dev/null @@ -1,15 +0,0 @@ -tests/cases/conformance/classes/classExpressions/classExpression3.ts(1,23): error TS2690: A class must be declared after its base class. -tests/cases/conformance/classes/classExpressions/classExpression3.ts(1,37): error TS2690: A class must be declared after its base class. - - -==== tests/cases/conformance/classes/classExpressions/classExpression3.ts (2 errors) ==== - let C = class extends class extends class { a = 1 } { b = 2 } { c = 3 }; - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2690: A class must be declared after its base class. - ~~~~~~~~~~~~~~~ -!!! error TS2690: A class must be declared after its base class. - let c = new C(); - c.a; - c.b; - c.c; - \ No newline at end of file diff --git a/tests/baselines/reference/classExpression3.symbols b/tests/baselines/reference/classExpression3.symbols new file mode 100644 index 00000000000..bc1b263a000 --- /dev/null +++ b/tests/baselines/reference/classExpression3.symbols @@ -0,0 +1,26 @@ +=== tests/cases/conformance/classes/classExpressions/classExpression3.ts === +let C = class extends class extends class { a = 1 } { b = 2 } { c = 3 }; +>C : Symbol(C, Decl(classExpression3.ts, 0, 3)) +>a : Symbol((Anonymous class).a, Decl(classExpression3.ts, 0, 43)) +>b : Symbol((Anonymous class).b, Decl(classExpression3.ts, 0, 53)) +>c : Symbol((Anonymous class).c, Decl(classExpression3.ts, 0, 63)) + +let c = new C(); +>c : Symbol(c, Decl(classExpression3.ts, 1, 3)) +>C : Symbol(C, Decl(classExpression3.ts, 0, 3)) + +c.a; +>c.a : Symbol((Anonymous class).a, Decl(classExpression3.ts, 0, 43)) +>c : Symbol(c, Decl(classExpression3.ts, 1, 3)) +>a : Symbol((Anonymous class).a, Decl(classExpression3.ts, 0, 43)) + +c.b; +>c.b : Symbol((Anonymous class).b, Decl(classExpression3.ts, 0, 53)) +>c : Symbol(c, Decl(classExpression3.ts, 1, 3)) +>b : Symbol((Anonymous class).b, Decl(classExpression3.ts, 0, 53)) + +c.c; +>c.c : Symbol((Anonymous class).c, Decl(classExpression3.ts, 0, 63)) +>c : Symbol(c, Decl(classExpression3.ts, 1, 3)) +>c : Symbol((Anonymous class).c, Decl(classExpression3.ts, 0, 63)) + diff --git a/tests/baselines/reference/classExpression3.types b/tests/baselines/reference/classExpression3.types new file mode 100644 index 00000000000..51798f300d4 --- /dev/null +++ b/tests/baselines/reference/classExpression3.types @@ -0,0 +1,33 @@ +=== tests/cases/conformance/classes/classExpressions/classExpression3.ts === +let C = class extends class extends class { a = 1 } { b = 2 } { c = 3 }; +>C : typeof (Anonymous class) +>class extends class extends class { a = 1 } { b = 2 } { c = 3 } : typeof (Anonymous class) +>class extends class { a = 1 } { b = 2 } : (Anonymous class) +>class { a = 1 } : (Anonymous class) +>a : number +>1 : 1 +>b : number +>2 : 2 +>c : number +>3 : 3 + +let c = new C(); +>c : (Anonymous class) +>new C() : (Anonymous class) +>C : typeof (Anonymous class) + +c.a; +>c.a : number +>c : (Anonymous class) +>a : number + +c.b; +>c.b : number +>c : (Anonymous class) +>b : number + +c.c; +>c.c : number +>c : (Anonymous class) +>c : number + diff --git a/tests/baselines/reference/classExpressionES63.errors.txt b/tests/baselines/reference/classExpressionES63.errors.txt deleted file mode 100644 index 9463162e4a6..00000000000 --- a/tests/baselines/reference/classExpressionES63.errors.txt +++ /dev/null @@ -1,15 +0,0 @@ -tests/cases/conformance/es6/classExpressions/classExpressionES63.ts(1,23): error TS2690: A class must be declared after its base class. -tests/cases/conformance/es6/classExpressions/classExpressionES63.ts(1,37): error TS2690: A class must be declared after its base class. - - -==== tests/cases/conformance/es6/classExpressions/classExpressionES63.ts (2 errors) ==== - let C = class extends class extends class { a = 1 } { b = 2 } { c = 3 }; - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2690: A class must be declared after its base class. - ~~~~~~~~~~~~~~~ -!!! error TS2690: A class must be declared after its base class. - let c = new C(); - c.a; - c.b; - c.c; - \ No newline at end of file diff --git a/tests/baselines/reference/classExpressionES63.symbols b/tests/baselines/reference/classExpressionES63.symbols new file mode 100644 index 00000000000..4e52d5ee9dd --- /dev/null +++ b/tests/baselines/reference/classExpressionES63.symbols @@ -0,0 +1,26 @@ +=== tests/cases/conformance/es6/classExpressions/classExpressionES63.ts === +let C = class extends class extends class { a = 1 } { b = 2 } { c = 3 }; +>C : Symbol(C, Decl(classExpressionES63.ts, 0, 3)) +>a : Symbol((Anonymous class).a, Decl(classExpressionES63.ts, 0, 43)) +>b : Symbol((Anonymous class).b, Decl(classExpressionES63.ts, 0, 53)) +>c : Symbol((Anonymous class).c, Decl(classExpressionES63.ts, 0, 63)) + +let c = new C(); +>c : Symbol(c, Decl(classExpressionES63.ts, 1, 3)) +>C : Symbol(C, Decl(classExpressionES63.ts, 0, 3)) + +c.a; +>c.a : Symbol((Anonymous class).a, Decl(classExpressionES63.ts, 0, 43)) +>c : Symbol(c, Decl(classExpressionES63.ts, 1, 3)) +>a : Symbol((Anonymous class).a, Decl(classExpressionES63.ts, 0, 43)) + +c.b; +>c.b : Symbol((Anonymous class).b, Decl(classExpressionES63.ts, 0, 53)) +>c : Symbol(c, Decl(classExpressionES63.ts, 1, 3)) +>b : Symbol((Anonymous class).b, Decl(classExpressionES63.ts, 0, 53)) + +c.c; +>c.c : Symbol((Anonymous class).c, Decl(classExpressionES63.ts, 0, 63)) +>c : Symbol(c, Decl(classExpressionES63.ts, 1, 3)) +>c : Symbol((Anonymous class).c, Decl(classExpressionES63.ts, 0, 63)) + diff --git a/tests/baselines/reference/classExpressionES63.types b/tests/baselines/reference/classExpressionES63.types new file mode 100644 index 00000000000..c5c8de91c17 --- /dev/null +++ b/tests/baselines/reference/classExpressionES63.types @@ -0,0 +1,33 @@ +=== tests/cases/conformance/es6/classExpressions/classExpressionES63.ts === +let C = class extends class extends class { a = 1 } { b = 2 } { c = 3 }; +>C : typeof (Anonymous class) +>class extends class extends class { a = 1 } { b = 2 } { c = 3 } : typeof (Anonymous class) +>class extends class { a = 1 } { b = 2 } : (Anonymous class) +>class { a = 1 } : (Anonymous class) +>a : number +>1 : 1 +>b : number +>2 : 2 +>c : number +>3 : 3 + +let c = new C(); +>c : (Anonymous class) +>new C() : (Anonymous class) +>C : typeof (Anonymous class) + +c.a; +>c.a : number +>c : (Anonymous class) +>a : number + +c.b; +>c.b : number +>c : (Anonymous class) +>b : number + +c.c; +>c.c : number +>c : (Anonymous class) +>c : number + diff --git a/tests/baselines/reference/missingPropertiesOfClassExpression.errors.txt b/tests/baselines/reference/missingPropertiesOfClassExpression.errors.txt index 23e67d7cf0b..b7331a68271 100644 --- a/tests/baselines/reference/missingPropertiesOfClassExpression.errors.txt +++ b/tests/baselines/reference/missingPropertiesOfClassExpression.errors.txt @@ -1,11 +1,8 @@ -tests/cases/compiler/missingPropertiesOfClassExpression.ts(1,22): error TS2690: A class must be declared after its base class. tests/cases/compiler/missingPropertiesOfClassExpression.ts(1,52): error TS2339: Property 'y' does not exist on type '(Anonymous class)'. -==== tests/cases/compiler/missingPropertiesOfClassExpression.ts (2 errors) ==== +==== tests/cases/compiler/missingPropertiesOfClassExpression.ts (1 errors) ==== class George extends class { reset() { return this.y; } } { - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2690: A class must be declared after its base class. ~ !!! error TS2339: Property 'y' does not exist on type '(Anonymous class)'. constructor() { diff --git a/tests/cases/compiler/classDeclaredBeforeClassFactory.ts b/tests/cases/compiler/classDeclaredBeforeClassFactory.ts new file mode 100644 index 00000000000..27191ce7fd2 --- /dev/null +++ b/tests/cases/compiler/classDeclaredBeforeClassFactory.ts @@ -0,0 +1,6 @@ +// Should be OK due to hoisting +class Derived extends makeBaseClass() {} + +function makeBaseClass() { + return class Base {}; +}