From 3be6e75d6aee0c2a0a3be1b42ab84aa8c5c2e8ac Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Mon, 26 Aug 2019 11:13:17 -0700 Subject: [PATCH 01/17] Improve names in infer-from-usage Basically, drop "Context" from all names, because it just indicates that it's an implementation of the State monad. --- src/services/codefixes/inferFromUsage.ts | 238 +++++++++++------------ 1 file changed, 119 insertions(+), 119 deletions(-) diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index 396d7f44fa8..417ed5c625c 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -359,7 +359,7 @@ namespace ts.codefix { const references = getReferences(token, program, cancellationToken); const checker = program.getTypeChecker(); const types = InferFromReference.inferTypesFromReferences(references, checker, cancellationToken); - return InferFromReference.unifyFromContext(types, checker); + return InferFromReference.unifyFromUsage(types, checker); } function inferFunctionReferencesFromUsage(containingFunction: FunctionLike, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): ReadonlyArray | undefined { @@ -395,33 +395,33 @@ namespace ts.codefix { } namespace InferFromReference { - interface CallContext { + interface CallUsage { argumentTypes: Type[]; - returnType: UsageContext; + returnType: Usage; } - interface UsageContext { + interface Usage { isNumber?: boolean; isString?: boolean; /** Used ambiguously, eg x + ___ or object[___]; results in string | number if no other evidence exists */ isNumberOrString?: boolean; candidateTypes?: Type[]; - properties?: UnderscoreEscapedMap; - callContexts?: CallContext[]; - constructContexts?: CallContext[]; - numberIndexContext?: UsageContext; - stringIndexContext?: UsageContext; + properties?: UnderscoreEscapedMap; + calls?: CallUsage[]; + constructs?: CallUsage[]; + numberIndex?: Usage; + stringIndex?: Usage; candidateThisTypes?: Type[]; } export function inferTypesFromReferences(references: ReadonlyArray, checker: TypeChecker, cancellationToken: CancellationToken): Type[] { - const usageContext: UsageContext = {}; + const usage: Usage = {}; for (const reference of references) { cancellationToken.throwIfCancellationRequested(); - inferTypeFromContext(reference, checker, usageContext); + calculateUsageOfNode(reference, checker, usage); } - return inferFromContext(usageContext, checker); + return inferFromUsage(usage, checker); } export function inferTypeForParametersFromReferences(references: ReadonlyArray | undefined, declaration: FunctionLike, program: Program, cancellationToken: CancellationToken): ParameterInference[] | undefined { @@ -430,35 +430,35 @@ namespace ts.codefix { } const checker = program.getTypeChecker(); - const usageContext: UsageContext = {}; + const usage: Usage = {}; for (const reference of references) { cancellationToken.throwIfCancellationRequested(); - inferTypeFromContext(reference, checker, usageContext); + calculateUsageOfNode(reference, checker, usage); } - const callContexts = [...usageContext.constructContexts || [], ...usageContext.callContexts || []]; + const calls = [...usage.constructs || [], ...usage.calls || []]; return declaration.parameters.map((parameter, parameterIndex): ParameterInference => { const types = []; const isRest = isRestParameter(parameter); let isOptional = false; - for (const callContext of callContexts) { - if (callContext.argumentTypes.length <= parameterIndex) { + for (const call of calls) { + if (call.argumentTypes.length <= parameterIndex) { isOptional = isInJSFile(declaration); types.push(checker.getUndefinedType()); } else if (isRest) { - for (let i = parameterIndex; i < callContext.argumentTypes.length; i++) { - types.push(checker.getBaseTypeOfLiteralType(callContext.argumentTypes[i])); + for (let i = parameterIndex; i < call.argumentTypes.length; i++) { + types.push(checker.getBaseTypeOfLiteralType(call.argumentTypes[i])); } } else { - types.push(checker.getBaseTypeOfLiteralType(callContext.argumentTypes[parameterIndex])); + types.push(checker.getBaseTypeOfLiteralType(call.argumentTypes[parameterIndex])); } } if (isIdentifier(parameter.name)) { const inferred = inferTypesFromReferences(getReferences(parameter.name, program, cancellationToken), checker, cancellationToken); types.push(...(isRest ? mapDefined(inferred, checker.getElementTypeOfArrayType) : inferred)); } - const type = unifyFromContext(types, checker); + const type = unifyFromUsage(types, checker); return { type: isRest ? checker.createArrayType(type) : type, isOptional: isOptional && !isRest, @@ -473,89 +473,89 @@ namespace ts.codefix { } const checker = program.getTypeChecker(); - const usageContext: UsageContext = {}; + const usage: Usage = {}; for (const reference of references) { cancellationToken.throwIfCancellationRequested(); - inferTypeFromContext(reference, checker, usageContext); + calculateUsageOfNode(reference, checker, usage); } - return unifyFromContext(usageContext.candidateThisTypes || emptyArray, checker); + return unifyFromUsage(usage.candidateThisTypes || emptyArray, checker); } - function inferTypeFromContext(node: Expression, checker: TypeChecker, usageContext: UsageContext): void { + function calculateUsageOfNode(node: Expression, checker: TypeChecker, usage: Usage): void { while (isRightSideOfQualifiedNameOrPropertyAccess(node)) { node = node.parent; } switch (node.parent.kind) { case SyntaxKind.PostfixUnaryExpression: - usageContext.isNumber = true; + usage.isNumber = true; break; case SyntaxKind.PrefixUnaryExpression: - inferTypeFromPrefixUnaryExpressionContext(node.parent, usageContext); + inferTypeFromPrefixUnaryExpression(node.parent, usage); break; case SyntaxKind.BinaryExpression: - inferTypeFromBinaryExpressionContext(node, node.parent, checker, usageContext); + inferTypeFromBinaryExpression(node, node.parent, checker, usage); break; case SyntaxKind.CaseClause: case SyntaxKind.DefaultClause: - inferTypeFromSwitchStatementLabelContext(node.parent, checker, usageContext); + inferTypeFromSwitchStatementLabel(node.parent, checker, usage); break; case SyntaxKind.CallExpression: case SyntaxKind.NewExpression: if ((node.parent).expression === node) { - inferTypeFromCallExpressionContext(node.parent, checker, usageContext); + inferTypeFromCallExpression(node.parent, checker, usage); } else { - inferTypeFromContextualType(node, checker, usageContext); + inferTypeFromContextualType(node, checker, usage); } break; case SyntaxKind.PropertyAccessExpression: - inferTypeFromPropertyAccessExpressionContext(node.parent, checker, usageContext); + inferTypeFromPropertyAccessExpression(node.parent, checker, usage); break; case SyntaxKind.ElementAccessExpression: - inferTypeFromPropertyElementExpressionContext(node.parent, node, checker, usageContext); + inferTypeFromPropertyElementExpression(node.parent, node, checker, usage); break; case SyntaxKind.PropertyAssignment: case SyntaxKind.ShorthandPropertyAssignment: - inferTypeFromPropertyAssignment(node.parent, checker, usageContext); + inferTypeFromPropertyAssignment(node.parent, checker, usage); break; case SyntaxKind.PropertyDeclaration: - inferTypeFromPropertyDeclaration(node.parent, checker, usageContext); + inferTypeFromPropertyDeclaration(node.parent, checker, usage); break; case SyntaxKind.VariableDeclaration: { const { name, initializer } = node.parent as VariableDeclaration; if (node === name) { if (initializer) { // This can happen for `let x = null;` which still has an implicit-any error. - addCandidateType(usageContext, checker.getTypeAtLocation(initializer)); + addCandidateType(usage, checker.getTypeAtLocation(initializer)); } break; } } // falls through default: - return inferTypeFromContextualType(node, checker, usageContext); + return inferTypeFromContextualType(node, checker, usage); } } - function inferTypeFromContextualType(node: Expression, checker: TypeChecker, usageContext: UsageContext): void { + function inferTypeFromContextualType(node: Expression, checker: TypeChecker, usage: Usage): void { if (isExpressionNode(node)) { - addCandidateType(usageContext, checker.getContextualType(node)); + addCandidateType(usage, checker.getContextualType(node)); } } - function inferTypeFromPrefixUnaryExpressionContext(node: PrefixUnaryExpression, usageContext: UsageContext): void { + function inferTypeFromPrefixUnaryExpression(node: PrefixUnaryExpression, usage: Usage): void { switch (node.operator) { case SyntaxKind.PlusPlusToken: case SyntaxKind.MinusMinusToken: case SyntaxKind.MinusToken: case SyntaxKind.TildeToken: - usageContext.isNumber = true; + usage.isNumber = true; break; case SyntaxKind.PlusToken: - usageContext.isNumberOrString = true; + usage.isNumberOrString = true; break; // case SyntaxKind.ExclamationToken: @@ -563,7 +563,7 @@ namespace ts.codefix { } } - function inferTypeFromBinaryExpressionContext(node: Expression, parent: BinaryExpression, checker: TypeChecker, usageContext: UsageContext): void { + function inferTypeFromBinaryExpression(node: Expression, parent: BinaryExpression, checker: TypeChecker, usage: Usage): void { switch (parent.operatorToken.kind) { // ExponentiationOperator case SyntaxKind.AsteriskAsteriskToken: @@ -606,10 +606,10 @@ namespace ts.codefix { case SyntaxKind.GreaterThanEqualsToken: const operandType = checker.getTypeAtLocation(parent.left === node ? parent.right : parent.left); if (operandType.flags & TypeFlags.EnumLike) { - addCandidateType(usageContext, operandType); + addCandidateType(usage, operandType); } else { - usageContext.isNumber = true; + usage.isNumber = true; } break; @@ -617,16 +617,16 @@ namespace ts.codefix { case SyntaxKind.PlusToken: const otherOperandType = checker.getTypeAtLocation(parent.left === node ? parent.right : parent.left); if (otherOperandType.flags & TypeFlags.EnumLike) { - addCandidateType(usageContext, otherOperandType); + addCandidateType(usage, otherOperandType); } else if (otherOperandType.flags & TypeFlags.NumberLike) { - usageContext.isNumber = true; + usage.isNumber = true; } else if (otherOperandType.flags & TypeFlags.StringLike) { - usageContext.isString = true; + usage.isString = true; } else { - usageContext.isNumberOrString = true; + usage.isNumberOrString = true; } break; @@ -636,12 +636,12 @@ namespace ts.codefix { case SyntaxKind.EqualsEqualsEqualsToken: case SyntaxKind.ExclamationEqualsEqualsToken: case SyntaxKind.ExclamationEqualsToken: - addCandidateType(usageContext, checker.getTypeAtLocation(parent.left === node ? parent.right : parent.left)); + addCandidateType(usage, checker.getTypeAtLocation(parent.left === node ? parent.right : parent.left)); break; case SyntaxKind.InKeyword: if (node === parent.left) { - usageContext.isString = true; + usage.isString = true; } break; @@ -651,7 +651,7 @@ namespace ts.codefix { (node.parent.parent.kind === SyntaxKind.VariableDeclaration || isAssignmentExpression(node.parent.parent, /*excludeCompoundAssignment*/ true))) { // var x = x || {}; // TODO: use getFalsyflagsOfType - addCandidateType(usageContext, checker.getTypeAtLocation(parent.right)); + addCandidateType(usage, checker.getTypeAtLocation(parent.right)); } break; @@ -663,68 +663,68 @@ namespace ts.codefix { } } - function inferTypeFromSwitchStatementLabelContext(parent: CaseOrDefaultClause, checker: TypeChecker, usageContext: UsageContext): void { - addCandidateType(usageContext, checker.getTypeAtLocation(parent.parent.parent.expression)); + function inferTypeFromSwitchStatementLabel(parent: CaseOrDefaultClause, checker: TypeChecker, usage: Usage): void { + addCandidateType(usage, checker.getTypeAtLocation(parent.parent.parent.expression)); } - function inferTypeFromCallExpressionContext(parent: CallExpression | NewExpression, checker: TypeChecker, usageContext: UsageContext): void { - const callContext: CallContext = { + function inferTypeFromCallExpression(parent: CallExpression | NewExpression, checker: TypeChecker, usage: Usage): void { + const call: CallUsage = { argumentTypes: [], returnType: {} }; if (parent.arguments) { for (const argument of parent.arguments) { - callContext.argumentTypes.push(checker.getTypeAtLocation(argument)); + call.argumentTypes.push(checker.getTypeAtLocation(argument)); } } - inferTypeFromContext(parent, checker, callContext.returnType); + calculateUsageOfNode(parent, checker, call.returnType); if (parent.kind === SyntaxKind.CallExpression) { - (usageContext.callContexts || (usageContext.callContexts = [])).push(callContext); + (usage.calls || (usage.calls = [])).push(call); } else { - (usageContext.constructContexts || (usageContext.constructContexts = [])).push(callContext); + (usage.constructs || (usage.constructs = [])).push(call); } } - function inferTypeFromPropertyAccessExpressionContext(parent: PropertyAccessExpression, checker: TypeChecker, usageContext: UsageContext): void { + function inferTypeFromPropertyAccessExpression(parent: PropertyAccessExpression, checker: TypeChecker, usage: Usage): void { const name = escapeLeadingUnderscores(parent.name.text); - if (!usageContext.properties) { - usageContext.properties = createUnderscoreEscapedMap(); + if (!usage.properties) { + usage.properties = createUnderscoreEscapedMap(); } - const propertyUsageContext = usageContext.properties.get(name) || { }; - inferTypeFromContext(parent, checker, propertyUsageContext); - usageContext.properties.set(name, propertyUsageContext); + const propertyUsage = usage.properties.get(name) || { }; + calculateUsageOfNode(parent, checker, propertyUsage); + usage.properties.set(name, propertyUsage); } - function inferTypeFromPropertyElementExpressionContext(parent: ElementAccessExpression, node: Expression, checker: TypeChecker, usageContext: UsageContext): void { + function inferTypeFromPropertyElementExpression(parent: ElementAccessExpression, node: Expression, checker: TypeChecker, usage: Usage): void { if (node === parent.argumentExpression) { - usageContext.isNumberOrString = true; + usage.isNumberOrString = true; return; } else { const indexType = checker.getTypeAtLocation(parent.argumentExpression); - const indexUsageContext = {}; - inferTypeFromContext(parent, checker, indexUsageContext); + const indexUsage = {}; + calculateUsageOfNode(parent, checker, indexUsage); if (indexType.flags & TypeFlags.NumberLike) { - usageContext.numberIndexContext = indexUsageContext; + usage.numberIndex = indexUsage; } else { - usageContext.stringIndexContext = indexUsageContext; + usage.stringIndex = indexUsage; } } } - function inferTypeFromPropertyAssignment(assignment: PropertyAssignment | ShorthandPropertyAssignment, checker: TypeChecker, usageContext: UsageContext) { + function inferTypeFromPropertyAssignment(assignment: PropertyAssignment | ShorthandPropertyAssignment, checker: TypeChecker, usage: Usage) { const nodeWithRealType = isVariableDeclaration(assignment.parent.parent) ? assignment.parent.parent : assignment.parent; - addCandidateThisType(usageContext, checker.getTypeAtLocation(nodeWithRealType)); + addCandidateThisType(usage, checker.getTypeAtLocation(nodeWithRealType)); } - function inferTypeFromPropertyDeclaration(declaration: PropertyDeclaration, checker: TypeChecker, usageContext: UsageContext) { - addCandidateThisType(usageContext, checker.getTypeAtLocation(declaration.parent)); + function inferTypeFromPropertyDeclaration(declaration: PropertyDeclaration, checker: TypeChecker, usage: Usage) { + addCandidateThisType(usage, checker.getTypeAtLocation(declaration.parent)); } interface Priority { @@ -745,7 +745,7 @@ namespace ts.codefix { return inferences.filter(i => toRemove.every(f => !f(i))); } - export function unifyFromContext(inferences: ReadonlyArray, checker: TypeChecker, fallback = checker.getAnyType()): Type { + export function unifyFromUsage(inferences: ReadonlyArray, checker: TypeChecker, fallback = checker.getAnyType()): Type { if (!inferences.length) return fallback; // 1. string or number individually override string | number @@ -815,82 +815,82 @@ namespace ts.codefix { numberIndices.length ? checker.createIndexInfo(checker.getUnionType(numberIndices), numberIndexReadonly) : undefined); } - function inferFromContext(usageContext: UsageContext, checker: TypeChecker) { + function inferFromUsage(usage: Usage, checker: TypeChecker) { const types = []; - if (usageContext.isNumber) { + if (usage.isNumber) { types.push(checker.getNumberType()); } - if (usageContext.isString) { + if (usage.isString) { types.push(checker.getStringType()); } - if (usageContext.isNumberOrString) { + if (usage.isNumberOrString) { types.push(checker.getUnionType([checker.getStringType(), checker.getNumberType()])); } - types.push(...(usageContext.candidateTypes || []).map(t => checker.getBaseTypeOfLiteralType(t))); + types.push(...(usage.candidateTypes || []).map(t => checker.getBaseTypeOfLiteralType(t))); - if (usageContext.properties && hasCallContext(usageContext.properties.get("then" as __String))) { - const paramType = getParameterTypeFromCallContexts(0, usageContext.properties.get("then" as __String)!.callContexts!, /*isRestParameter*/ false, checker)!; // TODO: GH#18217 + if (usage.properties && hasCalls(usage.properties.get("then" as __String))) { + const paramType = getParameterTypeFromCalls(0, usage.properties.get("then" as __String)!.calls!, /*isRestParameter*/ false, checker)!; // TODO: GH#18217 const types = paramType.getCallSignatures().map(c => c.getReturnType()); types.push(checker.createPromiseType(types.length ? checker.getUnionType(types, UnionReduction.Subtype) : checker.getAnyType())); } - else if (usageContext.properties && hasCallContext(usageContext.properties.get("push" as __String))) { - types.push(checker.createArrayType(getParameterTypeFromCallContexts(0, usageContext.properties.get("push" as __String)!.callContexts!, /*isRestParameter*/ false, checker)!)); + else if (usage.properties && hasCalls(usage.properties.get("push" as __String))) { + types.push(checker.createArrayType(getParameterTypeFromCalls(0, usage.properties.get("push" as __String)!.calls!, /*isRestParameter*/ false, checker)!)); } - if (usageContext.numberIndexContext) { - types.push(checker.createArrayType(recur(usageContext.numberIndexContext))); + if (usage.numberIndex) { + types.push(checker.createArrayType(recur(usage.numberIndex))); } - else if (usageContext.properties || usageContext.callContexts || usageContext.constructContexts || usageContext.stringIndexContext) { + else if (usage.properties || usage.calls || usage.constructs || usage.stringIndex) { const members = createUnderscoreEscapedMap(); const callSignatures: Signature[] = []; const constructSignatures: Signature[] = []; let stringIndexInfo: IndexInfo | undefined; - if (usageContext.properties) { - usageContext.properties.forEach((context, name) => { + if (usage.properties) { + usage.properties.forEach((u, name) => { const symbol = checker.createSymbol(SymbolFlags.Property, name); - symbol.type = recur(context); + symbol.type = recur(u); members.set(name, symbol); }); } - if (usageContext.callContexts) { - for (const callContext of usageContext.callContexts) { - callSignatures.push(getSignatureFromCallContext(callContext, checker)); + if (usage.calls) { + for (const call of usage.calls) { + callSignatures.push(getSignatureFromCall(call, checker)); } } - if (usageContext.constructContexts) { - for (const constructContext of usageContext.constructContexts) { - constructSignatures.push(getSignatureFromCallContext(constructContext, checker)); + if (usage.constructs) { + for (const construct of usage.constructs) { + constructSignatures.push(getSignatureFromCall(construct, checker)); } } - if (usageContext.stringIndexContext) { - stringIndexInfo = checker.createIndexInfo(recur(usageContext.stringIndexContext), /*isReadonly*/ false); + if (usage.stringIndex) { + stringIndexInfo = checker.createIndexInfo(recur(usage.stringIndex), /*isReadonly*/ false); } types.push(checker.createAnonymousType(/*symbol*/ undefined!, members, callSignatures, constructSignatures, stringIndexInfo, /*numberIndexInfo*/ undefined)); // TODO: GH#18217 } return types; - function recur(innerContext: UsageContext): Type { - return unifyFromContext(inferFromContext(innerContext, checker), checker); + function recur(innerUsage: Usage): Type { + return unifyFromUsage(inferFromUsage(innerUsage, checker), checker); } } - function getParameterTypeFromCallContexts(parameterIndex: number, callContexts: CallContext[], isRestParameter: boolean, checker: TypeChecker) { + function getParameterTypeFromCalls(parameterIndex: number, calls: CallUsage[], isRestParameter: boolean, checker: TypeChecker) { let types: Type[] = []; - if (callContexts) { - for (const callContext of callContexts) { - if (callContext.argumentTypes.length > parameterIndex) { + if (calls) { + for (const call of calls) { + if (call.argumentTypes.length > parameterIndex) { if (isRestParameter) { - types = concatenate(types, map(callContext.argumentTypes.slice(parameterIndex), a => checker.getBaseTypeOfLiteralType(a))); + types = concatenate(types, map(call.argumentTypes.slice(parameterIndex), a => checker.getBaseTypeOfLiteralType(a))); } else { - types.push(checker.getBaseTypeOfLiteralType(callContext.argumentTypes[parameterIndex])); + types.push(checker.getBaseTypeOfLiteralType(call.argumentTypes[parameterIndex])); } } } @@ -903,32 +903,32 @@ namespace ts.codefix { return undefined; } - function getSignatureFromCallContext(callContext: CallContext, checker: TypeChecker): Signature { + function getSignatureFromCall(call: CallUsage, checker: TypeChecker): Signature { const parameters: Symbol[] = []; - for (let i = 0; i < callContext.argumentTypes.length; i++) { + for (let i = 0; i < call.argumentTypes.length; i++) { const symbol = checker.createSymbol(SymbolFlags.FunctionScopedVariable, escapeLeadingUnderscores(`arg${i}`)); - symbol.type = checker.getWidenedType(checker.getBaseTypeOfLiteralType(callContext.argumentTypes[i])); + symbol.type = checker.getWidenedType(checker.getBaseTypeOfLiteralType(call.argumentTypes[i])); parameters.push(symbol); } - const returnType = unifyFromContext(inferFromContext(callContext.returnType, checker), checker, checker.getVoidType()); + const returnType = unifyFromUsage(inferFromUsage(call.returnType, checker), checker, checker.getVoidType()); // TODO: GH#18217 - return checker.createSignature(/*declaration*/ undefined!, /*typeParameters*/ undefined, /*thisParameter*/ undefined, parameters, returnType, /*typePredicate*/ undefined, callContext.argumentTypes.length, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); + return checker.createSignature(/*declaration*/ undefined!, /*typeParameters*/ undefined, /*thisParameter*/ undefined, parameters, returnType, /*typePredicate*/ undefined, call.argumentTypes.length, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); } - function addCandidateType(context: UsageContext, type: Type | undefined) { + function addCandidateType(usage: Usage, type: Type | undefined) { if (type && !(type.flags & TypeFlags.Any) && !(type.flags & TypeFlags.Never)) { - (context.candidateTypes || (context.candidateTypes = [])).push(type); + (usage.candidateTypes || (usage.candidateTypes = [])).push(type); } } - function addCandidateThisType(context: UsageContext, type: Type | undefined) { + function addCandidateThisType(usage: Usage, type: Type | undefined) { if (type && !(type.flags & TypeFlags.Any) && !(type.flags & TypeFlags.Never)) { - (context.candidateThisTypes || (context.candidateThisTypes = [])).push(type); + (usage.candidateThisTypes || (usage.candidateThisTypes = [])).push(type); } } - function hasCallContext(usageContext: UsageContext | undefined): boolean { - return !!usageContext && !!usageContext.callContexts; + function hasCalls(usage: Usage | undefined): boolean { + return !!usage && !!usage.calls; } } } From d347b08a42bb705415fe8b859a69697c1d155a59 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 27 Aug 2019 13:13:58 -0700 Subject: [PATCH 02/17] 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. --- src/compiler/checker.ts | 3 + src/compiler/types.ts | 1 + src/services/codefixes/inferFromUsage.ts | 85 ++++++++++++++++++++---- 3 files changed, 75 insertions(+), 14 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cfd83efeb31..1b6fee6f0de 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -524,6 +524,9 @@ namespace ts { }, getApparentType, getUnionType, + isTypeAssignableTo: (source, target) => { + return isTypeAssignableTo(source, target); + }, createAnonymousType, createSignature, createSymbol, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 2c8a882c164..6e92eba8ded 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -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, diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index 2eb9eaca7b7..4b111dae25b 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -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) { From 945d423ef5b511ae157b15849b2b822de4b48953 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Wed, 28 Aug 2019 14:12:21 -0700 Subject: [PATCH 03/17] Fix bugs in combineUsages/getSignatureFromCalls --- src/services/codefixes/inferFromUsage.ts | 76 +++++++++++++++++------- 1 file changed, 56 insertions(+), 20 deletions(-) diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index 4b111dae25b..92382c462fa 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -405,18 +405,19 @@ namespace ts.codefix { } interface Usage { - isNumber?: boolean; - isString?: boolean; + isNumber: boolean | undefined; + isString: boolean | undefined; /** Used ambiguously, eg x + ___ or object[___]; results in string | number if no other evidence exists */ - isNumberOrString?: boolean; + isNumberOrString: boolean | undefined; - candidateTypes?: Type[]; - properties?: UnderscoreEscapedMap; - calls?: CallUsage[]; - constructs?: CallUsage[]; - numberIndex?: Usage; - stringIndex?: Usage; - candidateThisTypes?: Type[]; + candidateTypes: Type[] | undefined; + properties: UnderscoreEscapedMap | undefined; + calls: CallUsage[] | undefined; + constructs: CallUsage[] | undefined; + numberIndex: Usage | undefined; + stringIndex: Usage | undefined; + candidateThisTypes: Type[] | undefined; + inferredTypes: Type[] | undefined; } function single(): Type { @@ -428,7 +429,7 @@ namespace ts.codefix { return undefined; } - const usage: Usage = {}; + const usage = createEmptyUsage(); for (const reference of references) { cancellationToken.throwIfCancellationRequested(); calculateUsageOfNode(reference, usage); @@ -466,7 +467,7 @@ namespace ts.codefix { } function thisParameter() { - const usage: Usage = {}; + const usage = createEmptyUsage(); for (const reference of references) { cancellationToken.throwIfCancellationRequested(); calculateUsageOfNode(reference, usage); @@ -476,7 +477,7 @@ namespace ts.codefix { } function inferTypesFromReferencesSingle(references: readonly Identifier[]): Type[] { - const usage: Usage = {}; + const usage: Usage = createEmptyUsage(); for (const reference of references) { cancellationToken.throwIfCancellationRequested(); calculateUsageOfNode(reference, usage); @@ -671,7 +672,7 @@ namespace ts.codefix { function inferTypeFromCallExpression(parent: CallExpression | NewExpression, usage: Usage): void { const call: CallUsage = { argumentTypes: [], - return_: {} + return_: createEmptyUsage() }; if (parent.arguments) { @@ -695,7 +696,7 @@ namespace ts.codefix { if (!usage.properties) { usage.properties = createUnderscoreEscapedMap(); } - const propertyUsage = usage.properties.get(name) || { }; + const propertyUsage = usage.properties.get(name) || createEmptyUsage(); calculateUsageOfNode(parent, propertyUsage); usage.properties.set(name, propertyUsage); } @@ -707,7 +708,7 @@ namespace ts.codefix { } else { const indexType = checker.getTypeAtLocation(parent.argumentExpression); - const indexUsage = {}; + const indexUsage = createEmptyUsage(); calculateUsageOfNode(parent, indexUsage); if (indexType.flags & TypeFlags.NumberLike) { usage.numberIndex = indexUsage; @@ -845,7 +846,10 @@ namespace ts.codefix { if (usage.numberIndex) { types.push(checker.createArrayType(recur(usage.numberIndex))); } - else if (usage.properties || usage.calls || usage.constructs || usage.stringIndex) { + else if (usage.properties && usage.properties.size + || usage.calls && usage.calls.length + || usage.constructs && usage.constructs.length + || usage.stringIndex) { const members = createUnderscoreEscapedMap(); const callSignatures: Signature[] = []; const constructSignatures: Signature[] = []; @@ -873,25 +877,57 @@ namespace ts.codefix { types.push(checker.createAnonymousType(/*symbol*/ undefined!, members, callSignatures, constructSignatures, stringIndexInfo, /*numberIndexInfo*/ undefined)); // TODO: GH#18217 } - return types; + return types; // TODO: Should cache this since I HOPE it doesn't change function recur(innerUsage: Usage): Type { return unifyFromUsage(inferFromUsage(innerUsage)); } } + function createEmptyUsage(): Usage { + return { + isNumber: undefined, + isString: undefined, + isNumberOrString: undefined, + candidateTypes: undefined, + properties: undefined, + calls: undefined, + constructs: undefined, + numberIndex: undefined, + stringIndex: undefined, + candidateThisTypes: undefined, + inferredTypes: undefined, + } + } + function combineUsages(usages: Usage[]): Usage { + const combinedProperties = createUnderscoreEscapedMap() + for (const u of usages) { + if (u.properties) { + u.properties.forEach((p,name) => { + if (!combinedProperties.has(name)) { + combinedProperties.set(name, []); + } + combinedProperties.get(name)!.push(p); + }); + } + } + const properties = createUnderscoreEscapedMap() + combinedProperties.forEach((ps,name) => { + properties.set(name, combineUsages(ps)); + }); 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 + properties, 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[], + inferredTypes: undefined, // clear type cache } } @@ -901,7 +937,7 @@ namespace ts.codefix { checker.getNumberType(), checker.createArrayType(checker.getAnyType()), checker.createPromiseType(checker.getAnyType()), - // checker.getFunctionType() // not sure what this was supposed to be good for. + // checker.getFunctionType() // TODO: 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) { From 37150d9cb548e6e7802b731e8c03a298434e18d7 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Thu, 29 Aug 2019 12:40:33 -0700 Subject: [PATCH 04/17] Turn on findBuiltinTypes Type parameter inference is special-cased, just moved from its previous place with no improvement. --- src/services/codefixes/inferFromUsage.ts | 103 +++++++++--------- .../codeFixInferFromFunctionUsage.ts | 4 +- .../codeFixInferFromPrimitiveUsage.ts | 9 ++ .../codeFixInferFromUsageCallBodyBoth.ts | 2 +- 4 files changed, 65 insertions(+), 53 deletions(-) create mode 100644 tests/cases/fourslash/codeFixInferFromPrimitiveUsage.ts diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index 92382c462fa..ab1c2a4a52d 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -421,7 +421,7 @@ namespace ts.codefix { } function single(): Type { - return unifyFromUsage(inferTypesFromReferencesSingle(references)); + return unifyTypes(inferTypesFromReferencesSingle(references)); } function parameters(declaration: FunctionLike): ParameterInference[] | undefined { @@ -457,7 +457,7 @@ namespace ts.codefix { const inferred = inferTypesFromReferencesSingle(getReferences(parameter.name, program, cancellationToken)); types.push(...(isRest ? mapDefined(inferred, checker.getElementTypeOfArrayType) : inferred)); } - const type = unifyFromUsage(types); + const type = unifyTypes(types); return { type: isRest ? checker.createArrayType(type) : type, isOptional: isOptional && !isRest, @@ -473,7 +473,7 @@ namespace ts.codefix { calculateUsageOfNode(reference, usage); } - return unifyFromUsage(usage.candidateThisTypes || emptyArray); + return unifyTypes(usage.candidateThisTypes || emptyArray); } function inferTypesFromReferencesSingle(references: readonly Identifier[]): Type[] { @@ -627,6 +627,9 @@ namespace ts.codefix { else if (otherOperandType.flags & TypeFlags.StringLike) { usage.isString = true; } + else if (otherOperandType.flags & TypeFlags.Any) { + // do nothing, maybe we'll learn something elsewhere + } else { usage.isNumberOrString = true; } @@ -748,7 +751,7 @@ namespace ts.codefix { return inferences.filter(i => toRemove.every(f => !f(i))); } - function unifyFromUsage(inferences: ReadonlyArray, fallback = checker.getAnyType()): Type { + function unifyTypes(inferences: ReadonlyArray, fallback = checker.getAnyType()): Type { if (!inferences.length) return fallback; // 1. string or number individually override string | number @@ -774,7 +777,7 @@ namespace ts.codefix { good = good.filter(i => !(checker.getObjectFlags(i) & ObjectFlags.Anonymous)); good.push(unifyAnonymousTypes(anons)); } - return checker.getWidenedType(checker.getUnionType(good)); + return checker.getWidenedType(checker.getUnionType(good, UnionReduction.Subtype)); } function unifyAnonymousTypes(anons: AnonymousType[]) { @@ -832,16 +835,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 - const types = paramType.getCallSignatures().map(sig => sig.getReturnType()); - types.push(checker.createPromiseType(types.length ? checker.getUnionType(types, UnionReduction.Subtype) : checker.getAnyType())); - } - else if (usage.properties && hasCalls(usage.properties.get("push" as __String))) { - types.push(checker.createArrayType(getParameterTypeFromCalls(0, usage.properties.get("push" as __String)!.calls!, /*isRestParameter*/ false)!)); - } + types.push(...findBuiltinTypes(usage)); if (usage.numberIndex) { types.push(checker.createArrayType(recur(usage.numberIndex))); @@ -864,11 +858,12 @@ namespace ts.codefix { } if (usage.calls) { - callSignatures.push(getSignatureFromCalls(usage.calls)); + callSignatures.push(getSignatureFromCalls(usage.calls, checker.getVoidType())); } if (usage.constructs) { - constructSignatures.push(getSignatureFromCalls(usage.constructs)); + // TODO: fallback return should maybe be {}? + constructSignatures.push(getSignatureFromCalls(usage.constructs, checker.getVoidType())); } if (usage.stringIndex) { @@ -880,7 +875,7 @@ namespace ts.codefix { return types; // TODO: Should cache this since I HOPE it doesn't change function recur(innerUsage: Usage): Type { - return unifyFromUsage(inferFromUsage(innerUsage)); + return unifyTypes(inferFromUsage(innerUsage)); } } @@ -931,7 +926,8 @@ namespace ts.codefix { } } - function findBuiltinType(usage: Usage): Type[] { + function findBuiltinTypes(usage: Usage): Type[] { + if (!usage.properties || !usage.properties.size) return []; const builtins = [ checker.getStringType(), checker.getNumberType(), @@ -939,9 +935,21 @@ namespace ts.codefix { checker.createPromiseType(checker.getAnyType()), // checker.getFunctionType() // TODO: not sure what this was supposed to be good for. ]; + // TODO: Still need to infer type parameters const matches = builtins.filter(t => matchesAllPropertiesOf(t, usage)); - if (false && 0 < matches.length && matches.length < 3) { - return matches; + if (0 < matches.length && matches.length < 3) { + return matches.map(m => { + // special-case array and promise for now + if (m === builtins[3] && hasCalls(usage.properties!.get("then" as __String))) { + const paramType = getParameterTypeFromCalls(0, usage.properties!.get("then" as __String)!.calls!, /*isRestParameter*/ false)!; // TODO: GH#18217 + const returns = paramType.getCallSignatures().map(sig => sig.getReturnType()); + return checker.createPromiseType(returns.length ? checker.getUnionType(returns, UnionReduction.Subtype) : checker.getAnyType()); + } + else if (m === builtins[2] && hasCalls(usage.properties!.get("push" as __String))) { + return checker.createArrayType(getParameterTypeFromCalls(0, usage.properties!.get("push" as __String)!.calls!, /*isRestParameter*/ false)!); + } + return m; + }); } return []; } @@ -949,18 +957,18 @@ namespace ts.codefix { 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))); + usage.properties.forEach((propUsage, name) => { + const source = checker.getTypeOfPropertyOfType(type, name as string); + if (!source) { + result = false; + return; + } + if (propUsage.calls) { + const sigs = checker.getSignaturesOfType(source, ts.SignatureKind.Call); + result = result && !!sigs.length && checker.isTypeAssignableTo(source, getFunctionFromCalls(propUsage.calls)); } else { - result = result && !!source && !!target && checker.isTypeAssignableTo(source, target); + result = result && checker.isTypeAssignableTo(source, unifyTypes(inferFromUsage(propUsage))); } }); return result; @@ -968,43 +976,38 @@ namespace ts.codefix { function getFunctionFromCalls(calls: CallUsage[]) { - return checker.createAnonymousType(undefined!, createSymbolTable(), [getSignatureFromCalls(calls)], emptyArray, undefined, undefined); + return checker.createAnonymousType(undefined!, createSymbolTable(), [getSignatureFromCalls(calls, checker.getAnyType())], emptyArray, undefined, undefined); } function getParameterTypeFromCalls(parameterIndex: number, calls: CallUsage[], isRestParameter: boolean) { + // TODO: This is largely redundant with getSignatureFromCalls, I think. (though it handles rest parameters correctly, so that needs to be integrated there) let types: Type[] = []; - if (calls) { - for (const call of calls) { - if (call.argumentTypes.length > parameterIndex) { - if (isRestParameter) { - types = concatenate(types, map(call.argumentTypes.slice(parameterIndex), a => checker.getBaseTypeOfLiteralType(a))); - } - else { - types.push(checker.getBaseTypeOfLiteralType(call.argumentTypes[parameterIndex])); - } + for (const call of calls) { + if (call.argumentTypes.length > parameterIndex) { + if (isRestParameter) { + types = concatenate(types, map(call.argumentTypes.slice(parameterIndex), a => checker.getBaseTypeOfLiteralType(a))); + } + else { + types.push(checker.getBaseTypeOfLiteralType(call.argumentTypes[parameterIndex])); } } } - - if (types.length) { - const type = checker.getWidenedType(checker.getUnionType(types, UnionReduction.Subtype)); - return isRestParameter ? checker.createArrayType(type) : type; - } - return undefined; + const type = unifyTypes(types); + return isRestParameter ? checker.createArrayType(type) : type; } - function getSignatureFromCalls(calls: CallUsage[]): Signature { + function getSignatureFromCalls(calls: CallUsage[], fallbackReturn: Type): Signature { const parameters: Symbol[] = []; 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 = unifyFromUsage(calls.map(call => call.argumentTypes[i] || checker.getUndefinedType())); + symbol.type = unifyTypes(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(combineUsages(calls.map(call => call.return_))), checker.getVoidType()); + const returnType = unifyTypes(inferFromUsage(combineUsages(calls.map(call => call.return_))), fallbackReturn); // TODO: GH#18217 return checker.createSignature(/*declaration*/ undefined!, /*typeParameters*/ undefined, /*thisParameter*/ undefined, parameters, returnType, /*typePredicate*/ undefined, length, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); } diff --git a/tests/cases/fourslash/codeFixInferFromFunctionUsage.ts b/tests/cases/fourslash/codeFixInferFromFunctionUsage.ts index 27a039878ba..f2dbad67b4b 100644 --- a/tests/cases/fourslash/codeFixInferFromFunctionUsage.ts +++ b/tests/cases/fourslash/codeFixInferFromFunctionUsage.ts @@ -2,8 +2,8 @@ // @noImplicitAny: true ////function wrap( [| arr |] ) { -//// arr.sort(function (a: number, b: number) { return a < b ? -1 : 1 }) +//// arr.other(function (a: number, b: number) { return a < b ? -1 : 1 }) //// } // https://github.com/Microsoft/TypeScript/issues/29330 -verify.rangeAfterCodeFix("arr: { sort: (arg0: (a: number, b: number) => 1 | -1) => void; }"); +verify.rangeAfterCodeFix("arr: { other: (arg0: (a: number, b: number) => 1 | -1) => void; }"); diff --git a/tests/cases/fourslash/codeFixInferFromPrimitiveUsage.ts b/tests/cases/fourslash/codeFixInferFromPrimitiveUsage.ts new file mode 100644 index 00000000000..81c25770085 --- /dev/null +++ b/tests/cases/fourslash/codeFixInferFromPrimitiveUsage.ts @@ -0,0 +1,9 @@ +/// + +// @noImplicitAny: true +////function wrap( [| s |] ) { +//// return s.length + s.toUpperCase() +//// } + +// https://github.com/Microsoft/TypeScript/issues/29330 +verify.rangeAfterCodeFix("s: string"); diff --git a/tests/cases/fourslash/codeFixInferFromUsageCallBodyBoth.ts b/tests/cases/fourslash/codeFixInferFromUsageCallBodyBoth.ts index 859d5ea2ce7..f59d1bc1907 100644 --- a/tests/cases/fourslash/codeFixInferFromUsageCallBodyBoth.ts +++ b/tests/cases/fourslash/codeFixInferFromUsageCallBodyBoth.ts @@ -1,7 +1,7 @@ /// ////class C { -//// +//// p = 2 ////} ////var c = new C() ////function f([|x, y |]) { From 383286ff533aad1e9fe3bfa907ef84689eff920e Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Fri, 30 Aug 2019 13:44:06 -0700 Subject: [PATCH 05/17] Add type parameter inference It's a smeary copy of the checker's type parameter, so I feel bad about duplicating that code. Not sure what the solution is, architecturally. --- src/services/codefixes/inferFromUsage.ts | 132 ++++++++++++------ .../codeFixInferFromPrimitiveUsage.ts | 7 +- 2 files changed, 94 insertions(+), 45 deletions(-) diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index ab1c2a4a52d..0a190e7b379 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -393,6 +393,19 @@ namespace ts.codefix { function inferTypeFromReferences(program: Program, references: ReadonlyArray, cancellationToken: CancellationToken) { const checker = program.getTypeChecker(); + const builtinConstructors: { [s: string]: (t: Type) => Type } = { + string: () => checker.getStringType(), + number: () => checker.getNumberType(), + Array: t => checker.createArrayType(t), + Promise: t => checker.createPromiseType(t), + }; + const builtins = [ + checker.getStringType(), + checker.getNumberType(), + checker.createArrayType(checker.getAnyType()), + checker.createPromiseType(checker.getAnyType()), + ]; + return { single, parameters, @@ -777,7 +790,7 @@ namespace ts.codefix { good = good.filter(i => !(checker.getObjectFlags(i) & ObjectFlags.Anonymous)); good.push(unifyAnonymousTypes(anons)); } - return checker.getWidenedType(checker.getUnionType(good, UnionReduction.Subtype)); + return checker.getWidenedType(checker.getUnionType(good.map(checker.getBaseTypeOfLiteralType), UnionReduction.Subtype)); } function unifyAnonymousTypes(anons: AnonymousType[]) { @@ -928,28 +941,9 @@ namespace ts.codefix { function findBuiltinTypes(usage: Usage): Type[] { if (!usage.properties || !usage.properties.size) return []; - const builtins = [ - checker.getStringType(), - checker.getNumberType(), - checker.createArrayType(checker.getAnyType()), - checker.createPromiseType(checker.getAnyType()), - // checker.getFunctionType() // TODO: not sure what this was supposed to be good for. - ]; - // TODO: Still need to infer type parameters const matches = builtins.filter(t => matchesAllPropertiesOf(t, usage)); if (0 < matches.length && matches.length < 3) { - return matches.map(m => { - // special-case array and promise for now - if (m === builtins[3] && hasCalls(usage.properties!.get("then" as __String))) { - const paramType = getParameterTypeFromCalls(0, usage.properties!.get("then" as __String)!.calls!, /*isRestParameter*/ false)!; // TODO: GH#18217 - const returns = paramType.getCallSignatures().map(sig => sig.getReturnType()); - return checker.createPromiseType(returns.length ? checker.getUnionType(returns, UnionReduction.Subtype) : checker.getAnyType()); - } - else if (m === builtins[2] && hasCalls(usage.properties!.get("push" as __String))) { - return checker.createArrayType(getParameterTypeFromCalls(0, usage.properties!.get("push" as __String)!.calls!, /*isRestParameter*/ false)!); - } - return m; - }); + return matches.map(m => inferTypeParameterFromUsage(m, usage)); } return []; } @@ -974,28 +968,86 @@ namespace ts.codefix { return result; } + // inference is limited to + // 1. generic types with a single parameter + // 2. inference to/from calls with a single signature + function inferTypeParameterFromUsage(type: Type, usage: Usage) { + if (!usage.properties || !(getObjectFlags(type) & ObjectFlags.Reference)) return type; + const generic = (type as TypeReference).target; + const singleTypeParameter = singleOrUndefined(generic.typeParameters); + if (!singleTypeParameter) return type; + + const types: Type[] = []; + usage.properties.forEach((propUsage, name) => { + const source = checker.getTypeOfPropertyOfType(generic, name as string); + if (!source) { + return Debug.fail("generic should have all the properties of its reference."); + } + if (!propUsage.calls) return; + + types.push(...infer(source, getFunctionFromCalls(propUsage.calls), singleTypeParameter)); + }); + return builtinConstructors[type.symbol.escapedName as string](unifyTypes(types)); + } + + // TODO: Source and target are bad names. Should be builtinType and usageType...or something + // and search is a bad name + function infer(source: Type, target: Type, search: Type): readonly Type[] { + if (source === search) { + return [target]; + } + else if (source.flags & TypeFlags.UnionOrIntersection) { + return flatMap((source as UnionOrIntersectionType).types, t => infer(t, target, search)); + } + else if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference) { + // this is wrong because we need a reference to the targetType to, so we can check that it's also a reference + const sourceArgs = (source as TypeReference).typeArguments; + const targetArgs = (target as TypeReference).typeArguments; + const types = []; + if (sourceArgs && targetArgs) { + for (let i = 0; i < sourceArgs.length; i++) { + if (targetArgs[i]) { + types.push(...infer(sourceArgs[i], targetArgs[i], search)); + } + } + } + return types; + } + const sourceSigs = checker.getSignaturesOfType(source, SignatureKind.Call); + const targetSigs = checker.getSignaturesOfType(target, SignatureKind.Call); + if (sourceSigs.length === 1 && targetSigs.length === 1) { + return inferFromSignatures(sourceSigs[0], targetSigs[0], search); + } + return []; + } + + function inferFromSignatures(sourceSig: Signature, targetSig: Signature, search: Type) { + const types = []; + for (let i = 0; i < sourceSig.parameters.length; i++) { + const sourceParam = sourceSig.parameters[i]; + const targetParam = targetSig.parameters[i]; + const isRest = sourceSig.declaration && isRestParameter(sourceSig.declaration.parameters[i]); + if (!targetParam) { + break; + } + let sourceType = checker.getTypeOfSymbolAtLocation(sourceParam, sourceParam.valueDeclaration); + let elementType = isRest && checker.getElementTypeOfArrayType(sourceType); + if (elementType) { + sourceType = elementType; + } + const targetType = (targetParam as SymbolLinks).type || checker.getTypeOfSymbolAtLocation(targetParam, targetParam.valueDeclaration); + types.push(...infer(sourceType, targetType, search)); + } + const sourceReturn = checker.getReturnTypeOfSignature(sourceSig); + const targetReturn = checker.getReturnTypeOfSignature(targetSig); + types.push(...infer(sourceReturn, targetReturn, search)); + return types; + } function getFunctionFromCalls(calls: CallUsage[]) { return checker.createAnonymousType(undefined!, createSymbolTable(), [getSignatureFromCalls(calls, checker.getAnyType())], emptyArray, undefined, undefined); } - function getParameterTypeFromCalls(parameterIndex: number, calls: CallUsage[], isRestParameter: boolean) { - // TODO: This is largely redundant with getSignatureFromCalls, I think. (though it handles rest parameters correctly, so that needs to be integrated there) - let types: Type[] = []; - for (const call of calls) { - if (call.argumentTypes.length > parameterIndex) { - if (isRestParameter) { - types = concatenate(types, map(call.argumentTypes.slice(parameterIndex), a => checker.getBaseTypeOfLiteralType(a))); - } - else { - types.push(checker.getBaseTypeOfLiteralType(call.argumentTypes[parameterIndex])); - } - } - } - const type = unifyTypes(types); - return isRestParameter ? checker.createArrayType(type) : type; - } - function getSignatureFromCalls(calls: CallUsage[], fallbackReturn: Type): Signature { const parameters: Symbol[] = []; const length = Math.max(...calls.map(c => c.argumentTypes.length)); @@ -1023,9 +1075,5 @@ namespace ts.codefix { (usage.candidateThisTypes || (usage.candidateThisTypes = [])).push(type); } } - - function hasCalls(usage: Usage | undefined): boolean { - return !!usage && !!usage.calls; - } } } diff --git a/tests/cases/fourslash/codeFixInferFromPrimitiveUsage.ts b/tests/cases/fourslash/codeFixInferFromPrimitiveUsage.ts index 81c25770085..b74e49b4d39 100644 --- a/tests/cases/fourslash/codeFixInferFromPrimitiveUsage.ts +++ b/tests/cases/fourslash/codeFixInferFromPrimitiveUsage.ts @@ -1,9 +1,10 @@ /// // @noImplicitAny: true -////function wrap( [| s |] ) { -//// return s.length + s.toUpperCase() +//// function wrap( [| s |] ) { +//// return s.length + s.indexOf('hi') //// } // https://github.com/Microsoft/TypeScript/issues/29330 -verify.rangeAfterCodeFix("s: string"); +verify.rangeAfterCodeFix("s: string | string[]"); + From 052a3d9d73a009e11f26fa8ba99f6e72c63b5e6d Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Thu, 5 Sep 2019 16:16:35 -0700 Subject: [PATCH 06/17] Infer void from expr statement usage, not calls This makes inferences a lot better. --- src/services/codefixes/inferFromUsage.ts | 8 +++++--- .../cases/fourslash/codeFixInferFromCallInAssignment.ts | 9 +++++++++ .../fourslash/codeFixInferFromExpressionStatement.ts | 8 ++++++++ .../codeFixInferFromUsageCommentAfterParameter.ts | 2 +- tests/cases/fourslash/codeFixInferFromUsageJSXElement.ts | 2 +- .../fourslash/codeFixInferFromUsagePropertyAccess.ts | 2 +- .../fourslash/codeFixInferFromUsagePropertyAccessJS.ts | 2 +- 7 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 tests/cases/fourslash/codeFixInferFromCallInAssignment.ts create mode 100644 tests/cases/fourslash/codeFixInferFromExpressionStatement.ts diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index 0a190e7b379..daa2166103a 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -504,6 +504,9 @@ namespace ts.codefix { } switch (node.parent.kind) { + case SyntaxKind.ExpressionStatement: + addCandidateType(usage, checker.getVoidType()); + break; case SyntaxKind.PostfixUnaryExpression: usage.isNumber = true; break; @@ -871,12 +874,11 @@ namespace ts.codefix { } if (usage.calls) { - callSignatures.push(getSignatureFromCalls(usage.calls, checker.getVoidType())); + callSignatures.push(getSignatureFromCalls(usage.calls, checker.getAnyType())); } if (usage.constructs) { - // TODO: fallback return should maybe be {}? - constructSignatures.push(getSignatureFromCalls(usage.constructs, checker.getVoidType())); + constructSignatures.push(getSignatureFromCalls(usage.constructs, checker.getAnyType())); } if (usage.stringIndex) { diff --git a/tests/cases/fourslash/codeFixInferFromCallInAssignment.ts b/tests/cases/fourslash/codeFixInferFromCallInAssignment.ts new file mode 100644 index 00000000000..85e1d3bc509 --- /dev/null +++ b/tests/cases/fourslash/codeFixInferFromCallInAssignment.ts @@ -0,0 +1,9 @@ +/// + +// @noImplicitAny: true +//// function inferAny( [| app |] ) { +//// const result = app.use('hi') +//// return result +//// } + +verify.rangeAfterCodeFix("app: { use: (arg0: string) => any; }"); diff --git a/tests/cases/fourslash/codeFixInferFromExpressionStatement.ts b/tests/cases/fourslash/codeFixInferFromExpressionStatement.ts new file mode 100644 index 00000000000..b5969c79378 --- /dev/null +++ b/tests/cases/fourslash/codeFixInferFromExpressionStatement.ts @@ -0,0 +1,8 @@ +/// + +// @noImplicitAny: true +//// function inferVoid( [| app |] ) { +//// app.use('hi') +//// } + +verify.rangeAfterCodeFix("app: { use: (arg0: string) => void; }"); diff --git a/tests/cases/fourslash/codeFixInferFromUsageCommentAfterParameter.ts b/tests/cases/fourslash/codeFixInferFromUsageCommentAfterParameter.ts index bdefd2b5dea..866bfe04c13 100644 --- a/tests/cases/fourslash/codeFixInferFromUsageCommentAfterParameter.ts +++ b/tests/cases/fourslash/codeFixInferFromUsageCommentAfterParameter.ts @@ -16,7 +16,7 @@ verify.codeFix({ index: 0, newFileContent: `/** - * @param {(arg0: any) => void} callback + * @param {(arg0: any) => any} callback */ function coll(callback /*, name1, name2, ... */) { return callback(this); diff --git a/tests/cases/fourslash/codeFixInferFromUsageJSXElement.ts b/tests/cases/fourslash/codeFixInferFromUsageJSXElement.ts index 3200fffafb8..abe35fe46c8 100644 --- a/tests/cases/fourslash/codeFixInferFromUsageJSXElement.ts +++ b/tests/cases/fourslash/codeFixInferFromUsageJSXElement.ts @@ -30,4 +30,4 @@ //// } -verify.rangeAfterCodeFix("props: { isLoading: any; update: (arg0: any) => void; }",/*includeWhiteSpace*/ undefined, /*errorCode*/ undefined, 0); +verify.rangeAfterCodeFix("props: { isLoading: any; update: (arg0: any) => any; }",/*includeWhiteSpace*/ undefined, /*errorCode*/ undefined, 0); diff --git a/tests/cases/fourslash/codeFixInferFromUsagePropertyAccess.ts b/tests/cases/fourslash/codeFixInferFromUsagePropertyAccess.ts index c8b85ee11e8..44d2e2d7b1c 100644 --- a/tests/cases/fourslash/codeFixInferFromUsagePropertyAccess.ts +++ b/tests/cases/fourslash/codeFixInferFromUsagePropertyAccess.ts @@ -12,4 +12,4 @@ //// return x.y.z ////} -verify.rangeAfterCodeFix("a: { b: { c: any; }; }, m: { n: () => number; }, x: { y: { z: number[]; }; }", /*includeWhiteSpace*/ undefined, /*errorCode*/ undefined, /*index*/0); \ No newline at end of file +verify.rangeAfterCodeFix("a: { b: { c: void; }; }, m: { n: () => number; }, x: { y: { z: number[]; }; }", /*includeWhiteSpace*/ undefined, /*errorCode*/ undefined, /*index*/0); diff --git a/tests/cases/fourslash/codeFixInferFromUsagePropertyAccessJS.ts b/tests/cases/fourslash/codeFixInferFromUsagePropertyAccessJS.ts index ed9d4b33b37..357b1a991ba 100644 --- a/tests/cases/fourslash/codeFixInferFromUsagePropertyAccessJS.ts +++ b/tests/cases/fourslash/codeFixInferFromUsagePropertyAccessJS.ts @@ -21,7 +21,7 @@ verify.codeFix({ index: 0, newFileContent: `/** - * @param {{ b: { c: any; }; }} a + * @param {{ b: { c: void; }; }} a * @param {{ n: () => number; }} m * @param {{ y: { z: number[]; }; }} x */ From d32c6b2df1e1988c9565b4a7d08e422337540c2a Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Thu, 5 Sep 2019 16:21:08 -0700 Subject: [PATCH 07/17] Fallback type is always any now void is explicitly inferred now, never used as a fallback. --- src/services/codefixes/inferFromUsage.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index daa2166103a..b453535b462 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -767,8 +767,8 @@ namespace ts.codefix { return inferences.filter(i => toRemove.every(f => !f(i))); } - function unifyTypes(inferences: ReadonlyArray, fallback = checker.getAnyType()): Type { - if (!inferences.length) return fallback; + function unifyTypes(inferences: ReadonlyArray): Type { + if (!inferences.length) return checker.getAnyType(); // 1. string or number individually override string | number // 2. non-any, non-void overrides any or void @@ -874,11 +874,11 @@ namespace ts.codefix { } if (usage.calls) { - callSignatures.push(getSignatureFromCalls(usage.calls, checker.getAnyType())); + callSignatures.push(getSignatureFromCalls(usage.calls)); } if (usage.constructs) { - constructSignatures.push(getSignatureFromCalls(usage.constructs, checker.getAnyType())); + constructSignatures.push(getSignatureFromCalls(usage.constructs)); } if (usage.stringIndex) { @@ -1047,10 +1047,10 @@ namespace ts.codefix { } function getFunctionFromCalls(calls: CallUsage[]) { - return checker.createAnonymousType(undefined!, createSymbolTable(), [getSignatureFromCalls(calls, checker.getAnyType())], emptyArray, undefined, undefined); + return checker.createAnonymousType(undefined!, createSymbolTable(), [getSignatureFromCalls(calls)], emptyArray, undefined, undefined); } - function getSignatureFromCalls(calls: CallUsage[], fallbackReturn: Type): Signature { + function getSignatureFromCalls(calls: CallUsage[]): Signature { const parameters: Symbol[] = []; const length = Math.max(...calls.map(c => c.argumentTypes.length)); for (let i = 0; i < length; i++) { @@ -1061,7 +1061,7 @@ namespace ts.codefix { } parameters.push(symbol); } - const returnType = unifyTypes(inferFromUsage(combineUsages(calls.map(call => call.return_))), fallbackReturn); + const returnType = unifyTypes(inferFromUsage(combineUsages(calls.map(call => call.return_)))); // TODO: GH#18217 return checker.createSignature(/*declaration*/ undefined!, /*typeParameters*/ undefined, /*thisParameter*/ undefined, parameters, returnType, /*typePredicate*/ undefined, length, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); } From f394190572fb76b194df5f093f1af51abc1ffb98 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Fri, 6 Sep 2019 11:18:50 -0700 Subject: [PATCH 08/17] Tonnes of cleanup --- src/services/codefixes/inferFromUsage.ts | 167 ++++++++++++----------- 1 file changed, 87 insertions(+), 80 deletions(-) diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index b453535b462..2e9fb0dfc72 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -433,6 +433,53 @@ namespace ts.codefix { inferredTypes: Type[] | undefined; } + function createEmptyUsage(): Usage { + return { + isNumber: undefined, + isString: undefined, + isNumberOrString: undefined, + candidateTypes: undefined, + properties: undefined, + calls: undefined, + constructs: undefined, + numberIndex: undefined, + stringIndex: undefined, + candidateThisTypes: undefined, + inferredTypes: undefined, + }; + } + + function combineUsages(usages: Usage[]): Usage { + const combinedProperties = createUnderscoreEscapedMap(); + for (const u of usages) { + if (u.properties) { + u.properties.forEach((p, name) => { + if (!combinedProperties.has(name)) { + combinedProperties.set(name, []); + } + combinedProperties.get(name)!.push(p); + }); + } + } + const properties = createUnderscoreEscapedMap(); + combinedProperties.forEach((ps, name) => { + properties.set(name, combineUsages(ps)); + }); + 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, + 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[], + inferredTypes: undefined, // clear type cache + }; + } + function single(): Type { return unifyTypes(inferTypesFromReferencesSingle(references)); } @@ -767,6 +814,10 @@ namespace ts.codefix { return inferences.filter(i => toRemove.every(f => !f(i))); } + function unifyFromUsage(usage: Usage) { + return unifyTypes(inferFromUsage(usage)); + } + function unifyTypes(inferences: ReadonlyArray): Type { if (!inferences.length) return checker.getAnyType(); @@ -837,7 +888,7 @@ namespace ts.codefix { numberIndices.length ? checker.createIndexInfo(checker.getUnionType(numberIndices), numberIndexReadonly) : undefined); } - function inferFromUsage(usage: Usage) { + function inferFromUsage(usage: Usage): Type[] { const types = []; if (usage.isNumber) { @@ -851,12 +902,20 @@ namespace ts.codefix { } types.push(...(usage.candidateTypes || []).map(t => checker.getBaseTypeOfLiteralType(t))); - types.push(...findBuiltinTypes(usage)); + types.push(...inferNamedTypesFromProperties(usage)); if (usage.numberIndex) { - types.push(checker.createArrayType(recur(usage.numberIndex))); + types.push(checker.createArrayType(unifyFromUsage(usage.numberIndex))); } - else if (usage.properties && usage.properties.size + const structural = inferStructuralType(usage); + if (structural) { + types.push(structural); + } + return types; + } + + function inferStructuralType(usage: Usage) { + if (usage.properties && usage.properties.size || usage.calls && usage.calls.length || usage.constructs && usage.constructs.length || usage.stringIndex) { @@ -868,7 +927,7 @@ namespace ts.codefix { if (usage.properties) { usage.properties.forEach((u, name) => { const symbol = checker.createSymbol(SymbolFlags.Property, name); - symbol.type = recur(u); + symbol.type = unifyFromUsage(u); members.set(name, symbol); }); } @@ -882,75 +941,23 @@ namespace ts.codefix { } if (usage.stringIndex) { - stringIndexInfo = checker.createIndexInfo(recur(usage.stringIndex), /*isReadonly*/ false); + stringIndexInfo = checker.createIndexInfo(unifyFromUsage(usage.stringIndex), /*isReadonly*/ false); } - types.push(checker.createAnonymousType(/*symbol*/ undefined!, members, callSignatures, constructSignatures, stringIndexInfo, /*numberIndexInfo*/ undefined)); // TODO: GH#18217 - } - return types; // TODO: Should cache this since I HOPE it doesn't change - - function recur(innerUsage: Usage): Type { - return unifyTypes(inferFromUsage(innerUsage)); + return checker.createAnonymousType(/*symbol*/ undefined!, members, callSignatures, constructSignatures, stringIndexInfo, /*numberIndexInfo*/ undefined); // TODO: GH#18217 } } - function createEmptyUsage(): Usage { - return { - isNumber: undefined, - isString: undefined, - isNumberOrString: undefined, - candidateTypes: undefined, - properties: undefined, - calls: undefined, - constructs: undefined, - numberIndex: undefined, - stringIndex: undefined, - candidateThisTypes: undefined, - inferredTypes: undefined, - } - } - - function combineUsages(usages: Usage[]): Usage { - const combinedProperties = createUnderscoreEscapedMap() - for (const u of usages) { - if (u.properties) { - u.properties.forEach((p,name) => { - if (!combinedProperties.has(name)) { - combinedProperties.set(name, []); - } - combinedProperties.get(name)!.push(p); - }); - } - } - const properties = createUnderscoreEscapedMap() - combinedProperties.forEach((ps,name) => { - properties.set(name, combineUsages(ps)); - }); - 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, - 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[], - inferredTypes: undefined, // clear type cache - } - } - - function findBuiltinTypes(usage: Usage): Type[] { + function inferNamedTypesFromProperties(usage: Usage): Type[] { if (!usage.properties || !usage.properties.size) return []; - const matches = builtins.filter(t => matchesAllPropertiesOf(t, usage)); + const matches = builtins.filter(t => allPropertiesAreAssignableToUsage(t, usage)); if (0 < matches.length && matches.length < 3) { - return matches.map(m => inferTypeParameterFromUsage(m, usage)); + return matches.map(m => inferInstantiationFromUsage(m, usage)); } return []; } - function matchesAllPropertiesOf(type: Type, usage: Usage) { + function allPropertiesAreAssignableToUsage(type: Type, usage: Usage) { if (!usage.properties) return false; let result = true; usage.properties.forEach((propUsage, name) => { @@ -960,34 +967,34 @@ namespace ts.codefix { return; } if (propUsage.calls) { - const sigs = checker.getSignaturesOfType(source, ts.SignatureKind.Call); + const sigs = checker.getSignaturesOfType(source, SignatureKind.Call); result = result && !!sigs.length && checker.isTypeAssignableTo(source, getFunctionFromCalls(propUsage.calls)); } else { - result = result && checker.isTypeAssignableTo(source, unifyTypes(inferFromUsage(propUsage))); + result = result && checker.isTypeAssignableTo(source, unifyFromUsage(propUsage)); } }); return result; } - // inference is limited to - // 1. generic types with a single parameter - // 2. inference to/from calls with a single signature - function inferTypeParameterFromUsage(type: Type, usage: Usage) { - if (!usage.properties || !(getObjectFlags(type) & ObjectFlags.Reference)) return type; + /** + * inference is limited to + * 1. generic types with a single parameter + * 2. inference to/from calls with a single signature + */ + function inferInstantiationFromUsage(type: Type, usage: Usage) { + if (!(getObjectFlags(type) & ObjectFlags.Reference) || !usage.properties) { + return type; + } const generic = (type as TypeReference).target; const singleTypeParameter = singleOrUndefined(generic.typeParameters); if (!singleTypeParameter) return type; const types: Type[] = []; usage.properties.forEach((propUsage, name) => { - const source = checker.getTypeOfPropertyOfType(generic, name as string); - if (!source) { - return Debug.fail("generic should have all the properties of its reference."); - } - if (!propUsage.calls) return; - - types.push(...infer(source, getFunctionFromCalls(propUsage.calls), singleTypeParameter)); + const genericPropertyType = checker.getTypeOfPropertyOfType(generic, name as string); + Debug.assert(!!genericPropertyType, "generic should have all the properties of its reference."); + types.push(...infer(genericPropertyType!, unifyFromUsage(propUsage), singleTypeParameter)); }); return builtinConstructors[type.symbol.escapedName as string](unifyTypes(types)); } @@ -1033,7 +1040,7 @@ namespace ts.codefix { break; } let sourceType = checker.getTypeOfSymbolAtLocation(sourceParam, sourceParam.valueDeclaration); - let elementType = isRest && checker.getElementTypeOfArrayType(sourceType); + const elementType = isRest && checker.getElementTypeOfArrayType(sourceType); if (elementType) { sourceType = elementType; } @@ -1047,7 +1054,7 @@ namespace ts.codefix { } function getFunctionFromCalls(calls: CallUsage[]) { - return checker.createAnonymousType(undefined!, createSymbolTable(), [getSignatureFromCalls(calls)], emptyArray, undefined, undefined); + return checker.createAnonymousType(undefined!, createSymbolTable(), [getSignatureFromCalls(calls)], emptyArray, /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined); } function getSignatureFromCalls(calls: CallUsage[]): Signature { @@ -1061,7 +1068,7 @@ namespace ts.codefix { } parameters.push(symbol); } - const returnType = unifyTypes(inferFromUsage(combineUsages(calls.map(call => call.return_)))); + const returnType = unifyFromUsage(combineUsages(calls.map(call => call.return_))); // TODO: GH#18217 return checker.createSignature(/*declaration*/ undefined!, /*typeParameters*/ undefined, /*thisParameter*/ undefined, parameters, returnType, /*typePredicate*/ undefined, length, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); } From 1703ae0f46407beb4701e7234c9de558b20e17c0 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Fri, 6 Sep 2019 11:27:34 -0700 Subject: [PATCH 09/17] Renames and more cleanup --- src/services/codefixes/inferFromUsage.ts | 63 +++++++++++------------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index 2e9fb0dfc72..0c711cfa4c4 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -743,7 +743,6 @@ namespace ts.codefix { if (parent.arguments) { for (const argument of parent.arguments) { - // TODO: should recursively infer a usage here, right? call.argumentTypes.push(checker.getTypeAtLocation(argument)); } } @@ -999,57 +998,55 @@ namespace ts.codefix { return builtinConstructors[type.symbol.escapedName as string](unifyTypes(types)); } - // TODO: Source and target are bad names. Should be builtinType and usageType...or something - // and search is a bad name - function infer(source: Type, target: Type, search: Type): readonly Type[] { - if (source === search) { - return [target]; + function infer(genericType: Type, usageType: Type, typeParameter: Type): readonly Type[] { + if (genericType === typeParameter) { + return [usageType]; } - else if (source.flags & TypeFlags.UnionOrIntersection) { - return flatMap((source as UnionOrIntersectionType).types, t => infer(t, target, search)); + else if (genericType.flags & TypeFlags.UnionOrIntersection) { + return flatMap((genericType as UnionOrIntersectionType).types, t => infer(t, usageType, typeParameter)); } - else if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference) { + else if (getObjectFlags(genericType) & ObjectFlags.Reference && getObjectFlags(usageType) & ObjectFlags.Reference) { // this is wrong because we need a reference to the targetType to, so we can check that it's also a reference - const sourceArgs = (source as TypeReference).typeArguments; - const targetArgs = (target as TypeReference).typeArguments; + const genericArgs = (genericType as TypeReference).typeArguments; + const usageArgs = (usageType as TypeReference).typeArguments; const types = []; - if (sourceArgs && targetArgs) { - for (let i = 0; i < sourceArgs.length; i++) { - if (targetArgs[i]) { - types.push(...infer(sourceArgs[i], targetArgs[i], search)); + if (genericArgs && usageArgs) { + for (let i = 0; i < genericArgs.length; i++) { + if (usageArgs[i]) { + types.push(...infer(genericArgs[i], usageArgs[i], typeParameter)); } } } return types; } - const sourceSigs = checker.getSignaturesOfType(source, SignatureKind.Call); - const targetSigs = checker.getSignaturesOfType(target, SignatureKind.Call); - if (sourceSigs.length === 1 && targetSigs.length === 1) { - return inferFromSignatures(sourceSigs[0], targetSigs[0], search); + const genericSigs = checker.getSignaturesOfType(genericType, SignatureKind.Call); + const usageSigs = checker.getSignaturesOfType(usageType, SignatureKind.Call); + if (genericSigs.length === 1 && usageSigs.length === 1) { + return inferFromSignatures(genericSigs[0], usageSigs[0], typeParameter); } return []; } - function inferFromSignatures(sourceSig: Signature, targetSig: Signature, search: Type) { + function inferFromSignatures(genericSig: Signature, usageSig: Signature, typeParameter: Type) { const types = []; - for (let i = 0; i < sourceSig.parameters.length; i++) { - const sourceParam = sourceSig.parameters[i]; - const targetParam = targetSig.parameters[i]; - const isRest = sourceSig.declaration && isRestParameter(sourceSig.declaration.parameters[i]); - if (!targetParam) { + for (let i = 0; i < genericSig.parameters.length; i++) { + const genericParam = genericSig.parameters[i]; + const usageParam = usageSig.parameters[i]; + const isRest = genericSig.declaration && isRestParameter(genericSig.declaration.parameters[i]); + if (!usageParam) { break; } - let sourceType = checker.getTypeOfSymbolAtLocation(sourceParam, sourceParam.valueDeclaration); - const elementType = isRest && checker.getElementTypeOfArrayType(sourceType); + let genericParamType = checker.getTypeOfSymbolAtLocation(genericParam, genericParam.valueDeclaration); + const elementType = isRest && checker.getElementTypeOfArrayType(genericParamType); if (elementType) { - sourceType = elementType; + genericParamType = elementType; } - const targetType = (targetParam as SymbolLinks).type || checker.getTypeOfSymbolAtLocation(targetParam, targetParam.valueDeclaration); - types.push(...infer(sourceType, targetType, search)); + const targetType = (usageParam as SymbolLinks).type || checker.getTypeOfSymbolAtLocation(usageParam, usageParam.valueDeclaration); + types.push(...infer(genericParamType, targetType, typeParameter)); } - const sourceReturn = checker.getReturnTypeOfSignature(sourceSig); - const targetReturn = checker.getReturnTypeOfSignature(targetSig); - types.push(...infer(sourceReturn, targetReturn, search)); + const genericReturn = checker.getReturnTypeOfSignature(genericSig); + const usageReturn = checker.getReturnTypeOfSignature(usageSig); + types.push(...infer(genericReturn, usageReturn, typeParameter)); return types; } From 330e51f09811a41bddd71bfe2eea3baa4e6651bc Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Fri, 6 Sep 2019 15:15:19 -0700 Subject: [PATCH 10/17] Add test + reshuffle/rename new code --- src/services/codefixes/inferFromUsage.ts | 63 +++++++------------ .../codeFixInferFromUsageAddition.ts | 9 +++ .../fourslash/codeFixInferFromUsageArray.ts | 14 +++++ .../codeFixInferFromUsageLiteralTypes.ts | 10 +++ .../fourslash/codeFixInferFromUsagePromise.ts | 9 +++ .../fourslash/codeFixInferFromUsageString.ts | 12 ++++ 6 files changed, 77 insertions(+), 40 deletions(-) create mode 100644 tests/cases/fourslash/codeFixInferFromUsageAddition.ts create mode 100644 tests/cases/fourslash/codeFixInferFromUsageArray.ts create mode 100644 tests/cases/fourslash/codeFixInferFromUsageLiteralTypes.ts create mode 100644 tests/cases/fourslash/codeFixInferFromUsagePromise.ts create mode 100644 tests/cases/fourslash/codeFixInferFromUsageString.ts diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index 0c711cfa4c4..520f8520d21 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -899,59 +899,42 @@ namespace ts.codefix { if (usage.isNumberOrString) { types.push(checker.getUnionType([checker.getStringType(), checker.getNumberType()])); } + if (usage.numberIndex) { + types.push(checker.createArrayType(unifyFromUsage(usage.numberIndex))); + } + if (usage.properties && usage.properties.size + || usage.calls && usage.calls.length + || usage.constructs && usage.constructs.length + || usage.stringIndex) { + types.push(inferStructuralType(usage)); + } types.push(...(usage.candidateTypes || []).map(t => checker.getBaseTypeOfLiteralType(t))); types.push(...inferNamedTypesFromProperties(usage)); - if (usage.numberIndex) { - types.push(checker.createArrayType(unifyFromUsage(usage.numberIndex))); - } - const structural = inferStructuralType(usage); - if (structural) { - types.push(structural); - } return types; } function inferStructuralType(usage: Usage) { - if (usage.properties && usage.properties.size - || usage.calls && usage.calls.length - || usage.constructs && usage.constructs.length - || usage.stringIndex) { - const members = createUnderscoreEscapedMap(); - const callSignatures: Signature[] = []; - const constructSignatures: Signature[] = []; - let stringIndexInfo: IndexInfo | undefined; - - if (usage.properties) { - usage.properties.forEach((u, name) => { - const symbol = checker.createSymbol(SymbolFlags.Property, name); - symbol.type = unifyFromUsage(u); - members.set(name, symbol); - }); - } - - if (usage.calls) { - callSignatures.push(getSignatureFromCalls(usage.calls)); - } - - if (usage.constructs) { - constructSignatures.push(getSignatureFromCalls(usage.constructs)); - } - - if (usage.stringIndex) { - stringIndexInfo = checker.createIndexInfo(unifyFromUsage(usage.stringIndex), /*isReadonly*/ false); - } - - return checker.createAnonymousType(/*symbol*/ undefined!, members, callSignatures, constructSignatures, stringIndexInfo, /*numberIndexInfo*/ undefined); // TODO: GH#18217 + const members = createUnderscoreEscapedMap(); + if (usage.properties) { + usage.properties.forEach((u, name) => { + const symbol = checker.createSymbol(SymbolFlags.Property, name); + symbol.type = unifyFromUsage(u); + members.set(name, symbol); + }); } + const callSignatures: Signature[] = usage.calls ? [getSignatureFromCalls(usage.calls)] : []; + const constructSignatures: Signature[] = usage.constructs ? [getSignatureFromCalls(usage.constructs)] : []; + const stringIndexInfo = usage.stringIndex && checker.createIndexInfo(unifyFromUsage(usage.stringIndex), /*isReadonly*/ false); + return checker.createAnonymousType(/*symbol*/ undefined!, members, callSignatures, constructSignatures, stringIndexInfo, /*numberIndexInfo*/ undefined); // TODO: GH#18217 } function inferNamedTypesFromProperties(usage: Usage): Type[] { if (!usage.properties || !usage.properties.size) return []; - const matches = builtins.filter(t => allPropertiesAreAssignableToUsage(t, usage)); - if (0 < matches.length && matches.length < 3) { - return matches.map(m => inferInstantiationFromUsage(m, usage)); + const types = builtins.filter(t => allPropertiesAreAssignableToUsage(t, usage)); + if (0 < types.length && types.length < 3) { + return types.map(t => inferInstantiationFromUsage(t, usage)); } return []; } diff --git a/tests/cases/fourslash/codeFixInferFromUsageAddition.ts b/tests/cases/fourslash/codeFixInferFromUsageAddition.ts new file mode 100644 index 00000000000..4b57d0603f1 --- /dev/null +++ b/tests/cases/fourslash/codeFixInferFromUsageAddition.ts @@ -0,0 +1,9 @@ +/// + +// @noImplicitAny: true +//// function foo([|a, m |]) { +//// return a + m +//// } + +verify.rangeAfterCodeFix("a: any, m: any", /*includeWhiteSpace*/ undefined, /*errorCode*/ undefined, /*index*/0); + diff --git a/tests/cases/fourslash/codeFixInferFromUsageArray.ts b/tests/cases/fourslash/codeFixInferFromUsageArray.ts new file mode 100644 index 00000000000..03d6b09e99b --- /dev/null +++ b/tests/cases/fourslash/codeFixInferFromUsageArray.ts @@ -0,0 +1,14 @@ +/// + +// @noImplicitAny: true +//// function foo([|p, a, b, c, d, e |]) { +//// var x: string = a.pop() +//// b.reverse() +//// var rr: boolean[] = c.reverse() +//// d.some(t => t > 1); // can't infer from callbacks right now +//// var y = e.concat(12); // can't infer from overloaded functions right now +//// return p.push(12) +//// } + +verify.rangeAfterCodeFix("p: number[], a: string[], b: any[], c: boolean[], d: any[], e: number[]", /*includeWhiteSpace*/ undefined, /*errorCode*/ undefined, /*index*/0); + diff --git a/tests/cases/fourslash/codeFixInferFromUsageLiteralTypes.ts b/tests/cases/fourslash/codeFixInferFromUsageLiteralTypes.ts new file mode 100644 index 00000000000..3b8c9441159 --- /dev/null +++ b/tests/cases/fourslash/codeFixInferFromUsageLiteralTypes.ts @@ -0,0 +1,10 @@ +/// + +// @noImplicitAny: true +//// function foo([|a, m |]) { +//// a = 'hi' +//// m = 1 +//// } + +verify.rangeAfterCodeFix("a: string, m: number", /*includeWhiteSpace*/ undefined, /*errorCode*/ undefined, /*index*/0); + diff --git a/tests/cases/fourslash/codeFixInferFromUsagePromise.ts b/tests/cases/fourslash/codeFixInferFromUsagePromise.ts new file mode 100644 index 00000000000..d06bb3b6a0f --- /dev/null +++ b/tests/cases/fourslash/codeFixInferFromUsagePromise.ts @@ -0,0 +1,9 @@ +/// + +// @noImplicitAny: true +//// function foo([|p |]) { +//// return p.then((x: string[]) => x[0]) +//// } + +verify.rangeAfterCodeFix("p: Promise", /*includeWhiteSpace*/ undefined, /*errorCode*/ undefined, /*index*/0); + diff --git a/tests/cases/fourslash/codeFixInferFromUsageString.ts b/tests/cases/fourslash/codeFixInferFromUsageString.ts new file mode 100644 index 00000000000..dc5787dc75b --- /dev/null +++ b/tests/cases/fourslash/codeFixInferFromUsageString.ts @@ -0,0 +1,12 @@ +/// + +// @noImplicitAny: true +//// function foo([|p, a, b, c, d |]) { +//// var x +//// p.charAt(x) +//// a.charAt(0) +//// b.concat('hi') +//// } + +verify.rangeAfterCodeFix("p: string, a: string, b: string | string[]", /*includeWhiteSpace*/ undefined, /*errorCode*/ undefined, /*index*/0); + From 3c79225f48773cccdf247578cf2297111f0ccd2a Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Thu, 12 Sep 2019 11:18:47 -0700 Subject: [PATCH 11/17] Update baselines with any[] inferences --- tests/cases/fourslash/codeFixInferFromUsageArray.ts | 2 +- tests/cases/fourslash/codeFixInferFromUsageString.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/cases/fourslash/codeFixInferFromUsageArray.ts b/tests/cases/fourslash/codeFixInferFromUsageArray.ts index 03d6b09e99b..75f923d5aee 100644 --- a/tests/cases/fourslash/codeFixInferFromUsageArray.ts +++ b/tests/cases/fourslash/codeFixInferFromUsageArray.ts @@ -10,5 +10,5 @@ //// return p.push(12) //// } -verify.rangeAfterCodeFix("p: number[], a: string[], b: any[], c: boolean[], d: any[], e: number[]", /*includeWhiteSpace*/ undefined, /*errorCode*/ undefined, /*index*/0); +verify.rangeAfterCodeFix("p: number[], a: string[], b: any[], c: boolean[], d: any[], e: any[]", /*includeWhiteSpace*/ undefined, /*errorCode*/ undefined, /*index*/0); diff --git a/tests/cases/fourslash/codeFixInferFromUsageString.ts b/tests/cases/fourslash/codeFixInferFromUsageString.ts index dc5787dc75b..d58998cf4a3 100644 --- a/tests/cases/fourslash/codeFixInferFromUsageString.ts +++ b/tests/cases/fourslash/codeFixInferFromUsageString.ts @@ -1,12 +1,12 @@ /// // @noImplicitAny: true -//// function foo([|p, a, b, c, d |]) { +//// function foo([|p, a, b |]) { //// var x //// p.charAt(x) //// a.charAt(0) //// b.concat('hi') //// } -verify.rangeAfterCodeFix("p: string, a: string, b: string | string[]", /*includeWhiteSpace*/ undefined, /*errorCode*/ undefined, /*index*/0); +verify.rangeAfterCodeFix("p: string, a: string, b: string | any[]", /*includeWhiteSpace*/ undefined, /*errorCode*/ undefined, /*index*/0); From de7d68a6d8704545fa4d04e3e0cf3072bda887c2 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Thu, 12 Sep 2019 11:30:51 -0700 Subject: [PATCH 12/17] Even more renaming --- src/services/codefixes/inferFromUsage.ts | 46 ++++++++++++------------ 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index 00b95c57d1a..090c241b05d 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -481,7 +481,7 @@ namespace ts.codefix { } function single(): Type { - return unifyTypes(inferTypesFromReferencesSingle(references)); + return combineTypes(inferTypesFromReferencesSingle(references)); } function parameters(declaration: FunctionLike): ParameterInference[] | undefined { @@ -517,7 +517,7 @@ namespace ts.codefix { const inferred = inferTypesFromReferencesSingle(getReferences(parameter.name, program, cancellationToken)); types.push(...(isRest ? mapDefined(inferred, checker.getElementTypeOfArrayType) : inferred)); } - const type = unifyTypes(types); + const type = combineTypes(types); return { type: isRest ? checker.createArrayType(type) : type, isOptional: isOptional && !isRest, @@ -533,7 +533,7 @@ namespace ts.codefix { calculateUsageOfNode(reference, usage); } - return unifyTypes(usage.candidateThisTypes || emptyArray); + return combineTypes(usage.candidateThisTypes || emptyArray); } function inferTypesFromReferencesSingle(references: readonly Identifier[]): Type[] { @@ -542,7 +542,7 @@ namespace ts.codefix { cancellationToken.throwIfCancellationRequested(); calculateUsageOfNode(reference, usage); } - return inferFromUsage(usage); + return inferTypes(usage); } function calculateUsageOfNode(node: Expression, usage: Usage): void { @@ -819,11 +819,11 @@ namespace ts.codefix { return inferences.filter(i => toRemove.every(f => !f(i))); } - function unifyFromUsage(usage: Usage) { - return unifyTypes(inferFromUsage(usage)); + function combineFromUsage(usage: Usage) { + return combineTypes(inferTypes(usage)); } - function unifyTypes(inferences: readonly Type[]): Type { + function combineTypes(inferences: readonly Type[]): Type { if (!inferences.length) return checker.getAnyType(); // 1. string or number individually override string | number @@ -847,12 +847,12 @@ namespace ts.codefix { const anons = good.filter(i => checker.getObjectFlags(i) & ObjectFlags.Anonymous) as AnonymousType[]; if (anons.length) { good = good.filter(i => !(checker.getObjectFlags(i) & ObjectFlags.Anonymous)); - good.push(unifyAnonymousTypes(anons)); + good.push(combineAnonymousTypes(anons)); } return checker.getWidenedType(checker.getUnionType(good.map(checker.getBaseTypeOfLiteralType), UnionReduction.Subtype)); } - function unifyAnonymousTypes(anons: AnonymousType[]) { + function combineAnonymousTypes(anons: AnonymousType[]) { if (anons.length === 1) { return anons[0]; } @@ -893,7 +893,7 @@ namespace ts.codefix { numberIndices.length ? checker.createIndexInfo(checker.getUnionType(numberIndices), numberIndexReadonly) : undefined); } - function inferFromUsage(usage: Usage): Type[] { + function inferTypes(usage: Usage): Type[] { const types = []; if (usage.isNumber) { @@ -906,7 +906,7 @@ namespace ts.codefix { types.push(checker.getUnionType([checker.getStringType(), checker.getNumberType()])); } if (usage.numberIndex) { - types.push(checker.createArrayType(unifyFromUsage(usage.numberIndex))); + types.push(checker.createArrayType(combineFromUsage(usage.numberIndex))); } if (usage.properties && usage.properties.size || usage.calls && usage.calls.length @@ -926,13 +926,13 @@ namespace ts.codefix { if (usage.properties) { usage.properties.forEach((u, name) => { const symbol = checker.createSymbol(SymbolFlags.Property, name); - symbol.type = unifyFromUsage(u); + symbol.type = combineFromUsage(u); members.set(name, symbol); }); } const callSignatures: Signature[] = usage.calls ? [getSignatureFromCalls(usage.calls)] : []; const constructSignatures: Signature[] = usage.constructs ? [getSignatureFromCalls(usage.constructs)] : []; - const stringIndexInfo = usage.stringIndex && checker.createIndexInfo(unifyFromUsage(usage.stringIndex), /*isReadonly*/ false); + const stringIndexInfo = usage.stringIndex && checker.createIndexInfo(combineFromUsage(usage.stringIndex), /*isReadonly*/ false); return checker.createAnonymousType(/*symbol*/ undefined!, members, callSignatures, constructSignatures, stringIndexInfo, /*numberIndexInfo*/ undefined); // TODO: GH#18217 } @@ -959,7 +959,7 @@ namespace ts.codefix { result = result && !!sigs.length && checker.isTypeAssignableTo(source, getFunctionFromCalls(propUsage.calls)); } else { - result = result && checker.isTypeAssignableTo(source, unifyFromUsage(propUsage)); + result = result && checker.isTypeAssignableTo(source, combineFromUsage(propUsage)); } }); return result; @@ -982,17 +982,17 @@ namespace ts.codefix { usage.properties.forEach((propUsage, name) => { const genericPropertyType = checker.getTypeOfPropertyOfType(generic, name as string); Debug.assert(!!genericPropertyType, "generic should have all the properties of its reference."); - types.push(...infer(genericPropertyType!, unifyFromUsage(propUsage), singleTypeParameter)); + types.push(...inferTypeParameters(genericPropertyType!, combineFromUsage(propUsage), singleTypeParameter)); }); - return builtinConstructors[type.symbol.escapedName as string](unifyTypes(types)); + return builtinConstructors[type.symbol.escapedName as string](combineTypes(types)); } - function infer(genericType: Type, usageType: Type, typeParameter: Type): readonly Type[] { + function inferTypeParameters(genericType: Type, usageType: Type, typeParameter: Type): readonly Type[] { if (genericType === typeParameter) { return [usageType]; } else if (genericType.flags & TypeFlags.UnionOrIntersection) { - return flatMap((genericType as UnionOrIntersectionType).types, t => infer(t, usageType, typeParameter)); + return flatMap((genericType as UnionOrIntersectionType).types, t => inferTypeParameters(t, usageType, typeParameter)); } else if (getObjectFlags(genericType) & ObjectFlags.Reference && getObjectFlags(usageType) & ObjectFlags.Reference) { // this is wrong because we need a reference to the targetType to, so we can check that it's also a reference @@ -1002,7 +1002,7 @@ namespace ts.codefix { if (genericArgs && usageArgs) { for (let i = 0; i < genericArgs.length; i++) { if (usageArgs[i]) { - types.push(...infer(genericArgs[i], usageArgs[i], typeParameter)); + types.push(...inferTypeParameters(genericArgs[i], usageArgs[i], typeParameter)); } } } @@ -1031,11 +1031,11 @@ namespace ts.codefix { genericParamType = elementType; } const targetType = (usageParam as SymbolLinks).type || checker.getTypeOfSymbolAtLocation(usageParam, usageParam.valueDeclaration); - types.push(...infer(genericParamType, targetType, typeParameter)); + types.push(...inferTypeParameters(genericParamType, targetType, typeParameter)); } const genericReturn = checker.getReturnTypeOfSignature(genericSig); const usageReturn = checker.getReturnTypeOfSignature(usageSig); - types.push(...infer(genericReturn, usageReturn, typeParameter)); + types.push(...inferTypeParameters(genericReturn, usageReturn, typeParameter)); return types; } @@ -1048,13 +1048,13 @@ namespace ts.codefix { 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 = unifyTypes(calls.map(call => call.argumentTypes[i] || checker.getUndefinedType())); + symbol.type = combineTypes(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(combineUsages(calls.map(call => call.return_))); + const returnType = combineFromUsage(combineUsages(calls.map(call => call.return_))); // TODO: GH#18217 return checker.createSignature(/*declaration*/ undefined!, /*typeParameters*/ undefined, /*thisParameter*/ undefined, parameters, returnType, /*typePredicate*/ undefined, length, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false); } From 84e857b6f3624fcb01db807affa49ca8d9580f3b Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Mon, 23 Sep 2019 15:57:32 -0700 Subject: [PATCH 13/17] use forEachEntry --- src/services/codefixes/inferFromUsage.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index 090c241b05d..5dd34782885 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -947,22 +947,19 @@ namespace ts.codefix { function allPropertiesAreAssignableToUsage(type: Type, usage: Usage) { if (!usage.properties) return false; - let result = true; - usage.properties.forEach((propUsage, name) => { + return !forEachEntry(usage.properties, (propUsage, name) => { const source = checker.getTypeOfPropertyOfType(type, name as string); if (!source) { - result = false; - return; + return true; } if (propUsage.calls) { const sigs = checker.getSignaturesOfType(source, SignatureKind.Call); - result = result && !!sigs.length && checker.isTypeAssignableTo(source, getFunctionFromCalls(propUsage.calls)); + return !sigs.length || !checker.isTypeAssignableTo(source, getFunctionFromCalls(propUsage.calls)); } else { - result = result && checker.isTypeAssignableTo(source, combineFromUsage(propUsage)); + return !checker.isTypeAssignableTo(source, combineFromUsage(propUsage)); } }); - return result; } /** From 0a4f39af715c164cf7c905999fd8051f839e5d6c Mon Sep 17 00:00:00 2001 From: typescript-bot Date: Tue, 24 Sep 2019 14:10:40 +0000 Subject: [PATCH 14/17] Update user baselines --- .../reference/docker/office-ui-fabric.log | 21 +---- tests/baselines/reference/user/assert.log | 40 ++++---- .../user/chrome-devtools-frontend.log | 91 ++++++++----------- tests/baselines/reference/user/prettier.log | 75 ++++++++------- 4 files changed, 100 insertions(+), 127 deletions(-) diff --git a/tests/baselines/reference/docker/office-ui-fabric.log b/tests/baselines/reference/docker/office-ui-fabric.log index 9cda725e39e..e75c479de90 100644 --- a/tests/baselines/reference/docker/office-ui-fabric.log +++ b/tests/baselines/reference/docker/office-ui-fabric.log @@ -1,14 +1,5 @@ Exit Code: 1 Standard output: -@uifabric/codepen-loader: yarn run vX.X.X -@uifabric/codepen-loader: $ just-scripts build --production --lint -@uifabric/codepen-loader: [XX:XX:XX XM] ■ Removing [lib, temp, dist, coverage, lib-commonjs] -@uifabric/codepen-loader: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/codepen-loader/tsconfig.json -@uifabric/codepen-loader: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --module commonjs --outDir "./lib" --project "/office-ui-fabric-react/packages/codepen-loader/tsconfig.json" -@uifabric/codepen-loader: [XX:XX:XX XM] ■ Running Jest -@uifabric/codepen-loader: [XX:XX:XX XM] ■ /usr/local/bin/node "/office-ui-fabric-react/node_modules/jest/bin/jest.js" --config "/office-ui-fabric-react/packages/codepen-loader/jest.config.js" --passWithNoTests --colors --forceExit -@uifabric/codepen-loader: PASS src/__tests__/codepenTransform.test.ts -@uifabric/codepen-loader: Done in ?s. @uifabric/build: yarn run vX.X.X @uifabric/build: $ node ./just-scripts.js no-op --production --lint @uifabric/build: Done in ?s. @@ -36,9 +27,11 @@ Standard output: @uifabric/migration: Done in ?s. @uifabric/monaco-editor: yarn run vX.X.X @uifabric/monaco-editor: $ just-scripts build --production --lint -@uifabric/monaco-editor: [XX:XX:XX XM] ■ Removing [esm, lib] +@uifabric/monaco-editor: [XX:XX:XX XM] ■ Removing [esm, lib, lib-commonjs] @uifabric/monaco-editor: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/monaco-editor/tsconfig.json @uifabric/monaco-editor: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib --module esnext --project "/office-ui-fabric-react/packages/monaco-editor/tsconfig.json" +@uifabric/monaco-editor: [XX:XX:XX XM] ■ Running /office-ui-fabric-react/node_modules/typescript/lib/tsc.js with /office-ui-fabric-react/packages/monaco-editor/tsconfig.json +@uifabric/monaco-editor: [XX:XX:XX XM] ■ Executing: /usr/local/bin/node "/office-ui-fabric-react/node_modules/typescript/lib/tsc.js" --pretty --target es5 --inlineSources --sourceRoot "../src" --outDir lib-commonjs --module commonjs --project "/office-ui-fabric-react/packages/monaco-editor/tsconfig.json" @uifabric/monaco-editor: Done in ?s. @uifabric/set-version: yarn run vX.X.X @uifabric/set-version: $ just-scripts build --production --lint @@ -91,6 +84,7 @@ Standard output: @uifabric/merge-styles: PASS src/extractStyleParts.test.ts @uifabric/merge-styles: PASS src/server.test.ts @uifabric/merge-styles: PASS src/concatStyleSetsWithProps.test.ts +@uifabric/merge-styles: PASS src/fontFace.test.ts @uifabric/merge-styles: [XX:XX:XX XM] ■ Extracting Public API surface from '/office-ui-fabric-react/packages/merge-styles/lib/index.d.ts' @uifabric/merge-styles: Done in ?s. @uifabric/jest-serializer-merge-styles: yarn run vX.X.X @@ -206,7 +200,6 @@ Standard output: @uifabric/styling: PASS src/styles/theme.test.ts @uifabric/styling: PASS src/styles/scheme.test.ts @uifabric/styling: PASS src/styles/getGlobalClassNames.test.ts -@uifabric/styling: PASS src/utilities/icons.test.ts @uifabric/styling: [XX:XX:XX XM] ■ Extracting Public API surface from '/office-ui-fabric-react/packages/styling/lib/index.d.ts' @uifabric/styling: Done in ?s. @uifabric/file-type-icons: yarn run vX.X.X @@ -249,11 +242,7 @@ Standard output: Standard error: info cli using local version of lerna lerna notice cli vX.X.X -lerna info Executing command in 43 packages: "yarn run build --production --lint" -@uifabric/codepen-loader: ts-jest[versions] (WARN) Version X.X.X-insiders.xxxxxxxx of typescript installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=2.7.0 <4.0.0). Please do not report issues in ts-jest if you are using unsupported versions. -@uifabric/codepen-loader: Force exiting Jest -@uifabric/codepen-loader: -@uifabric/codepen-loader: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished? +lerna info Executing command in 42 packages: "yarn run build --production --lint" @uifabric/example-data: [XX:XX:XX XM] ▲ One of these [node-sass, postcss, autoprefixer] is not installed, so this task has no effect @uifabric/set-version: [XX:XX:XX XM] ▲ One of these [node-sass, postcss, autoprefixer] is not installed, so this task has no effect @uifabric/merge-styles: [XX:XX:XX XM] ▲ One of these [node-sass, postcss, autoprefixer] is not installed, so this task has no effect diff --git a/tests/baselines/reference/user/assert.log b/tests/baselines/reference/user/assert.log index 4b00cccc6ab..ce8e6cc19d0 100644 --- a/tests/baselines/reference/user/assert.log +++ b/tests/baselines/reference/user/assert.log @@ -1,34 +1,34 @@ Exit Code: 1 Standard output: node_modules/assert/test.js(25,5): error TS2367: This condition will always return 'false' since the types 'string | undefined' and 'boolean' have no overlap. -node_modules/assert/test.js(39,5): error TS2552: Cannot find name 'test'. Did you mean 'tests'? -node_modules/assert/test.js(55,5): error TS2552: Cannot find name 'test'. Did you mean 'tests'? -node_modules/assert/test.js(74,5): error TS2552: Cannot find name 'test'. Did you mean 'tests'? -node_modules/assert/test.js(84,5): error TS2552: Cannot find name 'test'. Did you mean 'tests'? -node_modules/assert/test.js(94,5): error TS2552: Cannot find name 'test'. Did you mean 'tests'? -node_modules/assert/test.js(103,5): error TS2552: Cannot find name 'test'. Did you mean 'tests'? -node_modules/assert/test.js(120,5): error TS2552: Cannot find name 'test'. Did you mean 'tests'? -node_modules/assert/test.js(128,5): error TS2552: Cannot find name 'test'. Did you mean 'tests'? +node_modules/assert/test.js(39,5): error TS2593: Cannot find name 'test'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha` and then add `jest` or `mocha` to the types field in your tsconfig. +node_modules/assert/test.js(55,5): error TS2593: Cannot find name 'test'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha` and then add `jest` or `mocha` to the types field in your tsconfig. +node_modules/assert/test.js(74,5): error TS2593: Cannot find name 'test'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha` and then add `jest` or `mocha` to the types field in your tsconfig. +node_modules/assert/test.js(84,5): error TS2593: Cannot find name 'test'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha` and then add `jest` or `mocha` to the types field in your tsconfig. +node_modules/assert/test.js(94,5): error TS2593: Cannot find name 'test'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha` and then add `jest` or `mocha` to the types field in your tsconfig. +node_modules/assert/test.js(103,5): error TS2593: Cannot find name 'test'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha` and then add `jest` or `mocha` to the types field in your tsconfig. +node_modules/assert/test.js(120,5): error TS2593: Cannot find name 'test'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha` and then add `jest` or `mocha` to the types field in your tsconfig. +node_modules/assert/test.js(128,5): error TS2593: Cannot find name 'test'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha` and then add `jest` or `mocha` to the types field in your tsconfig. node_modules/assert/test.js(140,10): error TS2339: Property 'a' does not exist on type 'number[]'. node_modules/assert/test.js(141,10): error TS2339: Property 'b' does not exist on type 'number[]'. node_modules/assert/test.js(142,10): error TS2339: Property 'b' does not exist on type 'number[]'. node_modules/assert/test.js(143,10): error TS2339: Property 'a' does not exist on type 'number[]'. -node_modules/assert/test.js(149,5): error TS2552: Cannot find name 'test'. Did you mean 'tests'? +node_modules/assert/test.js(149,5): error TS2593: Cannot find name 'test'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha` and then add `jest` or `mocha` to the types field in your tsconfig. node_modules/assert/test.js(157,51): error TS2349: This expression is not callable. Type 'never' has no call signatures. -node_modules/assert/test.js(161,5): error TS2552: Cannot find name 'test'. Did you mean 'tests'? +node_modules/assert/test.js(161,5): error TS2593: Cannot find name 'test'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha` and then add `jest` or `mocha` to the types field in your tsconfig. node_modules/assert/test.js(168,5): error TS2593: Cannot find name 'test'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha` and then add `jest` or `mocha` to the types field in your tsconfig. -node_modules/assert/test.js(182,5): error TS2593: Cannot find name 'test'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha` and then add `jest` or `mocha` to the types field in your tsconfig. -node_modules/assert/test.js(229,5): error TS2593: Cannot find name 'test'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha` and then add `jest` or `mocha` to the types field in your tsconfig. -node_modules/assert/test.js(235,5): error TS2593: Cannot find name 'test'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha` and then add `jest` or `mocha` to the types field in your tsconfig. -node_modules/assert/test.js(250,5): error TS2593: Cannot find name 'test'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha` and then add `jest` or `mocha` to the types field in your tsconfig. -node_modules/assert/test.js(254,5): error TS2593: Cannot find name 'test'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha` and then add `jest` or `mocha` to the types field in your tsconfig. +node_modules/assert/test.js(182,5): error TS2552: Cannot find name 'test'. Did you mean 'tests'? +node_modules/assert/test.js(229,5): error TS2552: Cannot find name 'test'. Did you mean 'tests'? +node_modules/assert/test.js(235,5): error TS2552: Cannot find name 'test'. Did you mean 'tests'? +node_modules/assert/test.js(250,5): error TS2552: Cannot find name 'test'. Did you mean 'tests'? +node_modules/assert/test.js(254,5): error TS2552: Cannot find name 'test'. Did you mean 'tests'? node_modules/assert/test.js(256,55): error TS2345: Argument of type 'TypeError' is not assignable to parameter of type 'string'. -node_modules/assert/test.js(262,5): error TS2593: Cannot find name 'test'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha` and then add `jest` or `mocha` to the types field in your tsconfig. -node_modules/assert/test.js(279,5): error TS2593: Cannot find name 'test'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha` and then add `jest` or `mocha` to the types field in your tsconfig. -node_modules/assert/test.js(285,5): error TS2593: Cannot find name 'test'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha` and then add `jest` or `mocha` to the types field in your tsconfig. -node_modules/assert/test.js(320,5): error TS2593: Cannot find name 'test'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha` and then add `jest` or `mocha` to the types field in your tsconfig. -node_modules/assert/test.js(346,5): error TS2593: Cannot find name 'test'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha` and then add `jest` or `mocha` to the types field in your tsconfig. +node_modules/assert/test.js(262,5): error TS2552: Cannot find name 'test'. Did you mean 'tests'? +node_modules/assert/test.js(279,5): error TS2552: Cannot find name 'test'. Did you mean 'tests'? +node_modules/assert/test.js(285,5): error TS2552: Cannot find name 'test'. Did you mean 'tests'? +node_modules/assert/test.js(320,5): error TS2552: Cannot find name 'test'. Did you mean 'tests'? +node_modules/assert/test.js(346,5): error TS2552: Cannot find name 'test'. Did you mean 'tests'? diff --git a/tests/baselines/reference/user/chrome-devtools-frontend.log b/tests/baselines/reference/user/chrome-devtools-frontend.log index bad901d3d57..c9ce3bc730b 100644 --- a/tests/baselines/reference/user/chrome-devtools-frontend.log +++ b/tests/baselines/reference/user/chrome-devtools-frontend.log @@ -3990,10 +3990,9 @@ node_modules/chrome-devtools-frontend/front_end/console/ConsoleView.js(1277,60): node_modules/chrome-devtools-frontend/front_end/console/ConsoleView.js(1278,42): error TS2769: No overload matches this call. Overload 1 of 2, '(...items: ConcatArray<{ key: string; text: string; regex: RegExp; negative: boolean; }>[]): { key: string; text: string; regex: RegExp; negative: boolean; }[]', gave the following error. Argument of type '{ key: any; text: string; negative: boolean; }[]' is not assignable to parameter of type 'ConcatArray<{ key: string; text: string; regex: RegExp; negative: boolean; }>'. - Types of property 'slice' are incompatible. - Type '(start?: number, end?: number) => { key: any; text: string; negative: boolean; }[]' is not assignable to type '(start?: number, end?: number) => { key: string; text: string; regex: RegExp; negative: boolean; }[]'. - Type '{ key: any; text: string; negative: boolean; }[]' is not assignable to type '{ key: string; text: string; regex: RegExp; negative: boolean; }[]'. - Property 'regex' is missing in type '{ key: any; text: string; negative: boolean; }' but required in type '{ key: string; text: string; regex: RegExp; negative: boolean; }'. + The types returned by 'slice(...)' are incompatible between these types. + Type '{ key: any; text: string; negative: boolean; }[]' is not assignable to type '{ key: string; text: string; regex: RegExp; negative: boolean; }[]'. + Property 'regex' is missing in type '{ key: any; text: string; negative: boolean; }' but required in type '{ key: string; text: string; regex: RegExp; negative: boolean; }'. Overload 2 of 2, '(...items: ({ key: string; text: string; regex: RegExp; negative: boolean; } | ConcatArray<{ key: string; text: string; regex: RegExp; negative: boolean; }>)[]): { key: string; text: string; regex: RegExp; negative: boolean; }[]', gave the following error. Argument of type '{ key: any; text: string; negative: boolean; }[]' is not assignable to parameter of type '{ key: string; text: string; regex: RegExp; negative: boolean; } | ConcatArray<{ key: string; text: string; regex: RegExp; negative: boolean; }>'. Type '{ key: any; text: string; negative: boolean; }[]' is not assignable to type 'ConcatArray<{ key: string; text: string; regex: RegExp; negative: boolean; }>'. @@ -5038,22 +5037,18 @@ node_modules/chrome-devtools-frontend/front_end/elements/ComputedStyleWidget.js( node_modules/chrome-devtools-frontend/front_end/elements/ComputedStyleWidget.js(91,24): error TS2769: No overload matches this call. The last overload gave the following error. Argument of type '(Promise | Promise)[]' is not assignable to parameter of type 'Iterable>'. - Types of property '[Symbol.iterator]' are incompatible. - Type '() => IterableIterator | Promise>' is not assignable to type '() => Iterator, any, undefined>'. - Type 'IterableIterator | Promise>' is not assignable to type 'Iterator, any, undefined>'. - Types of property 'next' are incompatible. - Type '(...args: [] | [undefined]) => IteratorResult | Promise, any>' is not assignable to type '(...args: [] | [undefined]) => IteratorResult, any>'. - Type 'IteratorResult | Promise, any>' is not assignable to type 'IteratorResult, any>'. - Type 'IteratorYieldResult | Promise>' is not assignable to type 'IteratorResult, any>'. - Type 'IteratorYieldResult | Promise>' is not assignable to type 'IteratorYieldResult>'. - Type 'Promise | Promise' is not assignable to type 'CSSMatchedStyles | PromiseLike'. - Type 'Promise' is not assignable to type 'CSSMatchedStyles | PromiseLike'. - Type 'Promise' is not assignable to type 'PromiseLike'. - Types of property 'then' are incompatible. - Type '(onfulfilled?: (value: ComputedStyle) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike) => Promise' is not assignable to type '(onfulfilled?: (value: CSSMatchedStyles) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike) => PromiseLike<...>'. - Types of parameters 'onfulfilled' and 'onfulfilled' are incompatible. - Types of parameters 'value' and 'value' are incompatible. - Type 'ComputedStyle' is missing the following properties from type 'CSSMatchedStyles': _cssModel, _node, _nodeStyles, _nodeForStyle, and 22 more. + The types returned by '[Symbol.iterator]().next(...)' are incompatible between these types. + Type 'IteratorResult | Promise, any>' is not assignable to type 'IteratorResult, any>'. + Type 'IteratorYieldResult | Promise>' is not assignable to type 'IteratorResult, any>'. + Type 'IteratorYieldResult | Promise>' is not assignable to type 'IteratorYieldResult>'. + Type 'Promise | Promise' is not assignable to type 'CSSMatchedStyles | PromiseLike'. + Type 'Promise' is not assignable to type 'CSSMatchedStyles | PromiseLike'. + Type 'Promise' is not assignable to type 'PromiseLike'. + Types of property 'then' are incompatible. + Type '(onfulfilled?: (value: ComputedStyle) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike) => Promise' is not assignable to type '(onfulfilled?: (value: CSSMatchedStyles) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike) => PromiseLike<...>'. + Types of parameters 'onfulfilled' and 'onfulfilled' are incompatible. + Types of parameters 'value' and 'value' are incompatible. + Type 'ComputedStyle' is missing the following properties from type 'CSSMatchedStyles': _cssModel, _node, _nodeStyles, _nodeForStyle, and 22 more. node_modules/chrome-devtools-frontend/front_end/elements/ComputedStyleWidget.js(147,52): error TS2339: Property 'keysArray' does not exist on type 'Map'. node_modules/chrome-devtools-frontend/front_end/elements/ComputedStyleWidget.js(179,50): error TS2339: Property 'createChild' does not exist on type 'Element'. node_modules/chrome-devtools-frontend/front_end/elements/ComputedStyleWidget.js(200,74): error TS2339: Property 'consume' does not exist on type 'Event'. @@ -5339,22 +5334,18 @@ node_modules/chrome-devtools-frontend/front_end/elements/MetricsSidebarPane.js(5 node_modules/chrome-devtools-frontend/front_end/elements/MetricsSidebarPane.js(82,24): error TS2769: No overload matches this call. The last overload gave the following error. Argument of type '(Promise> | Promise)[]' is not assignable to parameter of type 'Iterable | PromiseLike>>'. - Types of property '[Symbol.iterator]' are incompatible. - Type '() => IterableIterator> | Promise>' is not assignable to type '() => Iterator | PromiseLike>, any, undefined>'. - Type 'IterableIterator> | Promise>' is not assignable to type 'Iterator | PromiseLike>, any, undefined>'. - Types of property 'next' are incompatible. - Type '(...args: [] | [undefined]) => IteratorResult> | Promise, any>' is not assignable to type '(...args: [] | [undefined]) => IteratorResult | PromiseLike>, any>'. - Type 'IteratorResult> | Promise, any>' is not assignable to type 'IteratorResult | PromiseLike>, any>'. - Type 'IteratorYieldResult> | Promise>' is not assignable to type 'IteratorResult | PromiseLike>, any>'. - Type 'IteratorYieldResult> | Promise>' is not assignable to type 'IteratorYieldResult | PromiseLike>>'. - Type 'Promise> | Promise' is not assignable to type 'Map | PromiseLike>'. - Type 'Promise' is not assignable to type 'Map | PromiseLike>'. - Type 'Promise' is not assignable to type 'PromiseLike>'. - Types of property 'then' are incompatible. - Type '(onfulfilled?: (value: InlineStyleResult) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike) => Promise<...>' is not assignable to type ', TResult2 = never>(onfulfilled?: (value: Map) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike) => PromiseLike<...>'. - Types of parameters 'onfulfilled' and 'onfulfilled' are incompatible. - Types of parameters 'value' and 'value' are incompatible. - Type 'InlineStyleResult' is missing the following properties from type 'Map': clear, delete, forEach, get, and 8 more. + The types returned by '[Symbol.iterator]().next(...)' are incompatible between these types. + Type 'IteratorResult> | Promise, any>' is not assignable to type 'IteratorResult | PromiseLike>, any>'. + Type 'IteratorYieldResult> | Promise>' is not assignable to type 'IteratorResult | PromiseLike>, any>'. + Type 'IteratorYieldResult> | Promise>' is not assignable to type 'IteratorYieldResult | PromiseLike>>'. + Type 'Promise> | Promise' is not assignable to type 'Map | PromiseLike>'. + Type 'Promise' is not assignable to type 'Map | PromiseLike>'. + Type 'Promise' is not assignable to type 'PromiseLike>'. + Types of property 'then' are incompatible. + Type '(onfulfilled?: (value: InlineStyleResult) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike) => Promise<...>' is not assignable to type ', TResult2 = never>(onfulfilled?: (value: Map) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike) => PromiseLike<...>'. + Types of parameters 'onfulfilled' and 'onfulfilled' are incompatible. + Types of parameters 'value' and 'value' are incompatible. + Type 'InlineStyleResult' is missing the following properties from type 'Map': clear, delete, forEach, get, and 8 more. node_modules/chrome-devtools-frontend/front_end/elements/MetricsSidebarPane.js(120,11): error TS2339: Property 'consume' does not exist on type 'Event'. node_modules/chrome-devtools-frontend/front_end/elements/MetricsSidebarPane.js(164,22): error TS2339: Property 'toFixedIfFloating' does not exist on type 'NumberConstructor'. node_modules/chrome-devtools-frontend/front_end/elements/MetricsSidebarPane.js(179,18): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. @@ -12648,22 +12639,18 @@ node_modules/chrome-devtools-frontend/front_end/ui/View.js(454,38): error TS2339 node_modules/chrome-devtools-frontend/front_end/ui/View.js(461,44): error TS2769: No overload matches this call. The last overload gave the following error. Argument of type '(Promise | Promise)[]' is not assignable to parameter of type 'Iterable>'. - Types of property '[Symbol.iterator]' are incompatible. - Type '() => IterableIterator | Promise>' is not assignable to type '() => Iterator, any, undefined>'. - Type 'IterableIterator | Promise>' is not assignable to type 'Iterator, any, undefined>'. - Types of property 'next' are incompatible. - Type '(...args: [] | [undefined]) => IteratorResult | Promise, any>' is not assignable to type '(...args: [] | [undefined]) => IteratorResult, any>'. - Type 'IteratorResult | Promise, any>' is not assignable to type 'IteratorResult, any>'. - Type 'IteratorYieldResult | Promise>' is not assignable to type 'IteratorResult, any>'. - Type 'IteratorYieldResult | Promise>' is not assignable to type 'IteratorYieldResult>'. - Type 'Promise | Promise' is not assignable to type 'void | PromiseLike'. - Type 'Promise' is not assignable to type 'void | PromiseLike'. - Type 'Promise' is not assignable to type 'PromiseLike'. - Types of property 'then' are incompatible. - Type '(onfulfilled?: (value: ToolbarItem[]) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike) => Promise' is not assignable to type '(onfulfilled?: (value: void) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike) => PromiseLike'. - Types of parameters 'onfulfilled' and 'onfulfilled' are incompatible. - Types of parameters 'value' and 'value' are incompatible. - Type 'ToolbarItem[]' is not assignable to type 'void'. + The types returned by '[Symbol.iterator]().next(...)' are incompatible between these types. + Type 'IteratorResult | Promise, any>' is not assignable to type 'IteratorResult, any>'. + Type 'IteratorYieldResult | Promise>' is not assignable to type 'IteratorResult, any>'. + Type 'IteratorYieldResult | Promise>' is not assignable to type 'IteratorYieldResult>'. + Type 'Promise | Promise' is not assignable to type 'void | PromiseLike'. + Type 'Promise' is not assignable to type 'void | PromiseLike'. + Type 'Promise' is not assignable to type 'PromiseLike'. + Types of property 'then' are incompatible. + Type '(onfulfilled?: (value: ToolbarItem[]) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike) => Promise' is not assignable to type '(onfulfilled?: (value: void) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike) => PromiseLike'. + Types of parameters 'onfulfilled' and 'onfulfilled' are incompatible. + Types of parameters 'value' and 'value' are incompatible. + Type 'ToolbarItem[]' is not assignable to type 'void'. node_modules/chrome-devtools-frontend/front_end/ui/View.js(495,24): error TS2339: Property 'createTextChild' does not exist on type 'Element'. node_modules/chrome-devtools-frontend/front_end/ui/View.js(496,24): error TS2339: Property 'tabIndex' does not exist on type 'Element'. node_modules/chrome-devtools-frontend/front_end/ui/View.js(501,25): error TS2339: Property 'createChild' does not exist on type 'Element'. diff --git a/tests/baselines/reference/user/prettier.log b/tests/baselines/reference/user/prettier.log index 635c0bc0b36..71fb532b794 100644 --- a/tests/baselines/reference/user/prettier.log +++ b/tests/baselines/reference/user/prettier.log @@ -142,10 +142,9 @@ src/language-html/printer-html.js(314,13): error TS2769: No overload matches thi src/language-html/printer-html.js(471,11): error TS2769: No overload matches this call. Overload 1 of 2, '(...items: ConcatArray[]): never[]', gave the following error. Argument of type '{ type: string; parts: any; }[]' is not assignable to parameter of type 'ConcatArray'. - Types of property 'slice' are incompatible. - Type '(start?: number | undefined, end?: number | undefined) => { type: string; parts: any; }[]' is not assignable to type '(start?: number | undefined, end?: number | undefined) => never[]'. - Type '{ type: string; parts: any; }[]' is not assignable to type 'never[]'. - Type '{ type: string; parts: any; }' is not assignable to type 'never'. + The types returned by 'slice(...)' are incompatible between these types. + Type '{ type: string; parts: any; }[]' is not assignable to type 'never[]'. + Type '{ type: string; parts: any; }' is not assignable to type 'never'. Overload 2 of 2, '(...items: ConcatArray[]): never[]', gave the following error. Argument of type '{ type: string; parts: any; }[]' is not assignable to parameter of type 'ConcatArray'. src/language-html/printer-html.js(492,11): error TS2769: No overload matches this call. @@ -200,11 +199,10 @@ src/language-js/index.js(81,60): error TS2345: Argument of type '{ override: { s src/language-js/needs-parens.js(871,14): error TS2769: No overload matches this call. Overload 1 of 2, '(...items: ConcatArray<(childPath: any) => any>[]): ((childPath: any) => any)[]', gave the following error. Argument of type '(string | number)[]' is not assignable to parameter of type 'ConcatArray<(childPath: any) => any>'. - Types of property 'slice' are incompatible. - Type '(start?: number | undefined, end?: number | undefined) => (string | number)[]' is not assignable to type '(start?: number | undefined, end?: number | undefined) => ((childPath: any) => any)[]'. - Type '(string | number)[]' is not assignable to type '((childPath: any) => any)[]'. - Type 'string | number' is not assignable to type '(childPath: any) => any'. - Type 'string' is not assignable to type '(childPath: any) => any'. + The types returned by 'slice(...)' are incompatible between these types. + Type '(string | number)[]' is not assignable to type '((childPath: any) => any)[]'. + Type 'string | number' is not assignable to type '(childPath: any) => any'. + Type 'string' is not assignable to type '(childPath: any) => any'. Overload 2 of 2, '(...items: (((childPath: any) => any) | ConcatArray<(childPath: any) => any>)[]): ((childPath: any) => any)[]', gave the following error. Argument of type '(string | number)[]' is not assignable to parameter of type '((childPath: any) => any) | ConcatArray<(childPath: any) => any>'. Type '(string | number)[]' is not assignable to type 'ConcatArray<(childPath: any) => any>'. @@ -219,56 +217,55 @@ src/language-js/printer-estree.js(400,9): error TS2769: No overload matches this Overload 2 of 2, '(...items: ConcatArray[]): never[]', gave the following error. Argument of type '{ type: string; parts: any; } | { type: string; contents: any; n: any; }' is not assignable to parameter of type 'ConcatArray'. Type '{ type: string; parts: any; }' is not assignable to type 'ConcatArray'. -src/language-js/printer-estree.js(1480,28): error TS2769: No overload matches this call. +src/language-js/printer-estree.js(1481,28): error TS2769: No overload matches this call. Overload 1 of 2, '(...items: ConcatArray[]): (string | { type: string; id: any; contents: any; break: boolean; expandedStates: any; })[]', gave the following error. Argument of type '{ type: string; parts: any; }' is not assignable to parameter of type 'ConcatArray'. Type '{ type: string; parts: any; }' is missing the following properties from type 'ConcatArray': length, join, slice Overload 2 of 2, '(...items: (string | { type: string; id: any; contents: any; break: boolean; expandedStates: any; } | ConcatArray)[]): (string | { ...; })[]', gave the following error. Argument of type '{ type: string; parts: any; }' is not assignable to parameter of type 'string | { type: string; id: any; contents: any; break: boolean; expandedStates: any; } | ConcatArray'. Type '{ type: string; parts: any; }' is missing the following properties from type '{ type: string; id: any; contents: any; break: boolean; expandedStates: any; }': id, contents, break, expandedStates -src/language-js/printer-estree.js(1913,20): error TS2345: Argument of type '" "' is not assignable to parameter of type '{ type: string; id: any; contents: any; break: boolean; expandedStates: any; }'. -src/language-js/printer-estree.js(1915,20): error TS2345: Argument of type '{ type: string; parts: any; }' is not assignable to parameter of type '{ type: string; id: any; contents: any; break: boolean; expandedStates: any; }'. -src/language-js/printer-estree.js(1917,18): error TS2345: Argument of type '"while ("' is not assignable to parameter of type '{ type: string; id: any; contents: any; break: boolean; expandedStates: any; }'. -src/language-js/printer-estree.js(1926,9): error TS2345: Argument of type '")"' is not assignable to parameter of type '{ type: string; id: any; contents: any; break: boolean; expandedStates: any; }'. -src/language-js/printer-estree.js(3472,11): error TS2769: No overload matches this call. +src/language-js/printer-estree.js(1914,20): error TS2345: Argument of type '" "' is not assignable to parameter of type '{ type: string; id: any; contents: any; break: boolean; expandedStates: any; }'. +src/language-js/printer-estree.js(1916,20): error TS2345: Argument of type '{ type: string; parts: any; }' is not assignable to parameter of type '{ type: string; id: any; contents: any; break: boolean; expandedStates: any; }'. +src/language-js/printer-estree.js(1918,18): error TS2345: Argument of type '"while ("' is not assignable to parameter of type '{ type: string; id: any; contents: any; break: boolean; expandedStates: any; }'. +src/language-js/printer-estree.js(1927,9): error TS2345: Argument of type '")"' is not assignable to parameter of type '{ type: string; id: any; contents: any; break: boolean; expandedStates: any; }'. +src/language-js/printer-estree.js(3473,11): error TS2769: No overload matches this call. Overload 1 of 2, '(...items: ConcatArray[]): never[]', gave the following error. Argument of type 'never[] | { type: string; parts: any; }' is not assignable to parameter of type 'ConcatArray'. Type '{ type: string; parts: any; }' is not assignable to type 'ConcatArray'. Overload 2 of 2, '(...items: ConcatArray[]): never[]', gave the following error. Argument of type 'never[] | { type: string; parts: any; }' is not assignable to parameter of type 'ConcatArray'. Type '{ type: string; parts: any; }' is not assignable to type 'ConcatArray'. -src/language-js/printer-estree.js(3901,22): error TS2345: Argument of type 'any' is not assignable to parameter of type 'never'. -src/language-js/printer-estree.js(3968,14): error TS2339: Property 'comments' does not exist on type 'Expression'. +src/language-js/printer-estree.js(3902,22): error TS2345: Argument of type 'any' is not assignable to parameter of type 'never'. +src/language-js/printer-estree.js(3969,14): error TS2339: Property 'comments' does not exist on type 'Expression'. Property 'comments' does not exist on type 'Identifier'. -src/language-js/printer-estree.js(3980,9): error TS2367: This condition will always return 'false' since the types '"FunctionExpression" | "ClassExpression" | "ObjectExpression" | "TaggedTemplateExpression" | "CallExpression" | "ConditionalExpression" | "UpdateExpression" | "SequenceExpression" | ... 11 more ... | "MetaProperty"' and '"OptionalMemberExpression"' have no overlap. -src/language-js/printer-estree.js(3981,13): error TS2339: Property 'property' does not exist on type 'SimpleLiteral | RegExpLiteral | FunctionExpression | ArrowFunctionExpression | ArrayExpression | ObjectExpression | YieldExpression | UnaryExpression | UpdateExpression | ... 12 more ... | AwaitExpression'. +src/language-js/printer-estree.js(3981,9): error TS2367: This condition will always return 'false' since the types '"FunctionExpression" | "ClassExpression" | "ObjectExpression" | "TaggedTemplateExpression" | "CallExpression" | "ConditionalExpression" | "UpdateExpression" | "SequenceExpression" | ... 11 more ... | "MetaProperty"' and '"OptionalMemberExpression"' have no overlap. +src/language-js/printer-estree.js(3982,13): error TS2339: Property 'property' does not exist on type 'SimpleLiteral | RegExpLiteral | FunctionExpression | ArrowFunctionExpression | ArrayExpression | ObjectExpression | YieldExpression | UnaryExpression | UpdateExpression | ... 12 more ... | AwaitExpression'. Property 'property' does not exist on type 'SimpleLiteral'. -src/language-js/printer-estree.js(3981,52): error TS2339: Property 'property' does not exist on type 'SimpleLiteral | RegExpLiteral | FunctionExpression | ArrowFunctionExpression | ArrayExpression | ObjectExpression | YieldExpression | UnaryExpression | UpdateExpression | ... 12 more ... | AwaitExpression'. +src/language-js/printer-estree.js(3982,52): error TS2339: Property 'property' does not exist on type 'SimpleLiteral | RegExpLiteral | FunctionExpression | ArrowFunctionExpression | ArrayExpression | ObjectExpression | YieldExpression | UnaryExpression | UpdateExpression | ... 12 more ... | AwaitExpression'. Property 'property' does not exist on type 'SimpleLiteral'. -src/language-js/printer-estree.js(3986,9): error TS2367: This condition will always return 'false' since the types '"FunctionExpression" | "ClassExpression" | "ObjectExpression" | "TaggedTemplateExpression" | "CallExpression" | "ConditionalExpression" | "UpdateExpression" | "SequenceExpression" | ... 11 more ... | "MetaProperty"' and '"OptionalMemberExpression"' have no overlap. -src/language-js/printer-estree.js(3988,29): error TS2339: Property 'object' does not exist on type 'SimpleLiteral | RegExpLiteral | FunctionExpression | ArrowFunctionExpression | ArrayExpression | ObjectExpression | YieldExpression | UnaryExpression | UpdateExpression | ... 12 more ... | AwaitExpression'. +src/language-js/printer-estree.js(3987,9): error TS2367: This condition will always return 'false' since the types '"FunctionExpression" | "ClassExpression" | "ObjectExpression" | "TaggedTemplateExpression" | "CallExpression" | "ConditionalExpression" | "UpdateExpression" | "SequenceExpression" | ... 11 more ... | "MetaProperty"' and '"OptionalMemberExpression"' have no overlap. +src/language-js/printer-estree.js(3989,29): error TS2339: Property 'object' does not exist on type 'SimpleLiteral | RegExpLiteral | FunctionExpression | ArrowFunctionExpression | ArrayExpression | ObjectExpression | YieldExpression | UnaryExpression | UpdateExpression | ... 12 more ... | AwaitExpression'. Property 'object' does not exist on type 'SimpleLiteral'. -src/language-js/printer-estree.js(3989,22): error TS2339: Property 'comments' does not exist on type 'SimpleLiteral | RegExpLiteral | FunctionExpression | ArrowFunctionExpression | ArrayExpression | ObjectExpression | YieldExpression | UnaryExpression | UpdateExpression | ... 12 more ... | AwaitExpression'. +src/language-js/printer-estree.js(3990,22): error TS2339: Property 'comments' does not exist on type 'SimpleLiteral | RegExpLiteral | FunctionExpression | ArrowFunctionExpression | ArrayExpression | ObjectExpression | YieldExpression | UnaryExpression | UpdateExpression | ... 12 more ... | AwaitExpression'. Property 'comments' does not exist on type 'SimpleLiteral'. -src/language-js/printer-estree.js(3995,9): error TS2367: This condition will always return 'false' since the types '"FunctionExpression" | "ClassExpression" | "ObjectExpression" | "TaggedTemplateExpression" | "CallExpression" | "ConditionalExpression" | "UpdateExpression" | "SequenceExpression" | ... 11 more ... | "MetaProperty"' and '"Identifier"' have no overlap. -src/language-js/printer-estree.js(3996,9): error TS2367: This condition will always return 'false' since the types '"FunctionExpression" | "ClassExpression" | "ObjectExpression" | "TaggedTemplateExpression" | "CallExpression" | "ConditionalExpression" | "UpdateExpression" | "SequenceExpression" | ... 11 more ... | "MetaProperty"' and '"ThisExpression"' have no overlap. -src/language-js/printer-estree.js(4200,23): error TS2532: Object is possibly 'undefined'. -src/language-js/printer-estree.js(4201,24): error TS2532: Object is possibly 'undefined'. -src/language-js/printer-estree.js(4557,5): error TS2345: Argument of type '"" | { type: string; parts: any; } | { type: string; contents: any; }' is not assignable to parameter of type 'string'. +src/language-js/printer-estree.js(3996,9): error TS2367: This condition will always return 'false' since the types '"FunctionExpression" | "ClassExpression" | "ObjectExpression" | "TaggedTemplateExpression" | "CallExpression" | "ConditionalExpression" | "UpdateExpression" | "SequenceExpression" | ... 11 more ... | "MetaProperty"' and '"Identifier"' have no overlap. +src/language-js/printer-estree.js(3997,9): error TS2367: This condition will always return 'false' since the types '"FunctionExpression" | "ClassExpression" | "ObjectExpression" | "TaggedTemplateExpression" | "CallExpression" | "ConditionalExpression" | "UpdateExpression" | "SequenceExpression" | ... 11 more ... | "MetaProperty"' and '"ThisExpression"' have no overlap. +src/language-js/printer-estree.js(4201,23): error TS2532: Object is possibly 'undefined'. +src/language-js/printer-estree.js(4202,24): error TS2532: Object is possibly 'undefined'. +src/language-js/printer-estree.js(4558,5): error TS2345: Argument of type '"" | { type: string; parts: any; } | { type: string; contents: any; }' is not assignable to parameter of type 'string'. Type '{ type: string; parts: any; }' is not assignable to type 'string'. -src/language-js/printer-estree.js(4561,16): error TS2345: Argument of type '{ type: string; parts: any; }' is not assignable to parameter of type 'string'. -src/language-js/printer-estree.js(4609,11): error TS2322: Type '{ type: string; id: any; contents: any; break: boolean; expandedStates: any; }' is not assignable to type 'string'. -src/language-js/printer-estree.js(4624,11): error TS2322: Type '{ type: string; parts: any; }' is not assignable to type 'string'. -src/language-js/printer-estree.js(4636,9): error TS2345: Argument of type '{ type: string; parts: any; }' is not assignable to parameter of type 'string'. -src/language-js/printer-estree.js(4923,9): error TS2554: Expected 0-2 arguments, but got 3. -src/language-js/printer-estree.js(6130,7): error TS2769: No overload matches this call. +src/language-js/printer-estree.js(4562,16): error TS2345: Argument of type '{ type: string; parts: any; }' is not assignable to parameter of type 'string'. +src/language-js/printer-estree.js(4610,11): error TS2322: Type '{ type: string; id: any; contents: any; break: boolean; expandedStates: any; }' is not assignable to type 'string'. +src/language-js/printer-estree.js(4625,11): error TS2322: Type '{ type: string; parts: any; }' is not assignable to type 'string'. +src/language-js/printer-estree.js(4637,9): error TS2345: Argument of type '{ type: string; parts: any; }' is not assignable to parameter of type 'string'. +src/language-js/printer-estree.js(4924,9): error TS2554: Expected 0-2 arguments, but got 3. +src/language-js/printer-estree.js(6131,7): error TS2769: No overload matches this call. Overload 1 of 2, '(...items: ConcatArray<(childPath: any) => any>[]): ((childPath: any) => any)[]', gave the following error. Argument of type '(string | number)[]' is not assignable to parameter of type 'ConcatArray<(childPath: any) => any>'. - Types of property 'slice' are incompatible. - Type '(start?: number | undefined, end?: number | undefined) => (string | number)[]' is not assignable to type '(start?: number | undefined, end?: number | undefined) => ((childPath: any) => any)[]'. - Type '(string | number)[]' is not assignable to type '((childPath: any) => any)[]'. - Type 'string | number' is not assignable to type '(childPath: any) => any'. - Type 'string' is not assignable to type '(childPath: any) => any'. + The types returned by 'slice(...)' are incompatible between these types. + Type '(string | number)[]' is not assignable to type '((childPath: any) => any)[]'. + Type 'string | number' is not assignable to type '(childPath: any) => any'. + Type 'string' is not assignable to type '(childPath: any) => any'. Overload 2 of 2, '(...items: (((childPath: any) => any) | ConcatArray<(childPath: any) => any>)[]): ((childPath: any) => any)[]', gave the following error. Argument of type '(string | number)[]' is not assignable to parameter of type '((childPath: any) => any) | ConcatArray<(childPath: any) => any>'. Type '(string | number)[]' is not assignable to type 'ConcatArray<(childPath: any) => any>'. From aca0bb943f24c57854062b1a0bc13b1d64d73136 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 24 Sep 2019 08:30:18 -0700 Subject: [PATCH 15/17] Fix lint on master --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7a44ac66229..71c72a4cf82 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -33314,7 +33314,7 @@ namespace ts { // Modifiers are never allowed on properties except for 'async' on a method declaration if (prop.modifiers) { - for (const mod of prop.modifiers!) { // TODO: GH#19955 + for (const mod of prop.modifiers) { if (mod.kind !== SyntaxKind.AsyncKeyword || prop.kind !== SyntaxKind.MethodDeclaration) { grammarErrorOnNode(mod, Diagnostics._0_modifier_cannot_be_used_here, getTextOfNode(mod)); } From 4ddf1919bbdf3df09fe32cfdbe3fef7423fc5e51 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 24 Sep 2019 08:47:45 -0700 Subject: [PATCH 16/17] try eslint-disable-next-line instead --- src/compiler/checker.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 71c72a4cf82..e3494a1f341 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -33314,7 +33314,8 @@ namespace ts { // Modifiers are never allowed on properties except for 'async' on a method declaration if (prop.modifiers) { - for (const mod of prop.modifiers) { + // eslint-disable-next-line no-unnecessary-type-assertion + for (const mod of prop.modifiers!) { // TODO: GH#19955 if (mod.kind !== SyntaxKind.AsyncKeyword || prop.kind !== SyntaxKind.MethodDeclaration) { grammarErrorOnNode(mod, Diagnostics._0_modifier_cannot_be_used_here, getTextOfNode(mod)); } From 41c3e545457005c6c8fe3c78f1da56b4379bcf03 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 24 Sep 2019 09:38:44 -0700 Subject: [PATCH 17/17] change eslint-disable rule name --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e3494a1f341..2a3f2390cf3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -33314,7 +33314,7 @@ namespace ts { // Modifiers are never allowed on properties except for 'async' on a method declaration if (prop.modifiers) { - // eslint-disable-next-line no-unnecessary-type-assertion + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion for (const mod of prop.modifiers!) { // TODO: GH#19955 if (mod.kind !== SyntaxKind.AsyncKeyword || prop.kind !== SyntaxKind.MethodDeclaration) { grammarErrorOnNode(mod, Diagnostics._0_modifier_cannot_be_used_here, getTextOfNode(mod));