Skip to content

Commit a75e9ab

Browse files
committed
differentiate between call and construct
1 parent 5d332ae commit a75e9ab

File tree

7 files changed

+110
-8
lines changed

7 files changed

+110
-8
lines changed

src/compiler/checker.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18442,7 +18442,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1844218442
target: Signature,
1844318443
ignoreReturnTypes: boolean): boolean {
1844418444
return compareSignaturesRelated(source, target, ignoreReturnTypes ? SignatureCheckMode.IgnoreReturnTypes : 0, /*reportErrors*/ false,
18445-
/*errorReporter*/ undefined, /*errorReporter*/ undefined, compareTypesAssignable, /*reportUnreliableMarkers*/ undefined) !== Ternary.False;
18445+
/*errorReporter*/ undefined, /*incompatibleErrorReporter*/ undefined, /*signatureKindForErrors*/ undefined, compareTypesAssignable, /*reportUnreliableMarkers*/ undefined) !== Ternary.False;
1844618446
}
1844718447

1844818448
type ErrorReporter = (message: DiagnosticMessage, arg0?: string, arg1?: string) => void;
@@ -18465,6 +18465,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1846518465
reportErrors: boolean,
1846618466
errorReporter: ErrorReporter | undefined,
1846718467
incompatibleErrorReporter: ((source: Type, target: Type) => void) | undefined,
18468+
signatureKindForErrors: SignatureKind | undefined,
1846818469
compareTypes: TypeComparer,
1846918470
reportUnreliableMarkers: TypeMapper | undefined): Ternary {
1847018471
// TODO (drosen): De-duplicate code between related functions.
@@ -18481,7 +18482,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1848118482
(checkMode & SignatureCheckMode.StrictArity ? hasEffectiveRestParameter(source) || getParameterCount(source) > targetCount : getMinArgumentCount(source) > targetCount);
1848218483
if (sourceHasMoreParameters) {
1848318484
if (reportErrors) {
18484-
errorReporter!(Diagnostics.Call_signature_0_expects_more_arguments_than_call_signature_1, signatureToString(source), signatureToString(target));
18485+
const diagnostic = signatureKindForErrors! === SignatureKind.Call ? Diagnostics.Call_signature_0_expects_more_arguments_than_call_signature_1 : Diagnostics.Construct_signature_0_expects_more_arguments_than_construct_signature_1;
18486+
errorReporter!(diagnostic, signatureToString(source), signatureToString(target));
1848518487
}
1848618488
return Ternary.False;
1848718489
}
@@ -18540,7 +18542,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1854018542
const callbacks = sourceSig && targetSig && !getTypePredicateOfSignature(sourceSig) && !getTypePredicateOfSignature(targetSig) &&
1854118543
(getTypeFacts(sourceType) & TypeFacts.IsUndefinedOrNull) === (getTypeFacts(targetType) & TypeFacts.IsUndefinedOrNull);
1854218544
let related = callbacks ?
18543-
compareSignaturesRelated(targetSig, sourceSig, (checkMode & SignatureCheckMode.StrictArity) | (strictVariance ? SignatureCheckMode.StrictCallback : SignatureCheckMode.BivariantCallback), reportErrors, errorReporter, incompatibleErrorReporter, compareTypes, reportUnreliableMarkers) :
18545+
compareSignaturesRelated(targetSig, sourceSig, (checkMode & SignatureCheckMode.StrictArity) | (strictVariance ? SignatureCheckMode.StrictCallback : SignatureCheckMode.BivariantCallback), reportErrors, errorReporter, incompatibleErrorReporter, signatureKindForErrors, compareTypes, reportUnreliableMarkers) :
1854418546
!(checkMode & SignatureCheckMode.Callback) && !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors);
1854518547
// With strict arity, (x: number | undefined) => void is a subtype of (x?: number | undefined) => void
1854618548
if (related && checkMode & SignatureCheckMode.StrictArity && i >= getMinArgumentCount(source) && i < getMinArgumentCount(target) && compareTypes(sourceType, targetType, /*reportErrors*/ false)) {
@@ -20914,7 +20916,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2091420916
// of the much more expensive N * M comparison matrix we explore below. We erase type parameters
2091520917
// as they are known to always be the same.
2091620918
for (let i = 0; i < targetSignatures.length; i++) {
20917-
const related = signatureRelatedTo(sourceSignatures[i], targetSignatures[i], /*erase*/ true, reportErrors, incompatibleReporter(sourceSignatures[i], targetSignatures[i]));
20919+
const related = signatureRelatedTo(sourceSignatures[i], targetSignatures[i], /*erase*/ true, reportErrors, incompatibleReporter(sourceSignatures[i], targetSignatures[i]), kind);
2091820920
if (!related) {
2091920921
return Ternary.False;
2092020922
}
@@ -20930,7 +20932,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2093020932
const eraseGenerics = relation === comparableRelation || !!compilerOptions.noStrictGenericChecks;
2093120933
const sourceSignature = first(sourceSignatures);
2093220934
const targetSignature = first(targetSignatures);
20933-
result = signatureRelatedTo(sourceSignature, targetSignature, eraseGenerics, reportErrors, incompatibleReporter(sourceSignature, targetSignature));
20935+
result = signatureRelatedTo(sourceSignature, targetSignature, eraseGenerics, reportErrors, incompatibleReporter(sourceSignature, targetSignature), kind);
2093420936
if (!result && reportErrors && kind === SignatureKind.Construct && (sourceObjectFlags & targetObjectFlags) &&
2093520937
(targetSignature.declaration?.kind === SyntaxKind.Constructor || sourceSignature.declaration?.kind === SyntaxKind.Constructor)) {
2093620938
const constructSignatureToString = (signature: Signature) =>
@@ -20946,7 +20948,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2094620948
// Only elaborate errors from the first failure
2094720949
let shouldElaborateErrors = reportErrors;
2094820950
for (const s of sourceSignatures) {
20949-
const related = signatureRelatedTo(s, t, /*erase*/ true, shouldElaborateErrors, incompatibleReporter(s, t));
20951+
const related = signatureRelatedTo(s, t, /*erase*/ true, shouldElaborateErrors, incompatibleReporter(s, t), kind);
2095020952
if (related) {
2095120953
result &= related;
2095220954
resetErrorInfo(saveErrorInfo);
@@ -20996,9 +20998,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2099620998
/**
2099720999
* See signatureAssignableTo, compareSignaturesIdentical
2099821000
*/
20999-
function signatureRelatedTo(source: Signature, target: Signature, erase: boolean, reportErrors: boolean, incompatibleReporter: (source: Type, target: Type) => void): Ternary {
21001+
function signatureRelatedTo(source: Signature, target: Signature, erase: boolean, reportErrors: boolean, incompatibleReporter: (source: Type, target: Type) => void, signatureKind: SignatureKind): Ternary {
2100021002
return compareSignaturesRelated(erase ? getErasedSignature(source) : source, erase ? getErasedSignature(target) : target,
21001-
relation === strictSubtypeRelation ? SignatureCheckMode.StrictArity : 0, reportErrors, reportError, incompatibleReporter, isRelatedToWorker, reportUnreliableMapper);
21003+
relation === strictSubtypeRelation ? SignatureCheckMode.StrictArity : 0, reportErrors, reportError, incompatibleReporter, signatureKind, isRelatedToWorker, reportUnreliableMapper);
2100221004
}
2100321005

2100421006
function signaturesIdenticalTo(source: Type, target: Type, kind: SignatureKind): Ternary {

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3567,6 +3567,10 @@
35673567
"category": "Error",
35683568
"code": 2846
35693569
},
3570+
"Construct signature '{0}' expects more arguments than construct signature '{1}'.": {
3571+
"category": "Error",
3572+
"code": 2847
3573+
},
35703574

35713575
"Import declaration '{0}' is using private name '{1}'.": {
35723576
"category": "Error",
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
tests/cases/compiler/signatureLengthMismatchConstruct.ts(9,15): error TS2345: Argument of type 'typeof OverlongCtor' is not assignable to parameter of type 'new (a: number) => void'.
2+
Types of construct signatures are incompatible.
3+
Type 'new (a: number, b: number) => OverlongCtor' is not assignable to type 'new (a: number) => void'.
4+
Construct signature '(a: number, b: number): OverlongCtor' expects more arguments than construct signature '(a: number): void'.
5+
6+
7+
==== tests/cases/compiler/signatureLengthMismatchConstruct.ts (1 errors) ====
8+
function takesCallback(fn: new (a: number) => void) {
9+
// ...
10+
}
11+
12+
class OverlongCtor {
13+
constructor(a: number, b: number) {}
14+
}
15+
16+
takesCallback(OverlongCtor);
17+
~~~~~~~~~~~~
18+
!!! error TS2345: Argument of type 'typeof OverlongCtor' is not assignable to parameter of type 'new (a: number) => void'.
19+
!!! error TS2345: Types of construct signatures are incompatible.
20+
!!! error TS2345: Type 'new (a: number, b: number) => OverlongCtor' is not assignable to type 'new (a: number) => void'.
21+
!!! error TS2345: Construct signature '(a: number, b: number): OverlongCtor' expects more arguments than construct signature '(a: number): void'.
22+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//// [signatureLengthMismatchConstruct.ts]
2+
function takesCallback(fn: new (a: number) => void) {
3+
// ...
4+
}
5+
6+
class OverlongCtor {
7+
constructor(a: number, b: number) {}
8+
}
9+
10+
takesCallback(OverlongCtor);
11+
12+
13+
//// [signatureLengthMismatchConstruct.js]
14+
function takesCallback(fn) {
15+
// ...
16+
}
17+
var OverlongCtor = /** @class */ (function () {
18+
function OverlongCtor(a, b) {
19+
}
20+
return OverlongCtor;
21+
}());
22+
takesCallback(OverlongCtor);
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
=== tests/cases/compiler/signatureLengthMismatchConstruct.ts ===
2+
function takesCallback(fn: new (a: number) => void) {
3+
>takesCallback : Symbol(takesCallback, Decl(signatureLengthMismatchConstruct.ts, 0, 0))
4+
>fn : Symbol(fn, Decl(signatureLengthMismatchConstruct.ts, 0, 23))
5+
>a : Symbol(a, Decl(signatureLengthMismatchConstruct.ts, 0, 32))
6+
7+
// ...
8+
}
9+
10+
class OverlongCtor {
11+
>OverlongCtor : Symbol(OverlongCtor, Decl(signatureLengthMismatchConstruct.ts, 2, 1))
12+
13+
constructor(a: number, b: number) {}
14+
>a : Symbol(a, Decl(signatureLengthMismatchConstruct.ts, 5, 14))
15+
>b : Symbol(b, Decl(signatureLengthMismatchConstruct.ts, 5, 24))
16+
}
17+
18+
takesCallback(OverlongCtor);
19+
>takesCallback : Symbol(takesCallback, Decl(signatureLengthMismatchConstruct.ts, 0, 0))
20+
>OverlongCtor : Symbol(OverlongCtor, Decl(signatureLengthMismatchConstruct.ts, 2, 1))
21+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
=== tests/cases/compiler/signatureLengthMismatchConstruct.ts ===
2+
function takesCallback(fn: new (a: number) => void) {
3+
>takesCallback : (fn: new (a: number) => void) => void
4+
>fn : new (a: number) => void
5+
>a : number
6+
7+
// ...
8+
}
9+
10+
class OverlongCtor {
11+
>OverlongCtor : OverlongCtor
12+
13+
constructor(a: number, b: number) {}
14+
>a : number
15+
>b : number
16+
}
17+
18+
takesCallback(OverlongCtor);
19+
>takesCallback(OverlongCtor) : void
20+
>takesCallback : (fn: new (a: number) => void) => void
21+
>OverlongCtor : typeof OverlongCtor
22+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
function takesCallback(fn: new (a: number) => void) {
2+
// ...
3+
}
4+
5+
class OverlongCtor {
6+
constructor(a: number, b: number) {}
7+
}
8+
9+
takesCallback(OverlongCtor);

0 commit comments

Comments
 (0)