From 01789d387089491b9a4c961723d842019dc7dcee Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Thu, 14 Jul 2022 18:37:13 -0700 Subject: [PATCH 1/2] Clean up inference of type parameters, contravariant types --- src/compiler/checker.ts | 46 ++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ecbc98ee4955c..6c343dc5fc563 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -22556,15 +22556,11 @@ namespace ts { inferFromTypeArguments(getTypeArguments(source as TypeReference), getTypeArguments(target as TypeReference), getVariances((source as TypeReference).target)); } else if (source.flags & TypeFlags.Index && target.flags & TypeFlags.Index) { - contravariant = !contravariant; - inferFromTypes((source as IndexType).type, (target as IndexType).type); - contravariant = !contravariant; + inferFromContravariantTypes((source as IndexType).type, (target as IndexType).type); } else if ((isLiteralType(source) || source.flags & TypeFlags.String) && target.flags & TypeFlags.Index) { const empty = createEmptyObjectTypeFromStringLiteral(source); - contravariant = !contravariant; - inferWithPriority(empty, (target as IndexType).type, InferencePriority.LiteralKeyof); - contravariant = !contravariant; + inferFromContravariantTypesWithPriority(empty, (target as IndexType).type, InferencePriority.LiteralKeyof); } else if (source.flags & TypeFlags.IndexedAccess && target.flags & TypeFlags.IndexedAccess) { inferFromTypes((source as IndexedAccessType).objectType, (target as IndexedAccessType).objectType); @@ -22577,10 +22573,7 @@ namespace ts { } else if (source.flags & TypeFlags.Substitution) { inferFromTypes((source as SubstitutionType).baseType, target); - const oldPriority = priority; - priority |= InferencePriority.SubstituteSource; - inferFromTypes((source as SubstitutionType).substitute, target); // Make substitute inference at a lower priority - priority = oldPriority; + inferWithPriority((source as SubstitutionType).substitute, target, InferencePriority.SubstituteSource); // Make substitute inference at a lower priority } else if (target.flags & TypeFlags.Conditional) { invokeOnce(source, target, inferToConditionalType); @@ -22631,6 +22624,20 @@ namespace ts { priority = savePriority; } + function inferFromContravariantTypesWithPriority(source: Type, target: Type, newPriority: InferencePriority) { + const savePriority = priority; + priority |= newPriority; + inferFromContravariantTypes(source, target); + priority = savePriority; + } + + function inferToMultipleTypesWithPriority(source: Type, targets: Type[], targetFlags: TypeFlags, newPriority: InferencePriority) { + const savePriority = priority; + priority |= newPriority; + inferToMultipleTypes(source, targets, targetFlags); + priority = savePriority; + } + function invokeOnce(source: Type, target: Type, action: (source: Type, target: Type) => void) { const key = source.id + "," + target.id; const status = visited && visited.get(key); @@ -22694,10 +22701,14 @@ namespace ts { } function inferFromContravariantTypes(source: Type, target: Type) { + contravariant = !contravariant; + inferFromTypes(source, target); + contravariant = !contravariant; + } + + function inferFromContravariantTypesIfStrictFunctionTypes(source: Type, target: Type) { if (strictFunctionTypes || priority & InferencePriority.AlwaysStrict) { - contravariant = !contravariant; - inferFromTypes(source, target); - contravariant = !contravariant; + inferFromContravariantTypes(source, target); } else { inferFromTypes(source, target); @@ -22860,11 +22871,8 @@ namespace ts { inferFromTypes(getFalseTypeFromConditionalType(source as ConditionalType), getFalseTypeFromConditionalType(target)); } else { - const savePriority = priority; - priority |= contravariant ? InferencePriority.ContravariantConditional : 0; const targetTypes = [getTrueTypeFromConditionalType(target), getFalseTypeFromConditionalType(target)]; - inferToMultipleTypes(source, targetTypes, target.flags); - priority = savePriority; + inferToMultipleTypesWithPriority(source, targetTypes, target.flags, contravariant ? InferencePriority.ContravariantConditional : 0); } } @@ -23059,7 +23067,7 @@ namespace ts { const kind = target.declaration ? target.declaration.kind : SyntaxKind.Unknown; // Once we descend into a bivariant signature we remain bivariant for all nested inferences bivariant = bivariant || kind === SyntaxKind.MethodDeclaration || kind === SyntaxKind.MethodSignature || kind === SyntaxKind.Constructor; - applyToParameterTypes(source, target, inferFromContravariantTypes); + applyToParameterTypes(source, target, inferFromContravariantTypesIfStrictFunctionTypes); bivariant = saveBivariant; applyToReturnTypes(source, target, inferFromTypes); } @@ -30072,7 +30080,7 @@ namespace ts { // Instantiate a generic signature in the context of a non-generic signature (section 3.8.5 in TypeScript spec) function instantiateSignatureInContextOf(signature: Signature, contextualSignature: Signature, inferenceContext?: InferenceContext, compareTypes?: TypeComparer): Signature { - const context = createInferenceContext(signature.typeParameters!, signature, InferenceFlags.None, compareTypes); + const context = createInferenceContext(signature.typeParameters!, signature, inferenceContext?.flags ?? InferenceFlags.None, compareTypes); // We clone the inferenceContext to avoid fixing. For example, when the source signature is (x: T) => T[] and // the contextual signature is (...args: A) => B, we want to infer the element type of A's constraint (say 'any') // for T but leave it possible to later infer '[any]' back to A. From 4c5d4c198ccd98c143a0cb4d5671cf8e031d959e Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 19 Jul 2022 14:58:48 -0700 Subject: [PATCH 2/2] Remove unintentional change --- 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 6c343dc5fc563..cf5c410995de8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -30080,7 +30080,7 @@ namespace ts { // Instantiate a generic signature in the context of a non-generic signature (section 3.8.5 in TypeScript spec) function instantiateSignatureInContextOf(signature: Signature, contextualSignature: Signature, inferenceContext?: InferenceContext, compareTypes?: TypeComparer): Signature { - const context = createInferenceContext(signature.typeParameters!, signature, inferenceContext?.flags ?? InferenceFlags.None, compareTypes); + const context = createInferenceContext(signature.typeParameters!, signature, InferenceFlags.None, compareTypes); // We clone the inferenceContext to avoid fixing. For example, when the source signature is (x: T) => T[] and // the contextual signature is (...args: A) => B, we want to infer the element type of A's constraint (say 'any') // for T but leave it possible to later infer '[any]' back to A.