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 (#40073)
  • Loading branch information
a-tarasyuk authored Aug 22, 2020
1 parent 9569198 commit 2dd7a4b
Show file tree
Hide file tree
Showing 15 changed files with 208 additions and 13 deletions.
17 changes: 14 additions & 3 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17772,8 +17772,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 @@ -17793,7 +17794,17 @@ 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) &&
(targetSignature.declaration?.kind === SyntaxKind.Constructor || sourceSignature.declaration?.kind === SyntaxKind.Constructor)) {
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_signatures_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 signatures are incompatible.": {
"category": "Error",
"code": 2419
},
"Class '{0}' incorrectly implements interface '{1}'.": {
"category": "Error",
"code": 2420
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ tests/cases/compiler/assignmentCompatWithOverloads.ts(19,1): error TS2322: Type
tests/cases/compiler/assignmentCompatWithOverloads.ts(21,1): error TS2322: Type '{ (x: string): string; (x: number): number; }' is not assignable to type '(s1: string) => number'.
Type 'string' is not assignable to type 'number'.
tests/cases/compiler/assignmentCompatWithOverloads.ts(30,1): error TS2322: Type 'typeof C' is not assignable to type 'new (x: number) => void'.
Types of parameters 'x' and 'x' are incompatible.
Type 'number' is not assignable to type 'string'.
Types of construct signatures are incompatible.
Type 'new (x: string) => C' is not assignable to type 'new (x: number) => void'.
Types of parameters 'x' and 'x' are incompatible.
Type 'number' is not assignable to type 'string'.


==== tests/cases/compiler/assignmentCompatWithOverloads.ts (4 errors) ====
Expand Down Expand Up @@ -53,5 +55,7 @@ tests/cases/compiler/assignmentCompatWithOverloads.ts(30,1): error TS2322: Type
d = C; // Error
~
!!! error TS2322: Type 'typeof C' is not assignable to type 'new (x: number) => void'.
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
!!! error TS2322: Type 'number' is not assignable to type 'string'.
!!! error TS2322: Types of construct signatures are incompatible.
!!! error TS2322: Type 'new (x: string) => C' is not assignable to type 'new (x: number) => void'.
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
!!! error TS2322: Type 'number' is not assignable to type 'string'.
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 signatures 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 signatures 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 signatures 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 signatures 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

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


==== tests/cases/compiler/classSideInheritance3.ts (2 errors) ====
Expand All @@ -21,7 +25,11 @@ 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 signatures 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'.
!!! error TS2322: Types of construct signatures are incompatible.
!!! error TS2322: Type 'new (x: string, data: string) => B' is not assignable to type 'new (x: string) => A'.
var r3: typeof A = C; // ok
16 changes: 10 additions & 6 deletions tests/baselines/reference/strictBindCallApply1.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,11 @@ tests/cases/conformance/functions/strictBindCallApply1.ts(62,11): error TS2769:
Argument of type 'number' is not assignable to parameter of type 'string'.
Overload 2 of 6, '(this: new (...args: (10 | 20)[]) => C, thisArg: any, ...args: (10 | 20)[]): new (...args: (10 | 20)[]) => C', gave the following error.
The 'this' context of type 'typeof C' is not assignable to method's 'this' of type 'new (...args: (10 | 20)[]) => C'.
Types of parameters 'b' and 'args' are incompatible.
Type 'number' is not assignable to type 'string'.
Type 'number' is not assignable to type 'string'.
Types of construct signatures are incompatible.
Type 'new (a: number, b: string) => C' is not assignable to type 'new (...args: (10 | 20)[]) => C'.
Types of parameters 'b' and 'args' are incompatible.
Type 'number' is not assignable to type 'string'.
Type 'number' is not assignable to type 'string'.
tests/cases/conformance/functions/strictBindCallApply1.ts(65,3): error TS2554: Expected 3 arguments, but got 2.
tests/cases/conformance/functions/strictBindCallApply1.ts(66,15): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
tests/cases/conformance/functions/strictBindCallApply1.ts(67,24): error TS2554: Expected 3 arguments, but got 4.
Expand Down Expand Up @@ -186,9 +188,11 @@ tests/cases/conformance/functions/strictBindCallApply1.ts(72,12): error TS2345:
!!! error TS2769: Argument of type 'number' is not assignable to parameter of type 'string'.
!!! error TS2769: Overload 2 of 6, '(this: new (...args: (10 | 20)[]) => C, thisArg: any, ...args: (10 | 20)[]): new (...args: (10 | 20)[]) => C', gave the following error.
!!! error TS2769: The 'this' context of type 'typeof C' is not assignable to method's 'this' of type 'new (...args: (10 | 20)[]) => C'.
!!! error TS2769: Types of parameters 'b' and 'args' are incompatible.
!!! error TS2769: Type 'number' is not assignable to type 'string'.
!!! error TS2769: Type 'number' is not assignable to type 'string'.
!!! error TS2769: Types of construct signatures are incompatible.
!!! error TS2769: Type 'new (a: number, b: string) => C' is not assignable to type 'new (...args: (10 | 20)[]) => C'.
!!! error TS2769: Types of parameters 'b' and 'args' are incompatible.
!!! error TS2769: Type 'number' is not assignable to type 'string'.
!!! error TS2769: Type 'number' is not assignable to type 'string'.

C.call(c, 10, "hello");
C.call(c, 10); // Error
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 2dd7a4b

Please sign in to comment.