Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 28 additions & 5 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1512,6 +1512,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
var currentNode: Node | undefined;
var varianceTypeParameter: TypeParameter | undefined;
var isInferencePartiallyBlocked = false;
var propagateAnyFunctionType = true;

var emptySymbols = createSymbolTable();
var arrayVariances = [VarianceFlags.Covariant];
Expand Down Expand Up @@ -2145,7 +2146,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
var anyFunctionType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray);
// The anyFunctionType contains the anyFunctionType by definition. The flag is further propagated
// in getPropagatingFlagsOfTypes, and it is checked in inferFromTypes.
anyFunctionType.objectFlags |= ObjectFlags.NonInferrableType;
anyFunctionType.objectFlags |= ObjectFlags.NonInferrableType | ObjectFlags.ContainsAnyFunctionType;

var noConstraintType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray);
var circularConstraintType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray);
Expand Down Expand Up @@ -26195,7 +26196,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// Before we commit to a particular inference (and thus lock out any further inferences),
// we infer from any intra-expression inference sites we have collected.
inferFromIntraExpressionSites(context);
clearCachedInferences(context.inferences);
clearCachedInferences(context.inferences, true);
inference.isFixed = true;
}
return getInferredType(context, i);
Expand All @@ -26212,8 +26213,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
);
}

function clearCachedInferences(inferences: InferenceInfo[]) {
function clearCachedInferences(inferences: InferenceInfo[], clearSeenAnyFunctionType?: boolean) {
for (const inference of inferences) {
if (clearSeenAnyFunctionType && inference.seenAnyFunctionType) {
inference.seenAnyFunctionType = false;
inference.inferredType = undefined;
}
if (!inference.isFixed) {
inference.inferredType = undefined;
}
Expand Down Expand Up @@ -26694,7 +26699,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (!couldContainTypeVariables(target) || isNoInferType(target)) {
return;
}
if (source === wildcardType || source === blockedStringType) {
if (source === wildcardType || source === blockedStringType || propagateAnyFunctionType && source === anyFunctionType) {
// We are inferring from an 'any' type. We want to infer this type for every type parameter
// referenced in the target type, so we record it as the propagation type and infer from the
// target to itself. Then, as we find candidates we substitute the propagation type.
Expand Down Expand Up @@ -26793,19 +26798,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
//
// As a special case, also ignore nonInferrableAnyType, which is a special form of the any type
// used as a stand-in for binding elements when they are being inferred.
if (getObjectFlags(source) & ObjectFlags.NonInferrableType || source === nonInferrableAnyType) {
const objectFlags = getObjectFlags(source);
if ((objectFlags & (ObjectFlags.NonInferrableType | (propagateAnyFunctionType ? ObjectFlags.ContainsAnyFunctionType : 0))) === ObjectFlags.NonInferrableType || source === nonInferrableAnyType) {
return;
}
if (!inference.isFixed) {
const candidate = propagationType || source;
if (candidate === blockedStringType) {
return;
}
if (propagateAnyFunctionType && getObjectFlags(candidate) & ObjectFlags.ContainsAnyFunctionType) {
// basically it means that
if (!hasInferenceCandidates(inference)) {
inference.seenAnyFunctionType = true;
}
return;
}
if (inference.priority === undefined || priority < inference.priority) {
inference.candidates = undefined;
inference.contraCandidates = undefined;
inference.topLevel = true;
inference.priority = priority;
inference.seenAnyFunctionType = false;
}
if (priority === inference.priority) {
// We make contravariant inferences only if we are in a pure contravariant position,
Expand Down Expand Up @@ -27542,6 +27556,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// We use silentNeverType as the wildcard that signals no inferences.
inferredType = silentNeverType;
}
else if (inference.seenAnyFunctionType) {
inferredType = wildcardType;
}
else {
// Infer either the default or the empty object type when no inferences were
// made. It is important to remember that in this case, inference still
Expand Down Expand Up @@ -36745,6 +36762,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// round of type inference and applicability checking for this particular candidate.
argCheckMode = CheckMode.Normal;
if (inferenceContext) {
if (some(inferenceContext.inferences, i => !!i.seenAnyFunctionType)) {
clearCachedInferences(inferenceContext.inferences, true);
}
const typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode, inferenceContext);
checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext.inferredTypeParameters);
// If the original signature has a generic rest type, instantiation may produce a
Expand Down Expand Up @@ -36873,7 +36893,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {

function inferSignatureInstantiationForOverloadFailure(node: CallLikeExpression, typeParameters: readonly TypeParameter[], candidate: Signature, args: readonly Expression[], checkMode: CheckMode): Signature {
const inferenceContext = createInferenceContext(typeParameters, candidate, /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None);
const savePropagateAnyFunctionType = propagateAnyFunctionType;
propagateAnyFunctionType = false;
const typeArgumentTypes = inferTypeArguments(node, candidate, args, checkMode | CheckMode.SkipContextSensitive | CheckMode.SkipGenericFunctions, inferenceContext);
propagateAnyFunctionType = savePropagateAnyFunctionType;
return createSignatureInstantiation(candidate, typeArgumentTypes);
}

Expand Down
5 changes: 4 additions & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6531,11 +6531,13 @@ export const enum ObjectFlags {
/** @internal */
CouldContainTypeVariables = 1 << 20, // Type could contain a type variable
SingleSignatureType = 1 << 27, // A single signature type extracted from a potentially broader type
/** @internal */
ContainsAnyFunctionType = 1 << 28, // pick a better value maybe
ClassOrInterface = Class | Interface,
/** @internal */
RequiresWidening = ContainsWideningType | ContainsObjectOrArrayLiteral,
/** @internal */
PropagatingFlags = ContainsWideningType | ContainsObjectOrArrayLiteral | NonInferrableType,
PropagatingFlags = ContainsWideningType | ContainsObjectOrArrayLiteral | NonInferrableType | ContainsAnyFunctionType,
/** @internal */
InstantiatedMapped = Mapped | Instantiated,
// Object flags that uniquely identify the kind of ObjectType
Expand Down Expand Up @@ -7111,6 +7113,7 @@ export interface InferenceInfo {
topLevel: boolean; // True if all inferences are to top level occurrences
isFixed: boolean; // True if inferences are fixed
impliedArity?: number;
seenAnyFunctionType?: boolean
}

// dprint-ignore
Expand Down
Loading
Loading