diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 041ea6dbfd6..976bd6d64e9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16244,6 +16244,15 @@ namespace ts { getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags); } + function writeBaseConstructorTypeOfClass(node: ClassLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter) { + const classType = getDeclaredTypeOfSymbol(getSymbolOfNode(node)); + resolveBaseTypesOfClass(classType); + const baseType = classType.resolvedBaseTypes[0]; + if (baseType) { + getSymbolDisplayBuilder().buildTypeDisplay(baseType, writer, enclosingDeclaration, flags); + } + } + function hasGlobalName(name: string): boolean { return hasProperty(globals, name); } @@ -16276,6 +16285,7 @@ namespace ts { writeTypeOfDeclaration, writeReturnTypeOfSignatureDeclaration, writeTypeOfExpression, + writeBaseConstructorTypeOfClass, isSymbolAccessible, isEntityNameVisible, getConstantValue, diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 0b5ffca4b53..c758d658888 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -987,6 +987,10 @@ namespace ts { else if (!isImplementsList && node.expression.kind === SyntaxKind.NullKeyword) { write("null"); } + else { + writer.getSymbolAccessibilityDiagnostic = getHeritageClauseVisibilityError; + resolver.writeBaseConstructorTypeOfClass(enclosingDeclaration, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer); + } function getHeritageClauseVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic { let diagnosticMessage: DiagnosticMessage; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 2d53d5addad..0b0a1cbe61c 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1889,6 +1889,7 @@ namespace ts { writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; writeTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; + writeBaseConstructorTypeOfClass(node: ClassLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessibilityResult; isEntityNameVisible(entityName: EntityName | Expression, enclosingDeclaration: Node): SymbolVisibilityResult; // Returns the constant value this property access resolves to, or 'undefined' for a non-constant diff --git a/tests/baselines/reference/declarationEmit_expressionInExtends2.js b/tests/baselines/reference/declarationEmit_expressionInExtends2.js new file mode 100644 index 00000000000..da0478e26d0 --- /dev/null +++ b/tests/baselines/reference/declarationEmit_expressionInExtends2.js @@ -0,0 +1,45 @@ +//// [declarationEmit_expressionInExtends2.ts] + +class C { + x: T; + y: U; +} + +function getClass(c: T) { + return C; +} + +class MyClass extends getClass(2) { +} + +//// [declarationEmit_expressionInExtends2.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 __()); +}; +var C = (function () { + function C() { + } + return C; +}()); +function getClass(c) { + return C; +} +var MyClass = (function (_super) { + __extends(MyClass, _super); + function MyClass() { + _super.apply(this, arguments); + } + return MyClass; +}(getClass(2))); + + +//// [declarationEmit_expressionInExtends2.d.ts] +declare class C { + x: T; + y: U; +} +declare function getClass(c: T): typeof C; +declare class MyClass extends C { +} diff --git a/tests/baselines/reference/declarationEmit_expressionInExtends2.symbols b/tests/baselines/reference/declarationEmit_expressionInExtends2.symbols new file mode 100644 index 00000000000..8cd166852ac --- /dev/null +++ b/tests/baselines/reference/declarationEmit_expressionInExtends2.symbols @@ -0,0 +1,30 @@ +=== tests/cases/compiler/declarationEmit_expressionInExtends2.ts === + +class C { +>C : Symbol(C, Decl(declarationEmit_expressionInExtends2.ts, 0, 0)) +>T : Symbol(T, Decl(declarationEmit_expressionInExtends2.ts, 1, 8)) +>U : Symbol(U, Decl(declarationEmit_expressionInExtends2.ts, 1, 10)) + + x: T; +>x : Symbol(x, Decl(declarationEmit_expressionInExtends2.ts, 1, 15)) +>T : Symbol(T, Decl(declarationEmit_expressionInExtends2.ts, 1, 8)) + + y: U; +>y : Symbol(y, Decl(declarationEmit_expressionInExtends2.ts, 2, 9)) +>U : Symbol(U, Decl(declarationEmit_expressionInExtends2.ts, 1, 10)) +} + +function getClass(c: T) { +>getClass : Symbol(getClass, Decl(declarationEmit_expressionInExtends2.ts, 4, 1)) +>T : Symbol(T, Decl(declarationEmit_expressionInExtends2.ts, 6, 18)) +>c : Symbol(c, Decl(declarationEmit_expressionInExtends2.ts, 6, 21)) +>T : Symbol(T, Decl(declarationEmit_expressionInExtends2.ts, 6, 18)) + + return C; +>C : Symbol(C, Decl(declarationEmit_expressionInExtends2.ts, 0, 0)) +} + +class MyClass extends getClass(2) { +>MyClass : Symbol(MyClass, Decl(declarationEmit_expressionInExtends2.ts, 8, 1)) +>getClass : Symbol(getClass, Decl(declarationEmit_expressionInExtends2.ts, 4, 1)) +} diff --git a/tests/baselines/reference/declarationEmit_expressionInExtends2.types b/tests/baselines/reference/declarationEmit_expressionInExtends2.types new file mode 100644 index 00000000000..77a1539267d --- /dev/null +++ b/tests/baselines/reference/declarationEmit_expressionInExtends2.types @@ -0,0 +1,32 @@ +=== tests/cases/compiler/declarationEmit_expressionInExtends2.ts === + +class C { +>C : C +>T : T +>U : U + + x: T; +>x : T +>T : T + + y: U; +>y : U +>U : U +} + +function getClass(c: T) { +>getClass : (c: T) => typeof C +>T : T +>c : T +>T : T + + return C; +>C : typeof C +} + +class MyClass extends getClass(2) { +>MyClass : MyClass +>getClass(2) : C +>getClass : (c: T) => typeof C +>2 : number +} diff --git a/tests/baselines/reference/declarationEmit_expressionInExtends3.errors.txt b/tests/baselines/reference/declarationEmit_expressionInExtends3.errors.txt new file mode 100644 index 00000000000..2783810c568 --- /dev/null +++ b/tests/baselines/reference/declarationEmit_expressionInExtends3.errors.txt @@ -0,0 +1,52 @@ +tests/cases/compiler/declarationEmit_expressionInExtends3.ts(29,30): error TS4020: Extends clause of exported class 'MyClass' has or is using private name 'LocalClass'. +tests/cases/compiler/declarationEmit_expressionInExtends3.ts(37,31): error TS4020: Extends clause of exported class 'MyClass3' has or is using private name 'LocalInterface'. + + +==== tests/cases/compiler/declarationEmit_expressionInExtends3.ts (2 errors) ==== + + export class ExportedClass { + x: T; + } + + class LocalClass { + x: T; + y: U; + } + + export interface ExportedInterface { + x: number; + } + + interface LocalInterface { + x: number; + } + + function getLocalClass(c: T) { + return LocalClass; + } + + function getExportedClass(c: T) { + return ExportedClass; + } + + + + export class MyClass extends getLocalClass(undefined) { // error LocalClass is inaccisible + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS4020: Extends clause of exported class 'MyClass' has or is using private name 'LocalClass'. + } + + + export class MyClass2 extends getExportedClass(undefined) { // OK + } + + + export class MyClass3 extends getExportedClass(undefined) { // Error LocalInterface is inaccisble + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS4020: Extends clause of exported class 'MyClass3' has or is using private name 'LocalInterface'. + } + + + export class MyClass4 extends getExportedClass(undefined) { // OK + } + \ No newline at end of file diff --git a/tests/baselines/reference/declarationEmit_expressionInExtends3.js b/tests/baselines/reference/declarationEmit_expressionInExtends3.js new file mode 100644 index 00000000000..10ef42d6838 --- /dev/null +++ b/tests/baselines/reference/declarationEmit_expressionInExtends3.js @@ -0,0 +1,101 @@ +//// [declarationEmit_expressionInExtends3.ts] + +export class ExportedClass { + x: T; +} + +class LocalClass { + x: T; + y: U; +} + +export interface ExportedInterface { + x: number; +} + +interface LocalInterface { + x: number; +} + +function getLocalClass(c: T) { + return LocalClass; +} + +function getExportedClass(c: T) { + return ExportedClass; +} + + + +export class MyClass extends getLocalClass(undefined) { // error LocalClass is inaccisible +} + + +export class MyClass2 extends getExportedClass(undefined) { // OK +} + + +export class MyClass3 extends getExportedClass(undefined) { // Error LocalInterface is inaccisble +} + + +export class MyClass4 extends getExportedClass(undefined) { // OK +} + + +//// [declarationEmit_expressionInExtends3.js] +"use strict"; +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 __()); +}; +var ExportedClass = (function () { + function ExportedClass() { + } + return ExportedClass; +}()); +exports.ExportedClass = ExportedClass; +var LocalClass = (function () { + function LocalClass() { + } + return LocalClass; +}()); +function getLocalClass(c) { + return LocalClass; +} +function getExportedClass(c) { + return ExportedClass; +} +var MyClass = (function (_super) { + __extends(MyClass, _super); + function MyClass() { + _super.apply(this, arguments); + } + return MyClass; +}(getLocalClass(undefined))); +exports.MyClass = MyClass; +var MyClass2 = (function (_super) { + __extends(MyClass2, _super); + function MyClass2() { + _super.apply(this, arguments); + } + return MyClass2; +}(getExportedClass(undefined))); +exports.MyClass2 = MyClass2; +var MyClass3 = (function (_super) { + __extends(MyClass3, _super); + function MyClass3() { + _super.apply(this, arguments); + } + return MyClass3; +}(getExportedClass(undefined))); +exports.MyClass3 = MyClass3; +var MyClass4 = (function (_super) { + __extends(MyClass4, _super); + function MyClass4() { + _super.apply(this, arguments); + } + return MyClass4; +}(getExportedClass(undefined))); +exports.MyClass4 = MyClass4; diff --git a/tests/cases/compiler/declarationEmit_expressionInExtends2.ts b/tests/cases/compiler/declarationEmit_expressionInExtends2.ts new file mode 100644 index 00000000000..0b2ccab8385 --- /dev/null +++ b/tests/cases/compiler/declarationEmit_expressionInExtends2.ts @@ -0,0 +1,13 @@ +// @declaration: true + +class C { + x: T; + y: U; +} + +function getClass(c: T) { + return C; +} + +class MyClass extends getClass(2) { +} \ No newline at end of file diff --git a/tests/cases/compiler/declarationEmit_expressionInExtends3.ts b/tests/cases/compiler/declarationEmit_expressionInExtends3.ts new file mode 100644 index 00000000000..348d0d188f7 --- /dev/null +++ b/tests/cases/compiler/declarationEmit_expressionInExtends3.ts @@ -0,0 +1,43 @@ +// @declaration: true + +export class ExportedClass { + x: T; +} + +class LocalClass { + x: T; + y: U; +} + +export interface ExportedInterface { + x: number; +} + +interface LocalInterface { + x: number; +} + +function getLocalClass(c: T) { + return LocalClass; +} + +function getExportedClass(c: T) { + return ExportedClass; +} + + + +export class MyClass extends getLocalClass(undefined) { // error LocalClass is inaccisible +} + + +export class MyClass2 extends getExportedClass(undefined) { // OK +} + + +export class MyClass3 extends getExportedClass(undefined) { // Error LocalInterface is inaccisble +} + + +export class MyClass4 extends getExportedClass(undefined) { // OK +}