Skip to content

Commit

Permalink
fix(31046): add new diagnostic message for incompatible constructor s…
Browse files Browse the repository at this point in the history
…ignature
  • Loading branch information
a-tarasyuk committed Aug 19, 2020
1 parent 610fa28 commit 22d94fd
Show file tree
Hide file tree
Showing 13 changed files with 188 additions and 3 deletions.
19 changes: 16 additions & 3 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17715,8 +17715,9 @@ namespace ts {
let result = Ternary.True;
const saveErrorInfo = captureErrorCalculationState();
const incompatibleReporter = kind === SignatureKind.Construct ? reportIncompatibleConstructSignatureReturn : reportIncompatibleCallSignatureReturn;

if (getObjectFlags(source) & ObjectFlags.Instantiated && getObjectFlags(target) & ObjectFlags.Instantiated && source.symbol === target.symbol) {
const sourceObjectFlags = getObjectFlags(source);
const targetObjectFlags = getObjectFlags(target);
if (sourceObjectFlags & ObjectFlags.Instantiated && targetObjectFlags & ObjectFlags.Instantiated && source.symbol === target.symbol) {
// We have instantiations of the same anonymous type (which typically will be the type of a
// method). Simply do a pairwise comparison of the signatures in the two signature lists instead
// of the much more expensive N * M comparison matrix we explore below. We erase type parameters
Expand All @@ -17736,7 +17737,19 @@ namespace ts {
// this regardless of the number of signatures, but the potential costs are prohibitive due
// to the quadratic nature of the logic below.
const eraseGenerics = relation === comparableRelation || !!compilerOptions.noStrictGenericChecks;
result = signatureRelatedTo(sourceSignatures[0], targetSignatures[0], eraseGenerics, reportErrors, incompatibleReporter(sourceSignatures[0], targetSignatures[0]));
const sourceSignature = first(sourceSignatures);
const targetSignature = first(targetSignatures);
result = signatureRelatedTo(sourceSignature, targetSignature, eraseGenerics, reportErrors, incompatibleReporter(sourceSignature, targetSignature));
if (!result && reportErrors && kind === SignatureKind.Construct && (sourceObjectFlags & targetObjectFlags)) {
const declaration = targetSignature.declaration || sourceSignature.declaration;
if (declaration && (isConstructorDeclaration(declaration) || isConstructSignatureDeclaration(declaration))) {
const constructSignatureToString = (signature: Signature) =>
signatureToString(signature, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrowStyleSignature, kind);
reportError(Diagnostics.Type_0_is_not_assignable_to_type_1, constructSignatureToString(sourceSignature), constructSignatureToString(targetSignature));
reportError(Diagnostics.Types_of_construct_signature_are_incompatible);
return result;
}
}
}
else {
outer: for (const t of targetSignatures) {
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1686,6 +1686,10 @@
"category": "Error",
"code": 2418
},
"Types of construct signature are incompatible.": {
"category": "Error",
"code": 2419
},
"Class '{0}' incorrectly implements interface '{1}'.": {
"category": "Error",
"code": 2420
Expand Down
16 changes: 16 additions & 0 deletions tests/baselines/reference/assignmentCompatability44.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
tests/cases/compiler/assignmentCompatability44.ts(5,7): error TS2322: Type 'typeof Foo' is not assignable to type 'new () => Foo'.
Types of construct signature are incompatible.
Type 'new (x: number) => Foo' is not assignable to type 'new () => Foo'.


==== tests/cases/compiler/assignmentCompatability44.ts (1 errors) ====
class Foo {
constructor(x: number) {}
}

const foo: { new(): Foo } = Foo;
~~~
!!! error TS2322: Type 'typeof Foo' is not assignable to type 'new () => Foo'.
!!! error TS2322: Types of construct signature are incompatible.
!!! error TS2322: Type 'new (x: number) => Foo' is not assignable to type 'new () => Foo'.

15 changes: 15 additions & 0 deletions tests/baselines/reference/assignmentCompatability44.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//// [assignmentCompatability44.ts]
class Foo {
constructor(x: number) {}
}

const foo: { new(): Foo } = Foo;


//// [assignmentCompatability44.js]
var Foo = /** @class */ (function () {
function Foo(x) {
}
return Foo;
}());
var foo = Foo;
13 changes: 13 additions & 0 deletions tests/baselines/reference/assignmentCompatability44.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
=== tests/cases/compiler/assignmentCompatability44.ts ===
class Foo {
>Foo : Symbol(Foo, Decl(assignmentCompatability44.ts, 0, 0))

constructor(x: number) {}
>x : Symbol(x, Decl(assignmentCompatability44.ts, 1, 16))
}

const foo: { new(): Foo } = Foo;
>foo : Symbol(foo, Decl(assignmentCompatability44.ts, 4, 5))
>Foo : Symbol(Foo, Decl(assignmentCompatability44.ts, 0, 0))
>Foo : Symbol(Foo, Decl(assignmentCompatability44.ts, 0, 0))

12 changes: 12 additions & 0 deletions tests/baselines/reference/assignmentCompatability44.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
=== tests/cases/compiler/assignmentCompatability44.ts ===
class Foo {
>Foo : Foo

constructor(x: number) {}
>x : number
}

const foo: { new(): Foo } = Foo;
>foo : new () => Foo
>Foo : typeof Foo

18 changes: 18 additions & 0 deletions tests/baselines/reference/assignmentCompatability45.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
tests/cases/compiler/assignmentCompatability45.ts(7,7): error TS2322: Type 'typeof B' is not assignable to type 'typeof A'.
Types of construct signature are incompatible.
Type 'new (x: number) => B' is not assignable to type 'new () => A'.


==== tests/cases/compiler/assignmentCompatability45.ts (1 errors) ====
abstract class A {}
class B extends A {
constructor(x: number) {
super();
}
}
const b: typeof A = B;
~
!!! error TS2322: Type 'typeof B' is not assignable to type 'typeof A'.
!!! error TS2322: Types of construct signature are incompatible.
!!! error TS2322: Type 'new (x: number) => B' is not assignable to type 'new () => A'.

37 changes: 37 additions & 0 deletions tests/baselines/reference/assignmentCompatability45.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//// [assignmentCompatability45.ts]
abstract class A {}
class B extends A {
constructor(x: number) {
super();
}
}
const b: typeof A = B;


//// [assignmentCompatability45.js]
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
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() {
}
return A;
}());
var B = /** @class */ (function (_super) {
__extends(B, _super);
function B(x) {
return _super.call(this) || this;
}
return B;
}(A));
var b = B;
20 changes: 20 additions & 0 deletions tests/baselines/reference/assignmentCompatability45.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
=== tests/cases/compiler/assignmentCompatability45.ts ===
abstract class A {}
>A : Symbol(A, Decl(assignmentCompatability45.ts, 0, 0))

class B extends A {
>B : Symbol(B, Decl(assignmentCompatability45.ts, 0, 19))
>A : Symbol(A, Decl(assignmentCompatability45.ts, 0, 0))

constructor(x: number) {
>x : Symbol(x, Decl(assignmentCompatability45.ts, 2, 16))

super();
>super : Symbol(A, Decl(assignmentCompatability45.ts, 0, 0))
}
}
const b: typeof A = B;
>b : Symbol(b, Decl(assignmentCompatability45.ts, 6, 5))
>A : Symbol(A, Decl(assignmentCompatability45.ts, 0, 0))
>B : Symbol(B, Decl(assignmentCompatability45.ts, 0, 19))

21 changes: 21 additions & 0 deletions tests/baselines/reference/assignmentCompatability45.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
=== tests/cases/compiler/assignmentCompatability45.ts ===
abstract class A {}
>A : A

class B extends A {
>B : B
>A : A

constructor(x: number) {
>x : number

super();
>super() : void
>super : typeof A
}
}
const b: typeof A = B;
>b : typeof A
>A : typeof A
>B : typeof B

4 changes: 4 additions & 0 deletions tests/baselines/reference/classSideInheritance3.errors.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
tests/cases/compiler/classSideInheritance3.ts(16,5): error TS2322: Type 'typeof B' is not assignable to type 'typeof A'.
Types of construct signature are incompatible.
Type 'new (x: string, data: string) => B' is not assignable to type 'new (x: string) => A'.
tests/cases/compiler/classSideInheritance3.ts(17,5): error TS2322: Type 'typeof B' is not assignable to type 'new (x: string) => A'.


Expand All @@ -21,6 +23,8 @@ tests/cases/compiler/classSideInheritance3.ts(17,5): error TS2322: Type 'typeof
var r1: typeof A = B; // error
~~
!!! error TS2322: Type 'typeof B' is not assignable to type 'typeof A'.
!!! error TS2322: Types of construct signature are incompatible.
!!! error TS2322: Type 'new (x: string, data: string) => B' is not assignable to type 'new (x: string) => A'.
var r2: new (x: string) => A = B; // error
~~
!!! error TS2322: Type 'typeof B' is not assignable to type 'new (x: string) => A'.
Expand Down
5 changes: 5 additions & 0 deletions tests/cases/compiler/assignmentCompatability44.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class Foo {
constructor(x: number) {}
}

const foo: { new(): Foo } = Foo;
7 changes: 7 additions & 0 deletions tests/cases/compiler/assignmentCompatability45.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
abstract class A {}
class B extends A {
constructor(x: number) {
super();
}
}
const b: typeof A = B;

0 comments on commit 22d94fd

Please sign in to comment.