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.
This commit is contained in:
parent
0f215fd233
commit
d347b08a42
3 changed files with 75 additions and 14 deletions
|
@ -524,6 +524,9 @@ namespace ts {
|
|||
},
|
||||
getApparentType,
|
||||
getUnionType,
|
||||
isTypeAssignableTo: (source, target) => {
|
||||
return isTypeAssignableTo(source, target);
|
||||
},
|
||||
createAnonymousType,
|
||||
createSignature,
|
||||
createSymbol,
|
||||
|
|
|
@ -3286,6 +3286,7 @@ namespace ts {
|
|||
/* @internal */ getElementTypeOfArrayType(arrayType: Type): Type | undefined;
|
||||
/* @internal */ createPromiseType(type: Type): Type;
|
||||
|
||||
/* @internal */ isTypeAssignableTo(source: Type, target: Type): boolean;
|
||||
/* @internal */ createAnonymousType(symbol: Symbol, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexInfo: IndexInfo | undefined, numberIndexInfo: IndexInfo | undefined): Type;
|
||||
/* @internal */ createSignature(
|
||||
declaration: SignatureDeclaration,
|
||||
|
|
|
@ -401,7 +401,7 @@ namespace ts.codefix {
|
|||
|
||||
interface CallUsage {
|
||||
argumentTypes: Type[];
|
||||
returnType: Usage;
|
||||
return_: Usage;
|
||||
}
|
||||
|
||||
interface Usage {
|
||||
|
@ -671,16 +671,17 @@ namespace ts.codefix {
|
|||
function inferTypeFromCallExpression(parent: CallExpression | NewExpression, usage: Usage): void {
|
||||
const call: CallUsage = {
|
||||
argumentTypes: [],
|
||||
returnType: {}
|
||||
return_: {}
|
||||
};
|
||||
|
||||
if (parent.arguments) {
|
||||
for (const argument of parent.arguments) {
|
||||
// TODO: should recursively infer a usage here, right?
|
||||
call.argumentTypes.push(checker.getTypeAtLocation(argument));
|
||||
}
|
||||
}
|
||||
|
||||
calculateUsageOfNode(parent, call.returnType);
|
||||
calculateUsageOfNode(parent, call.return_);
|
||||
if (parent.kind === SyntaxKind.CallExpression) {
|
||||
(usage.calls || (usage.calls = [])).push(call);
|
||||
}
|
||||
|
@ -830,6 +831,7 @@ namespace ts.codefix {
|
|||
}
|
||||
|
||||
types.push(...(usage.candidateTypes || []).map(t => checker.getBaseTypeOfLiteralType(t)));
|
||||
types.push(...findBuiltinType(usage));
|
||||
|
||||
if (usage.properties && hasCalls(usage.properties.get("then" as __String))) {
|
||||
const paramType = getParameterTypeFromCalls(0, usage.properties.get("then" as __String)!.calls!, /*isRestParameter*/ false)!; // TODO: GH#18217
|
||||
|
@ -858,15 +860,11 @@ namespace ts.codefix {
|
|||
}
|
||||
|
||||
if (usage.calls) {
|
||||
for (const call of usage.calls) {
|
||||
callSignatures.push(getSignatureFromCall(call));
|
||||
}
|
||||
callSignatures.push(getSignatureFromCalls(usage.calls));
|
||||
}
|
||||
|
||||
if (usage.constructs) {
|
||||
for (const construct of usage.constructs) {
|
||||
constructSignatures.push(getSignatureFromCall(construct));
|
||||
}
|
||||
constructSignatures.push(getSignatureFromCalls(usage.constructs));
|
||||
}
|
||||
|
||||
if (usage.stringIndex) {
|
||||
|
@ -882,6 +880,61 @@ namespace ts.codefix {
|
|||
}
|
||||
}
|
||||
|
||||
function combineUsages(usages: Usage[]): Usage {
|
||||
return {
|
||||
isNumber: usages.some(u => u.isNumber),
|
||||
isString: usages.some(u => u.isString),
|
||||
isNumberOrString: usages.some(u => u.isNumberOrString),
|
||||
candidateTypes: flatMap(usages, u => u.candidateTypes) as Type[],
|
||||
properties: undefined, // TODO
|
||||
calls: flatMap(usages, u => u.calls) as CallUsage[],
|
||||
constructs: flatMap(usages, u => u.constructs) as CallUsage[],
|
||||
numberIndex: forEach(usages, u => u.numberIndex),
|
||||
stringIndex: forEach(usages, u => u.stringIndex),
|
||||
candidateThisTypes: flatMap(usages, u => u.candidateThisTypes) as Type[],
|
||||
}
|
||||
}
|
||||
|
||||
function findBuiltinType(usage: Usage): Type[] {
|
||||
const builtins = [
|
||||
checker.getStringType(),
|
||||
checker.getNumberType(),
|
||||
checker.createArrayType(checker.getAnyType()),
|
||||
checker.createPromiseType(checker.getAnyType()),
|
||||
// checker.getFunctionType() // not sure what this was supposed to be good for.
|
||||
];
|
||||
const matches = builtins.filter(t => matchesAllPropertiesOf(t, usage));
|
||||
if (false && 0 < matches.length && matches.length < 3) {
|
||||
return matches;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
function matchesAllPropertiesOf(type: Type, usage: Usage) {
|
||||
if (!usage.properties) return false;
|
||||
let result = true;
|
||||
usage.properties.forEach((prop, name) => {
|
||||
const source = checker.getUnionType(inferFromUsage(prop));
|
||||
const target = checker.getTypeOfPropertyOfType(type, name as string);
|
||||
if (target && prop.calls) {
|
||||
const sigs = checker.getSignaturesOfType(target, ts.SignatureKind.Call);
|
||||
result = result && !!sigs.length && sigs.some(
|
||||
sig => checker.isTypeAssignableTo(
|
||||
getFunctionFromCalls(prop.calls!),
|
||||
checker.createAnonymousType(undefined!, createSymbolTable(), [sig], emptyArray, undefined, undefined)));
|
||||
}
|
||||
else {
|
||||
result = result && !!source && !!target && checker.isTypeAssignableTo(source, target);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
function getFunctionFromCalls(calls: CallUsage[]) {
|
||||
return checker.createAnonymousType(undefined!, createSymbolTable(), [getSignatureFromCalls(calls)], emptyArray, undefined, undefined);
|
||||
}
|
||||
|
||||
function getParameterTypeFromCalls(parameterIndex: number, calls: CallUsage[], isRestParameter: boolean) {
|
||||
let types: Type[] = [];
|
||||
if (calls) {
|
||||
|
@ -904,16 +957,20 @@ namespace ts.codefix {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
function getSignatureFromCall(call: CallUsage): Signature {
|
||||
function getSignatureFromCalls(calls: CallUsage[]): Signature {
|
||||
const parameters: Symbol[] = [];
|
||||
for (let i = 0; i < call.argumentTypes.length; i++) {
|
||||
const length = Math.max(...calls.map(c => c.argumentTypes.length));
|
||||
for (let i = 0; i < length; i++) {
|
||||
const symbol = checker.createSymbol(SymbolFlags.FunctionScopedVariable, escapeLeadingUnderscores(`arg${i}`));
|
||||
symbol.type = checker.getWidenedType(checker.getBaseTypeOfLiteralType(call.argumentTypes[i]));
|
||||
symbol.type = unifyFromUsage(calls.map(call => call.argumentTypes[i] || checker.getUndefinedType()));
|
||||
if (calls.some(call => call.argumentTypes[i] === undefined)) {
|
||||
symbol.flags |= SymbolFlags.Optional;
|
||||
}
|
||||
parameters.push(symbol);
|
||||
}
|
||||
const returnType = unifyFromUsage(inferFromUsage(call.returnType), checker.getVoidType());
|
||||
const returnType = unifyFromUsage(inferFromUsage(combineUsages(calls.map(call => call.return_))), checker.getVoidType());
|
||||
// TODO: GH#18217
|
||||
return checker.createSignature(/*declaration*/ undefined!, /*typeParameters*/ undefined, /*thisParameter*/ undefined, parameters, returnType, /*typePredicate*/ undefined, call.argumentTypes.length, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
|
||||
return checker.createSignature(/*declaration*/ undefined!, /*typeParameters*/ undefined, /*thisParameter*/ undefined, parameters, returnType, /*typePredicate*/ undefined, length, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
|
||||
}
|
||||
|
||||
function addCandidateType(usage: Usage, type: Type | undefined) {
|
||||
|
|
Loading…
Reference in a new issue