Skip to content

Commit 96c2085

Browse files
author
Andy Hanson
committed
Code review
1 parent 8463d9e commit 96c2085

File tree

1 file changed

+47
-43
lines changed

1 file changed

+47
-43
lines changed

src/compiler/checker.ts

Lines changed: 47 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -7429,7 +7429,7 @@ namespace ts {
74297429

74307430
// Add the given types to the given type set. Order is preserved, duplicates are removed,
74317431
// and nested types of the given kind are flattened into the set.
7432-
function addTypesToUnion(typeSet: TypeSet, types: Type[]) {
7432+
function addTypesToUnion(typeSet: TypeSet, types: ReadonlyArray<Type>) {
74337433
for (const type of types) {
74347434
addTypeToUnion(typeSet, type);
74357435
}
@@ -7504,7 +7504,7 @@ namespace ts {
75047504
// expression constructs such as array literals and the || and ?: operators). Named types can
75057505
// circularly reference themselves and therefore cannot be subtype reduced during their declaration.
75067506
// For example, "type Item = string | (() => Item" is a named type that circularly references itself.
7507-
function getUnionType(types: Type[], subtypeReduction?: boolean, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type {
7507+
function getUnionType(types: ReadonlyArray<Type>, subtypeReduction?: boolean, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type {
75087508
if (types.length === 0) {
75097509
return neverType;
75107510
}
@@ -10434,11 +10434,6 @@ namespace ts {
1043410434
return symbol;
1043510435
}
1043610436

10437-
function createCombinedSymbolWithType(sources: ReadonlyArray<Symbol>, type: Type): Symbol {
10438-
// This function is currently only used for erroneous overloads, so it's good enough to just use the first source.
10439-
return createSymbolWithType(first(sources), type);
10440-
}
10441-
1044210437
function transformTypeOfMembers(type: Type, f: (propertyType: Type) => Type) {
1044310438
const members = createSymbolTable();
1044410439
for (const property of getPropertiesOfObjectType(type)) {
@@ -16526,49 +16521,22 @@ namespace ts {
1652616521
hasCandidatesOutArray: boolean,
1652716522
): Signature {
1652816523
Debug.assert(candidates.length > 0); // Else should not have called this.
16529-
1653016524
// Normally we will combine overloads. Skip this if they have type parameters since that's hard to combine.
1653116525
// Don't do this if there is a `candidatesOutArray`,
1653216526
// because then we want the chosen best candidate to be one of the overloads, not a combination.
16533-
if (!hasCandidatesOutArray && candidates.length > 1 && !candidates.some(c => !!c.typeParameters)) {
16534-
return createUnionOfSignaturesForOverloadFailure(candidates);
16535-
}
16536-
16537-
// Pick the longest signature. This way we can get a contextual type for cases like:
16538-
// declare function f(a: { xa: number; xb: number; }, b: number);
16539-
// f({ |
16540-
// Also, use explicitly-supplied type arguments if they are provided, so we can get a contextual signature in cases like:
16541-
// declare function f<T>(k: keyof T);
16542-
// f<Foo>("
16543-
const bestIndex = getLongestCandidateIndex(candidates, apparentArgumentCount === undefined ? args.length : apparentArgumentCount);
16544-
const candidate = candidates[bestIndex];
16545-
16546-
const { typeParameters } = candidate;
16547-
if (typeParameters && callLikeExpressionMayHaveTypeArguments(node) && node.typeArguments) {
16548-
const typeArguments = node.typeArguments.map(getTypeOfNode);
16549-
while (typeArguments.length > typeParameters.length) {
16550-
typeArguments.pop();
16551-
}
16552-
while (typeArguments.length < typeParameters.length) {
16553-
typeArguments.push(getDefaultTypeArgumentType(isInJavaScriptFile(node)));
16554-
}
16555-
16556-
const instantiated = createSignatureInstantiation(candidate, typeArguments);
16557-
candidates[bestIndex] = instantiated;
16558-
return instantiated;
16559-
}
16560-
16561-
return candidate;
16527+
return hasCandidatesOutArray || candidates.length === 1 || candidates.some(c => !!c.typeParameters)
16528+
? pickLongestCandidateSignature(node, candidates, args)
16529+
: createUnionOfSignaturesForOverloadFailure(candidates);
1656216530
}
1656316531

1656416532
function createUnionOfSignaturesForOverloadFailure(candidates: ReadonlyArray<Signature>): Signature {
1656516533
const thisParameters = mapDefined(candidates, c => c.thisParameter);
1656616534
let thisParameter: Symbol | undefined;
1656716535
if (thisParameters.length) {
16568-
thisParameter = createCombinedSymbolWithType(thisParameters, getUnionType(thisParameters.map(getTypeOfParameter), /*subtypeReduction*/ true));
16536+
thisParameter = createCombinedSymbolFromTypes(thisParameters, thisParameters.map(getTypeOfParameter));
1656916537
}
1657016538

16571-
const { min: minArgumentCount, max: maxNonRestParam } = minAndMax(candidates, getNumNonRestParameters);
16539+
const { min: minArgumentCount, max: maxNonRestParam } = minAndMax(candidates, getNumNonRestParameters);
1657216540
const hasRestParameter = candidates.some(c => c.hasRestParameter);
1657316541
const hasLiteralTypes = candidates.some(c => c.hasLiteralTypes);
1657416542
const parameters: ts.Symbol[] = [];
@@ -16577,15 +16545,14 @@ namespace ts {
1657716545
i < parameters.length - 1 ? parameters[i] : last(parameters) :
1657816546
i < parameters.length ? parameters[i] : undefined);
1657916547
Debug.assert(symbols.length !== 0);
16580-
const types = mapDefined(candidates, candidate => tryGetTypeAtPosition(candidate, i));
16581-
parameters.push(createCombinedSymbolWithType(symbols, getUnionType(types, /*subtypeReduction*/ true)));
16548+
parameters.push(createCombinedSymbolFromTypes(symbols, mapDefined(candidates, candidate => tryGetTypeAtPosition(candidate, i))));
1658216549
}
1658316550

1658416551
if (hasRestParameter) {
1658516552
const symbols = mapDefined(candidates, c => c.hasRestParameter ? last(c.parameters) : undefined);
1658616553
Debug.assert(symbols.length !== 0);
1658716554
const type = createArrayType(getUnionType(mapDefined(candidates, tryGetRestTypeOfSignature), /*subtypeReduction*/ true));
16588-
parameters.push(createCombinedSymbolWithType(symbols, type));
16555+
parameters.push(createCombinedSymbolForOverloadFailure(symbols, type));
1658916556
}
1659016557

1659116558
return createSignature(
@@ -16600,7 +16567,44 @@ namespace ts {
1660016567
hasLiteralTypes);
1660116568
}
1660216569

16603-
function getLongestCandidateIndex(candidates: Signature[], argsCount: number): number {
16570+
function createCombinedSymbolFromTypes(sources: ReadonlyArray<Symbol>, types: ReadonlyArray<Type>): Symbol {
16571+
return createCombinedSymbolForOverloadFailure(sources, getUnionType(types, /*subtypeReduction*/ true));
16572+
}
16573+
16574+
function createCombinedSymbolForOverloadFailure(sources: ReadonlyArray<Symbol>, type: Type): Symbol {
16575+
// This function is currently only used for erroneous overloads, so it's good enough to just use the first source.
16576+
return createSymbolWithType(first(sources), type);
16577+
}
16578+
16579+
function pickLongestCandidateSignature(node: CallLikeExpression, candidates: Signature[], args: ReadonlyArray<Expression>): Signature {
16580+
// Pick the longest signature. This way we can get a contextual type for cases like:
16581+
// declare function f(a: { xa: number; xb: number; }, b: number);
16582+
// f({ |
16583+
// Also, use explicitly-supplied type arguments if they are provided, so we can get a contextual signature in cases like:
16584+
// declare function f<T>(k: keyof T);
16585+
// f<Foo>("
16586+
const bestIndex = getLongestCandidateIndex(candidates, apparentArgumentCount === undefined ? args.length : apparentArgumentCount);
16587+
const candidate = candidates[bestIndex];
16588+
16589+
const { typeParameters } = candidate;
16590+
if (typeParameters && callLikeExpressionMayHaveTypeArguments(node) && node.typeArguments) {
16591+
const typeArguments = node.typeArguments.map(getTypeOfNode);
16592+
while (typeArguments.length > typeParameters.length) {
16593+
typeArguments.pop();
16594+
}
16595+
while (typeArguments.length < typeParameters.length) {
16596+
typeArguments.push(getDefaultTypeArgumentType(isInJavaScriptFile(node)));
16597+
}
16598+
16599+
const instantiated = createSignatureInstantiation(candidate, typeArguments);
16600+
candidates[bestIndex] = instantiated;
16601+
return instantiated;
16602+
}
16603+
16604+
return candidate;
16605+
}
16606+
16607+
function getLongestCandidateIndex(candidates: ReadonlyArray<Signature>, argsCount: number): number {
1660416608
let maxParamsIndex = -1;
1660516609
let maxParams = -1;
1660616610

0 commit comments

Comments
 (0)