mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-14 19:16:17 -06:00
Union this-types of unioned call signatures
And and tests and baselines
This commit is contained in:
parent
e7aa7e4958
commit
482acccada
@ -3610,9 +3610,9 @@ namespace ts {
|
||||
setObjectTypeMembers(type, members, arrayType.callSignatures, arrayType.constructSignatures, arrayType.stringIndexInfo, arrayType.numberIndexInfo);
|
||||
}
|
||||
|
||||
function findMatchingSignature(signatureList: Signature[], signature: Signature, partialMatch: boolean, ignoreReturnTypes: boolean): Signature {
|
||||
function findMatchingSignature(signatureList: Signature[], signature: Signature, partialMatch: boolean, ignoreThisTypes: boolean, ignoreReturnTypes: boolean): Signature {
|
||||
for (const s of signatureList) {
|
||||
if (compareSignaturesIdentical(s, signature, partialMatch, ignoreReturnTypes, compareTypesIdentical)) {
|
||||
if (compareSignaturesIdentical(s, signature, partialMatch, ignoreThisTypes, ignoreReturnTypes, compareTypesIdentical)) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@ -3626,7 +3626,7 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
for (let i = 1; i < signatureLists.length; i++) {
|
||||
if (!findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ false, /*ignoreReturnTypes*/ false)) {
|
||||
if (!findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ false)) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
@ -3635,7 +3635,7 @@ namespace ts {
|
||||
let result: Signature[] = undefined;
|
||||
for (let i = 0; i < signatureLists.length; i++) {
|
||||
// Allow matching non-generic signatures to have excess parameters and different return types
|
||||
const match = i === listIndex ? signature : findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ true, /*ignoreReturnTypes*/ true);
|
||||
const match = i === listIndex ? signature : findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ true, /*ignoreThisTypes*/ true, /*ignoreReturnTypes*/ true);
|
||||
if (!match) {
|
||||
return undefined;
|
||||
}
|
||||
@ -3656,13 +3656,16 @@ namespace ts {
|
||||
for (let i = 0; i < signatureLists.length; i++) {
|
||||
for (const signature of signatureLists[i]) {
|
||||
// Only process signatures with parameter lists that aren't already in the result list
|
||||
if (!result || !findMatchingSignature(result, signature, /*partialMatch*/ false, /*ignoreReturnTypes*/ true)) {
|
||||
if (!result || !findMatchingSignature(result, signature, /*partialMatch*/ false, /*ignoreThisTypes*/ true, /*ignoreReturnTypes*/ true)) {
|
||||
const unionSignatures = findMatchingSignatures(signatureLists, signature, i);
|
||||
if (unionSignatures) {
|
||||
let s = signature;
|
||||
// Union the result types when more than one signature matches
|
||||
if (unionSignatures.length > 1) {
|
||||
s = cloneSignature(signature);
|
||||
if (forEach(unionSignatures, sig => sig.thisType)) {
|
||||
s.thisType = getUnionType(map(unionSignatures, sig => sig.thisType || anyType));
|
||||
}
|
||||
// Clear resolved return type we possibly got from cloneSignature
|
||||
s.resolvedReturnType = undefined;
|
||||
s.unionSignatures = unionSignatures;
|
||||
@ -6002,7 +6005,7 @@ namespace ts {
|
||||
}
|
||||
let result = Ternary.True;
|
||||
for (let i = 0, len = sourceSignatures.length; i < len; i++) {
|
||||
const related = compareSignaturesIdentical(sourceSignatures[i], targetSignatures[i], /*partialMatch*/ false, /*ignoreReturnTypes*/ false, isRelatedTo);
|
||||
const related = compareSignaturesIdentical(sourceSignatures[i], targetSignatures[i], /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ false, isRelatedTo);
|
||||
if (!related) {
|
||||
return Ternary.False;
|
||||
}
|
||||
@ -6203,7 +6206,7 @@ namespace ts {
|
||||
/**
|
||||
* See signatureRelatedTo, compareSignaturesIdentical
|
||||
*/
|
||||
function compareSignaturesIdentical(source: Signature, target: Signature, partialMatch: boolean, ignoreReturnTypes: boolean, compareTypes: (s: Type, t: Type) => Ternary): Ternary {
|
||||
function compareSignaturesIdentical(source: Signature, target: Signature, partialMatch: boolean, ignoreThisTypes: boolean, ignoreReturnTypes: boolean, compareTypes: (s: Type, t: Type) => Ternary): Ternary {
|
||||
// TODO (drosen): De-duplicate code between related functions.
|
||||
if (source === target) {
|
||||
return Ternary.True;
|
||||
@ -6224,6 +6227,13 @@ namespace ts {
|
||||
source = getErasedSignature(source);
|
||||
target = getErasedSignature(target);
|
||||
let result = Ternary.True;
|
||||
if (!ignoreThisTypes && source.thisType && target.thisType) {
|
||||
const related = compareTypes(source.thisType, target.thisType);
|
||||
if (!related) {
|
||||
return Ternary.False;
|
||||
}
|
||||
result &= related;
|
||||
}
|
||||
const targetLen = target.parameters.length;
|
||||
for (let i = 0; i < targetLen; i++) {
|
||||
const s = isRestParameterIndex(source, i) ? getRestTypeOfSignature(source) : getTypeOfSymbol(source.parameters[i]);
|
||||
@ -8137,7 +8147,7 @@ namespace ts {
|
||||
// This signature will contribute to contextual union signature
|
||||
signatureList = [signature];
|
||||
}
|
||||
else if (!compareSignaturesIdentical(signatureList[0], signature, /*partialMatch*/ false, /*ignoreReturnTypes*/ true, compareTypesIdentical)) {
|
||||
else if (!compareSignaturesIdentical(signatureList[0], signature, /*partialMatch*/ false, /*ignoreThisTypes*/ true, /*ignoreReturnTypes*/ true, compareTypesIdentical)) {
|
||||
// Signatures aren't identical, do not use
|
||||
return undefined;
|
||||
}
|
||||
|
||||
18
tests/baselines/reference/unionThisTypeInFunctions.js
Normal file
18
tests/baselines/reference/unionThisTypeInFunctions.js
Normal file
@ -0,0 +1,18 @@
|
||||
//// [unionThisTypeInFunctions.ts]
|
||||
interface Real {
|
||||
method(n: number): void;
|
||||
data: string;
|
||||
}
|
||||
interface Fake {
|
||||
method(n: number): void;
|
||||
data: number;
|
||||
}
|
||||
function test(r: Real | Fake) {
|
||||
r.method(12);
|
||||
}
|
||||
|
||||
|
||||
//// [unionThisTypeInFunctions.js]
|
||||
function test(r) {
|
||||
r.method(12);
|
||||
}
|
||||
33
tests/baselines/reference/unionThisTypeInFunctions.symbols
Normal file
33
tests/baselines/reference/unionThisTypeInFunctions.symbols
Normal file
@ -0,0 +1,33 @@
|
||||
=== tests/cases/conformance/types/thisType/unionThisTypeInFunctions.ts ===
|
||||
interface Real {
|
||||
>Real : Symbol(Real, Decl(unionThisTypeInFunctions.ts, 0, 0))
|
||||
|
||||
method(n: number): void;
|
||||
>method : Symbol(method, Decl(unionThisTypeInFunctions.ts, 0, 16))
|
||||
>n : Symbol(n, Decl(unionThisTypeInFunctions.ts, 1, 11))
|
||||
|
||||
data: string;
|
||||
>data : Symbol(data, Decl(unionThisTypeInFunctions.ts, 1, 28))
|
||||
}
|
||||
interface Fake {
|
||||
>Fake : Symbol(Fake, Decl(unionThisTypeInFunctions.ts, 3, 1))
|
||||
|
||||
method(n: number): void;
|
||||
>method : Symbol(method, Decl(unionThisTypeInFunctions.ts, 4, 16))
|
||||
>n : Symbol(n, Decl(unionThisTypeInFunctions.ts, 5, 11))
|
||||
|
||||
data: number;
|
||||
>data : Symbol(data, Decl(unionThisTypeInFunctions.ts, 5, 28))
|
||||
}
|
||||
function test(r: Real | Fake) {
|
||||
>test : Symbol(test, Decl(unionThisTypeInFunctions.ts, 7, 1))
|
||||
>r : Symbol(r, Decl(unionThisTypeInFunctions.ts, 8, 14))
|
||||
>Real : Symbol(Real, Decl(unionThisTypeInFunctions.ts, 0, 0))
|
||||
>Fake : Symbol(Fake, Decl(unionThisTypeInFunctions.ts, 3, 1))
|
||||
|
||||
r.method(12);
|
||||
>r.method : Symbol(method, Decl(unionThisTypeInFunctions.ts, 0, 16), Decl(unionThisTypeInFunctions.ts, 4, 16))
|
||||
>r : Symbol(r, Decl(unionThisTypeInFunctions.ts, 8, 14))
|
||||
>method : Symbol(method, Decl(unionThisTypeInFunctions.ts, 0, 16), Decl(unionThisTypeInFunctions.ts, 4, 16))
|
||||
}
|
||||
|
||||
35
tests/baselines/reference/unionThisTypeInFunctions.types
Normal file
35
tests/baselines/reference/unionThisTypeInFunctions.types
Normal file
@ -0,0 +1,35 @@
|
||||
=== tests/cases/conformance/types/thisType/unionThisTypeInFunctions.ts ===
|
||||
interface Real {
|
||||
>Real : Real
|
||||
|
||||
method(n: number): void;
|
||||
>method : (this: this, n: number) => void
|
||||
>n : number
|
||||
|
||||
data: string;
|
||||
>data : string
|
||||
}
|
||||
interface Fake {
|
||||
>Fake : Fake
|
||||
|
||||
method(n: number): void;
|
||||
>method : (this: this, n: number) => void
|
||||
>n : number
|
||||
|
||||
data: number;
|
||||
>data : number
|
||||
}
|
||||
function test(r: Real | Fake) {
|
||||
>test : (this: void, r: Real | Fake) => void
|
||||
>r : Real | Fake
|
||||
>Real : Real
|
||||
>Fake : Fake
|
||||
|
||||
r.method(12);
|
||||
>r.method(12) : void
|
||||
>r.method : ((this: Real, n: number) => void) | ((this: Fake, n: number) => void)
|
||||
>r : Real | Fake
|
||||
>method : ((this: Real, n: number) => void) | ((this: Fake, n: number) => void)
|
||||
>12 : number
|
||||
}
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
// @strictThis: true
|
||||
interface Real {
|
||||
method(n: number): void;
|
||||
data: string;
|
||||
}
|
||||
interface Fake {
|
||||
method(n: number): void;
|
||||
data: number;
|
||||
}
|
||||
function test(r: Real | Fake) {
|
||||
r.method(12);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user