Skip to content

Commit d347b08

Browse files
committed
Copied from old branch
1. Everything explodes! Out of stack space! 2. Results aren't used yet. 3. But call and construct use the new getSignatureFromCalls, so I expect some baseline changes after I get the infinite recursion fixed.
1 parent 0f215fd commit d347b08

File tree

3 files changed

+75
-14
lines changed

3 files changed

+75
-14
lines changed

src/compiler/checker.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,9 @@ namespace ts {
524524
},
525525
getApparentType,
526526
getUnionType,
527+
isTypeAssignableTo: (source, target) => {
528+
return isTypeAssignableTo(source, target);
529+
},
527530
createAnonymousType,
528531
createSignature,
529532
createSymbol,

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3286,6 +3286,7 @@ namespace ts {
32863286
/* @internal */ getElementTypeOfArrayType(arrayType: Type): Type | undefined;
32873287
/* @internal */ createPromiseType(type: Type): Type;
32883288

3289+
/* @internal */ isTypeAssignableTo(source: Type, target: Type): boolean;
32893290
/* @internal */ createAnonymousType(symbol: Symbol, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexInfo: IndexInfo | undefined, numberIndexInfo: IndexInfo | undefined): Type;
32903291
/* @internal */ createSignature(
32913292
declaration: SignatureDeclaration,

src/services/codefixes/inferFromUsage.ts

Lines changed: 71 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ namespace ts.codefix {
401401

402402
interface CallUsage {
403403
argumentTypes: Type[];
404-
returnType: Usage;
404+
return_: Usage;
405405
}
406406

407407
interface Usage {
@@ -671,16 +671,17 @@ namespace ts.codefix {
671671
function inferTypeFromCallExpression(parent: CallExpression | NewExpression, usage: Usage): void {
672672
const call: CallUsage = {
673673
argumentTypes: [],
674-
returnType: {}
674+
return_: {}
675675
};
676676

677677
if (parent.arguments) {
678678
for (const argument of parent.arguments) {
679+
// TODO: should recursively infer a usage here, right?
679680
call.argumentTypes.push(checker.getTypeAtLocation(argument));
680681
}
681682
}
682683

683-
calculateUsageOfNode(parent, call.returnType);
684+
calculateUsageOfNode(parent, call.return_);
684685
if (parent.kind === SyntaxKind.CallExpression) {
685686
(usage.calls || (usage.calls = [])).push(call);
686687
}
@@ -830,6 +831,7 @@ namespace ts.codefix {
830831
}
831832

832833
types.push(...(usage.candidateTypes || []).map(t => checker.getBaseTypeOfLiteralType(t)));
834+
types.push(...findBuiltinType(usage));
833835

834836
if (usage.properties && hasCalls(usage.properties.get("then" as __String))) {
835837
const paramType = getParameterTypeFromCalls(0, usage.properties.get("then" as __String)!.calls!, /*isRestParameter*/ false)!; // TODO: GH#18217
@@ -858,15 +860,11 @@ namespace ts.codefix {
858860
}
859861

860862
if (usage.calls) {
861-
for (const call of usage.calls) {
862-
callSignatures.push(getSignatureFromCall(call));
863-
}
863+
callSignatures.push(getSignatureFromCalls(usage.calls));
864864
}
865865

866866
if (usage.constructs) {
867-
for (const construct of usage.constructs) {
868-
constructSignatures.push(getSignatureFromCall(construct));
869-
}
867+
constructSignatures.push(getSignatureFromCalls(usage.constructs));
870868
}
871869

872870
if (usage.stringIndex) {
@@ -882,6 +880,61 @@ namespace ts.codefix {
882880
}
883881
}
884882

883+
function combineUsages(usages: Usage[]): Usage {
884+
return {
885+
isNumber: usages.some(u => u.isNumber),
886+
isString: usages.some(u => u.isString),
887+
isNumberOrString: usages.some(u => u.isNumberOrString),
888+
candidateTypes: flatMap(usages, u => u.candidateTypes) as Type[],
889+
properties: undefined, // TODO
890+
calls: flatMap(usages, u => u.calls) as CallUsage[],
891+
constructs: flatMap(usages, u => u.constructs) as CallUsage[],
892+
numberIndex: forEach(usages, u => u.numberIndex),
893+
stringIndex: forEach(usages, u => u.stringIndex),
894+
candidateThisTypes: flatMap(usages, u => u.candidateThisTypes) as Type[],
895+
}
896+
}
897+
898+
function findBuiltinType(usage: Usage): Type[] {
899+
const builtins = [
900+
checker.getStringType(),
901+
checker.getNumberType(),
902+
checker.createArrayType(checker.getAnyType()),
903+
checker.createPromiseType(checker.getAnyType()),
904+
// checker.getFunctionType() // not sure what this was supposed to be good for.
905+
];
906+
const matches = builtins.filter(t => matchesAllPropertiesOf(t, usage));
907+
if (false && 0 < matches.length && matches.length < 3) {
908+
return matches;
909+
}
910+
return [];
911+
}
912+
913+
function matchesAllPropertiesOf(type: Type, usage: Usage) {
914+
if (!usage.properties) return false;
915+
let result = true;
916+
usage.properties.forEach((prop, name) => {
917+
const source = checker.getUnionType(inferFromUsage(prop));
918+
const target = checker.getTypeOfPropertyOfType(type, name as string);
919+
if (target && prop.calls) {
920+
const sigs = checker.getSignaturesOfType(target, ts.SignatureKind.Call);
921+
result = result && !!sigs.length && sigs.some(
922+
sig => checker.isTypeAssignableTo(
923+
getFunctionFromCalls(prop.calls!),
924+
checker.createAnonymousType(undefined!, createSymbolTable(), [sig], emptyArray, undefined, undefined)));
925+
}
926+
else {
927+
result = result && !!source && !!target && checker.isTypeAssignableTo(source, target);
928+
}
929+
});
930+
return result;
931+
}
932+
933+
934+
function getFunctionFromCalls(calls: CallUsage[]) {
935+
return checker.createAnonymousType(undefined!, createSymbolTable(), [getSignatureFromCalls(calls)], emptyArray, undefined, undefined);
936+
}
937+
885938
function getParameterTypeFromCalls(parameterIndex: number, calls: CallUsage[], isRestParameter: boolean) {
886939
let types: Type[] = [];
887940
if (calls) {
@@ -904,16 +957,20 @@ namespace ts.codefix {
904957
return undefined;
905958
}
906959

907-
function getSignatureFromCall(call: CallUsage): Signature {
960+
function getSignatureFromCalls(calls: CallUsage[]): Signature {
908961
const parameters: Symbol[] = [];
909-
for (let i = 0; i < call.argumentTypes.length; i++) {
962+
const length = Math.max(...calls.map(c => c.argumentTypes.length));
963+
for (let i = 0; i < length; i++) {
910964
const symbol = checker.createSymbol(SymbolFlags.FunctionScopedVariable, escapeLeadingUnderscores(`arg${i}`));
911-
symbol.type = checker.getWidenedType(checker.getBaseTypeOfLiteralType(call.argumentTypes[i]));
965+
symbol.type = unifyFromUsage(calls.map(call => call.argumentTypes[i] || checker.getUndefinedType()));
966+
if (calls.some(call => call.argumentTypes[i] === undefined)) {
967+
symbol.flags |= SymbolFlags.Optional;
968+
}
912969
parameters.push(symbol);
913970
}
914-
const returnType = unifyFromUsage(inferFromUsage(call.returnType), checker.getVoidType());
971+
const returnType = unifyFromUsage(inferFromUsage(combineUsages(calls.map(call => call.return_))), checker.getVoidType());
915972
// TODO: GH#18217
916-
return checker.createSignature(/*declaration*/ undefined!, /*typeParameters*/ undefined, /*thisParameter*/ undefined, parameters, returnType, /*typePredicate*/ undefined, call.argumentTypes.length, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
973+
return checker.createSignature(/*declaration*/ undefined!, /*typeParameters*/ undefined, /*thisParameter*/ undefined, parameters, returnType, /*typePredicate*/ undefined, length, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
917974
}
918975

919976
function addCandidateType(usage: Usage, type: Type | undefined) {

0 commit comments

Comments
 (0)