diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index beb75fd16d2dc..7d74a101b3d55 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -797,6 +797,7 @@ import { mangleScopedPackageName, map, mapDefined, + mapIterator, MappedSymbol, MappedType, MappedTypeNode, @@ -912,6 +913,7 @@ import { resolveTripleslashReference, resolvingEmptyArray, RestTypeNode, + returnFalse, ReturnStatement, ReverseMappedSymbol, ReverseMappedType, @@ -14816,25 +14818,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { isInJSFile(signature.declaration)); } - function getBaseSignature(signature: Signature) { - const typeParameters = signature.typeParameters; - if (typeParameters) { - if (signature.baseSignatureCache) { - return signature.baseSignatureCache; - } - const typeEraser = createTypeEraser(typeParameters); - const baseConstraintMapper = createTypeMapper(typeParameters, map(typeParameters, tp => getConstraintOfTypeParameter(tp) || unknownType)); - let baseConstraints: readonly Type[] = map(typeParameters, tp => instantiateType(tp, baseConstraintMapper) || unknownType); - // Run N type params thru the immediate constraint mapper up to N times - // This way any noncircular interdependent type parameters are definitely resolved to their external dependencies - for (let i = 0; i < typeParameters.length - 1; i++) { - baseConstraints = instantiateTypes(baseConstraints, baseConstraintMapper); - } - // and then apply a type eraser to remove any remaining circularly dependent type parameters - baseConstraints = instantiateTypes(baseConstraints, typeEraser); - return signature.baseSignatureCache = instantiateSignature(signature, createTypeMapper(typeParameters, baseConstraints), /*eraseTypeParameters*/ true); + function getTypeParameterConstraintMapper(typeParameters: readonly TypeParameter[]) { + const typeEraser = createTypeEraser(typeParameters); + const baseConstraintMapper = createTypeMapper(typeParameters, map(typeParameters, tp => getConstraintOfTypeParameter(tp) || unknownType)); + let baseConstraints: readonly Type[] = map(typeParameters, tp => instantiateType(tp, baseConstraintMapper) || unknownType); + // Run N type params thru the immediate constraint mapper up to N times + // This way any noncircular interdependent type parameters are definitely resolved to their external dependencies + for (let i = 0; i < typeParameters.length - 1; i++) { + baseConstraints = instantiateTypes(baseConstraints, baseConstraintMapper); } - return signature; + // and then apply a type eraser to remove any remaining circularly dependent type parameters + baseConstraints = instantiateTypes(baseConstraints, typeEraser); + return createTypeMapper(typeParameters, baseConstraints); } function getOrCreateTypeFromSignature(signature: Signature): ObjectType { @@ -17713,9 +17708,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We don't want inferences from constraints as they may cause us to eagerly resolve the // conditional type instead of deferring resolution. Also, we always want strict function // types rules (i.e. proper contravariance) for inferences. - inferTypes(context.inferences, checkType, instantiateType(extendsType, freshMapper), InferencePriority.NoConstraints | InferencePriority.AlwaysStrict); + inferTypes(context, checkType, instantiateType(extendsType, freshMapper), InferencePriority.NoConstraints | InferencePriority.AlwaysStrict); } - const innerMapper = combineTypeMappers(freshMapper, context.mapper); + const innerMapper = combineTypeMappers(freshMapper, getMapperFromContext(context)); // It's possible for 'infer T' type paramteters to be given uninstantiated constraints when the // those type parameters are used in type references (see getInferredTypeParameterConstraint). For // that reason we need context.mapper to be first in the combined mapper. See #42636 for examples. @@ -18506,8 +18501,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Maps forward-references to later types parameters to the empty object type. * This is used during inference when instantiating type parameter defaults. */ - function createBackreferenceMapper(context: InferenceContext, index: number): TypeMapper { - const forwardInferences = context.inferences.slice(index); + function createBackreferenceMapper(context: InferenceContext, inference: InferenceInfo): TypeMapper { + const inferences = context.inferences.indexOf(inference) >= 0 ? context.inferences : context.freeTypeVariables; + Debug.assert(inferences, "Inference for backreference mapper must exist within provided context"); + const index = inferences.indexOf(inference); + const forwardInferences = inferences.slice(index); return createTypeMapper(map(forwardInferences, i => i.typeParameter), map(forwardInferences, () => unknownType)); } @@ -21521,9 +21519,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (sourceParams) { // If the source has infer type parameters, we instantiate them in the context of the target const ctx = createInferenceContext(sourceParams, /*signature*/ undefined, InferenceFlags.None, isRelatedToWorker); - inferTypes(ctx.inferences, (target as ConditionalType).extendsType, sourceExtends, InferencePriority.NoConstraints | InferencePriority.AlwaysStrict); - sourceExtends = instantiateType(sourceExtends, ctx.mapper); - mapper = ctx.mapper; + inferTypes(ctx, (target as ConditionalType).extendsType, sourceExtends, InferencePriority.NoConstraints | InferencePriority.AlwaysStrict); + const newMapper = getMapperFromContext(ctx); + sourceExtends = instantiateType(sourceExtends, newMapper); + mapper = newMapper; } if (isTypeIdenticalTo(sourceExtends, (target as ConditionalType).extendsType) && (isRelatedTo((source as ConditionalType).checkType, (target as ConditionalType).checkType, RecursionFlags.Both) || isRelatedTo((target as ConditionalType).checkType, (source as ConditionalType).checkType, RecursionFlags.Both))) { @@ -23687,7 +23686,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function cloneInferenceContext(context: T, extraFlags: InferenceFlags = 0): InferenceContext | T & undefined { - return context && createInferenceContextWorker(map(context.inferences, cloneInferenceInfo), context.signature, context.flags | extraFlags, context.compareTypes); + const newContext = context && createInferenceContextWorker(map(context.inferences, cloneInferenceInfo), context.signature, context.flags | extraFlags, context.compareTypes); + if (context && context.freeTypeVariables) { + newContext.freeTypeVariables = map(context.freeTypeVariables, cloneInferenceInfo); + newContext.freeTypeVariableSourceSignatures = new Map(mapIterator(context.freeTypeVariableSourceSignatures!.entries(), ([k, v]) => [k, new Map(v.entries())])); + } + return newContext; } function createInferenceContextWorker(inferences: InferenceInfo[], signature: Signature | undefined, flags: InferenceFlags, compareTypes: TypeComparer): InferenceContext { @@ -23705,7 +23709,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function makeFixingMapperForContext(context: InferenceContext) { - return makeDeferredTypeMapper(map(context.inferences, i => i.typeParameter), map(context.inferences, (inference, i) => () => { + return makeDeferredTypeMapper(map(context.inferences, i => i.typeParameter), map(context.inferences, (inference) => () => { if (!inference.isFixed) { // 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. @@ -23713,16 +23717,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { clearCachedInferences(context.inferences); inference.isFixed = true; } - return getInferredType(context, i); + return getInferredType(context, inference); })); } function makeNonFixingMapperForContext(context: InferenceContext) { - return makeDeferredTypeMapper(map(context.inferences, i => i.typeParameter), map(context.inferences, (_, i) => () => { - return getInferredType(context, i); + return makeDeferredTypeMapper(map(context.inferences, i => i.typeParameter), map(context.inferences, (inference) => () => { + return getInferredType(context, inference); })); } + function makeFreeTypeVariableMapperForContext(context: InferenceContext) { + if (!context.freeTypeVariables) return undefined; + // make a seperate mapper for every free type variable so free type variables constrained to one another are instantiated + // with any intermediate inferences found rather than the constraints + const baseMapper = getTypeParameterConstraintMapper(map(context.freeTypeVariables, i => i.typeParameter)); + return context.freeTypeVariables.reduceRight( + (previous, i) => combineTypeMappers(makeDeferredTypeMapper([i.typeParameter], [() => hasInferenceCandidatesOrDefault(i) ? getInferredType(context, i) : instantiateType(i.typeParameter, baseMapper)]), previous), + baseMapper + ); + } + function clearCachedInferences(inferences: InferenceInfo[]) { for (const inference of inferences) { if (!inference.isFixed) { @@ -23755,7 +23770,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { getContextualTypeForObjectLiteralMethod(node as MethodDeclaration, ContextFlags.NoConstraints) : getContextualType(node, ContextFlags.NoConstraints); if (contextualType) { - inferTypes(context.inferences, type, contextualType); + inferTypes(context, type, contextualType); } } context.intraExpressionInferenceSites = undefined; @@ -23795,8 +23810,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { undefined; } + /** + * Note: for historical reasons, this function is not alternative-context-aware, instead preferring results from the last alternative. + * If you want to handle multiple inference alternatives, you need to iterate over flattenInferenceContextAlternatives(context) in the caller + * and decide how to handle multiple possible inference results! + */ function getMapperFromContext(context: T): TypeMapper | T & undefined { - return context && context.mapper; + const innerContext = context && last(flattenInferenceContextAlternatives(context)); + return innerContext && innerContext.mapper && (innerContext.freeTypeVariables ? combineTypeMappers(innerContext.mapper, makeFreeTypeVariableMapperForContext(innerContext)!) : innerContext.mapper); } // Return true if the given type could possibly reference a type parameter for which @@ -23931,8 +23952,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const typeParameter = getIndexedAccessType(constraint.type, getTypeParameterFromMappedType(target)) as TypeParameter; const templateType = getTemplateTypeFromMappedType(target); const inference = createInferenceInfo(typeParameter); - inferTypes([inference], sourceType, templateType); - return getTypeFromInference(inference) || unknownType; + const context = createInferenceContextWorker([inference], /*signature*/ undefined, InferenceFlags.None, compareTypesAssignable); + inferTypes(context, sourceType, templateType); + // By passing `returnFalse` here, we select the last option inferred from any overload lists - + // this matches historical behavior, but we can probably do better here. There's maybe a constraint we could check against? + return getInferredTypes(context, returnFalse)[0] || unknownType; } function* getUnmatchedProperties(source: Type, target: Type, requireOptionalProperties: boolean, matchDiscriminantProperties: boolean): IterableIterator { @@ -24157,7 +24181,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority = InferencePriority.None, contravariant = false) { + /** + * Merges the outer inference context into its alternatives and returns them, or + * just returns an array containing the outer context if there are no alternatives. + */ + function flattenInferenceContextAlternatives(context: InferenceContext): InferenceContext[] { + return context.alternatives ? (context.alternatives.forEach(a => mergeInferenceContexts(a, context, /*clone*/ true)), context.alternatives) : [context]; + } + + function inferTypes(context: InferenceContext, originalSource: Type, originalTarget: Type, priority = InferencePriority.None, contravariant = false) { let bivariant = false; let propagationType: Type; let inferencePriority: number = InferencePriority.MaxValue; @@ -24166,7 +24198,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let sourceStack: object[]; let targetStack: object[]; let expandingFlags = ExpandingFlags.None; + let useOnlyCachedAlternativeRoutes = false; inferFromTypes(originalSource, originalTarget); + // second inference stage to the non-fixing-mapped target ensures we record mappings for + // the free type variables in the context which come from signature inferences, + // which we need so we can map the free type variables entirely out of the resulting inferred types + // once inference is complete with a better mapping than their constraint. + useOnlyCachedAlternativeRoutes = true; + // For the followup passes, by using only cached alternative routes (and bailing on those alternatives which lack a cache entry), + // we can avoid creating a power set of combinations by only exploring the set of inferences where an overload is only influenced by itself, and + // not by sibling signatures from a prior pass. + + const group = forkInferenceContext(); + spawnAlternativeInferenceContext(group, () => { + if (length(context.freeTypeVariables)) { + inferFromTypes(originalSource, instantiateType(originalTarget, context.nonFixingMapper)); + } + }, /*fork*/ false); + joinInferenceContext(group); function inferFromTypes(source: Type, target: Type): void { if (!couldContainTypeVariables(target)) { @@ -24271,6 +24320,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (getObjectFlags(source) & ObjectFlags.NonInferrableType || source === nonInferrableAnyType) { return; } + if (useOnlyCachedAlternativeRoutes && source === target) { + // refrain from inferring a type to itself during a followup pass - it won't add extra information + return; + } if (!inference.isFixed) { if (inference.priority === undefined || priority < inference.priority) { inference.candidates = undefined; @@ -24285,17 +24338,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (contravariant && !bivariant) { if (!contains(inference.contraCandidates, candidate)) { inference.contraCandidates = append(inference.contraCandidates, candidate); - clearCachedInferences(inferences); + clearCachedInferences(context.inferences); } } else if (!contains(inference.candidates, candidate)) { inference.candidates = append(inference.candidates, candidate); - clearCachedInferences(inferences); + clearCachedInferences(context.inferences); } } if (!(priority & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter && inference.topLevel && !isTypeParameterAtTopLevel(originalTarget, target as TypeParameter)) { inference.topLevel = false; - clearCachedInferences(inferences); + clearCachedInferences(context.inferences); } } inferencePriority = Math.min(inferencePriority, priority); @@ -24486,7 +24539,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getInferenceInfoForType(type: Type) { if (type.flags & TypeFlags.TypeVariable) { - for (const inference of inferences) { + for (const inference of context.inferences) { + if (type === inference.typeParameter) { + return inference; + } + } + for (const inference of context.freeTypeVariables || []) { if (type === inference.typeParameter) { return inference; } @@ -24849,18 +24907,136 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } + /** + * Semantically starts a new group of alternatives within the active inference context + */ + function forkInferenceContext(): InferenceContext[] { + return []; + } + + /** + * Performs the given action in every alternative inference context currently under consideration, + * and add the resulting context(s) to a new resultant context list. + * + * Call multiple times to create multiple independent forks of the existing inference engine state. + * Call once with fork `false` to simply to do and action for every existing branch of the inference + * engine state, while handling if those actions produce further forks of the state. + */ + function spawnAlternativeInferenceContext(group: InferenceContext[], action: () => void, fork = true) { + const oldContext = context; + // We want to keep a flat list of alternatives in the top-level inference context; + // so we perform our new forking action for each existing alternative, and then when + // we're done making all the new forks, we'll replace the existing alternative list + // with the new one. + flattenInferenceContextAlternatives(context).forEach(alternative => { + // It's intentional that the `clone` here doesn't clone the `alternatives` - we want this + // fork to be ignorant to the other forks we'll be trying - only the outermost context + // should retain knowledge of the many linked inference attempts we're making. + const newContext = fork ? cloneInferenceContext(alternative) : alternative; + context = newContext; + action(); + context = oldContext; + group.push(...flattenInferenceContextAlternatives(newContext)); + }); + } + + /** + * Resets the alternatives list for the active infernce context to the supplied group of inference contexts + */ + function joinInferenceContext(group: InferenceContext[]) { + group = group.length < 10 ? deduplicate(group, compareInferenceContext) : group; + if (group.length === 1) { + // Only one alternative was tried - inline it as the new outer context. + mergeInferenceContexts(context, group[0]); + context.freeTypeVariables = group[0].freeTypeVariables; + context.freeTypeVariableSourceSignatures = group[0].freeTypeVariableSourceSignatures; + context.inferredTypeParameters = group[0].inferredTypeParameters; + context.flags = group[0].flags; + context.alternatives = undefined; + return; + } + context.alternatives = group; + } + + function compareInferenceContext(a: InferenceContext, b: InferenceContext): boolean { + return a.compareTypes === b.compareTypes + && a.flags === b.flags + && a.inferredTypeParameters === b.inferredTypeParameters + && a.intraExpressionInferenceSites === b.intraExpressionInferenceSites + && a.signature === b.signature + && compareInferencesIdentical(a, a.inferences, b, b.inferences) + && compareInferencesIdentical(a, a.freeTypeVariables, b, b.freeTypeVariables); + } + + function compareInferencesIdentical(ctxA: InferenceContext, a: InferenceInfo[] | undefined, ctxB: InferenceContext, b: InferenceInfo[] | undefined): boolean { + if (length(a) !== length(b)) return false; + if (length(a) === 0) return true; + for (let i = 0; i < length(a); i++) { + if ( + a![i].typeParameter !== b![i].typeParameter || + a![i].impliedArity !== b![i].impliedArity || + a![i].isFixed !== b![i].isFixed || + a![i].priority !== b![i].priority || + a![i].topLevel !== b![i].topLevel || + forEach(a, (_, i) => getInferredType(ctxA, a![i]) !== getInferredType(ctxB, b![i])) + ) return false; + } + return true; + } + function inferFromSignatures(source: Type, target: Type, kind: SignatureKind) { const sourceSignatures = getSignaturesOfType(source, kind); const targetSignatures = getSignaturesOfType(target, kind); const sourceLen = sourceSignatures.length; const targetLen = targetSignatures.length; - const len = sourceLen < targetLen ? sourceLen : targetLen; - for (let i = 0; i < len; i++) { - inferFromSignature(getBaseSignature(sourceSignatures[sourceLen - len + i]), getErasedSignature(targetSignatures[targetLen - len + i])); + if (targetLen === 1 && sourceLen > 1) { + // inference from a set of overloads to a single signature - produce matches for _every_ overload + const group = forkInferenceContext(); + for (let i = 0; i < sourceLen; i++) { + if (useOnlyCachedAlternativeRoutes && !context.freeTypeVariableSourceSignatures?.get(last(sourceStack))?.get(sourceSignatures[i])) { + continue; // Doing a follow-up pass - ignore new alternatives that don't follow the same "route" as the first pass + } + spawnAlternativeInferenceContext(group, () => + inferFromSignature(sourceSignatures[i], targetSignatures[0]) + ); + } + joinInferenceContext(group); + } + else { + // match from end of lists backwards the minimum signature length + // (legacy behavior - this is able to produce _a_ match, not necessarily a _good_ match) + const len = sourceLen < targetLen ? sourceLen : targetLen; + for (let i = 0; i < len; i++) { + inferFromSignature(sourceSignatures[sourceLen - len + i], targetSignatures[targetLen - len + i]); + } } } function inferFromSignature(source: Signature, target: Signature) { + target = getErasedSignature(target); + if (source.typeParameters) { + // Rather than getting the "base" signature, add the type parameters as free type variables to the inference list + // These get saved off so we can infer from the expression type to them after we apply contextual types, and then + // apply those mappings to our inference results. + // Create a fresh clone of the source with a fresh clone of the source's type parameters, so recursive invocations + // don't use the same type variable inferences (the noop mapper simply forces the clone) + // BUT we want to retain the same signature and type parameters between inference passes at the same depth, + // so we cache this signature on the context + let cache = (context.freeTypeVariableSourceSignatures ||= new Map()).get(last(sourceStack)); + if (!cache) { + context.freeTypeVariableSourceSignatures.set(last(sourceStack), cache = (new Map())); + } + const cached = cache.get(source); + if (cached) { + source = cached; // The relevant free type variables should already be in the context, no need to add more + } + else { + const originalSignature = source; + source = instantiateSignature(source, makeUnaryTypeMapper(unknownType, unknownType)); + cache.set(originalSignature, source); + (context.freeTypeVariables ||= []).push(...map(source.typeParameters!, createInferenceInfo)); + } + } const saveBivariant = bivariant; const kind = target.declaration ? target.declaration.kind : SyntaxKind.Unknown; // Once we descend into a bivariant signature we remain bivariant for all nested inferences @@ -24961,8 +25137,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getWidenedType(unwidenedType); } - function getInferredType(context: InferenceContext, index: number): Type { - const inference = context.inferences[index]; + function getInferredType(context: InferenceContext, inference: InferenceInfo): Type { if (!inference.inferredType) { let inferredType: Type | undefined; const signature = context.signature; @@ -24996,7 +25171,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (defaultType) { // Instantiate the default type. Any forward reference to a type // parameter should be instantiated to the empty object type. - inferredType = instantiateType(defaultType, mergeTypeMappers(createBackreferenceMapper(context, index), context.nonFixingMapper)); + inferredType = instantiateType(defaultType, mergeTypeMappers(createBackreferenceMapper(context, inference), context.nonFixingMapper)); } } } @@ -25022,12 +25197,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return isInJavaScriptFile ? anyType : unknownType; } - function getInferredTypes(context: InferenceContext): Type[] { - const result: Type[] = []; - for (let i = 0; i < context.inferences.length; i++) { - result.push(getInferredType(context, i)); + function getInferredTypes(context: InferenceContext, accept: (types: Type[]) => boolean): Type[] { + const alternatives = flattenInferenceContextAlternatives(context); + let finalAlternative: Type[] | undefined; + for (let a = alternatives.length - 1; a >= 0; a--) { + const context = alternatives[a]; + // This mapper isn't cached on the context, as the list of free type variables is generated as inference is performed, + // so the mappings in this mapper can evolve as inference progresses and more free type variables are + // introduced. + const freeTypeVariableMapper = makeFreeTypeVariableMapperForContext(context); + const result: Type[] = []; + for (const inference of context.inferences) { + result.push(instantiateType(getInferredType(context, inference), freeTypeVariableMapper)); + } + // Skip calling `accept` when there's only 1 alternative to try, as it can end up fixing expression types, which we can trivially avoid + // in simple cases when the inference result has to be used since it's the only one. + if ((alternatives.length === 1) || accept(result)) { + return result; + } + if (!finalAlternative) { + // The last alternative in the list most closely mirrors previous behaviors of only considering the final overload in a list + // during inference. If none pass the `accept` function, this is the one which'll be used (likely for error reporting! It's + // possible to improve upon this for better errors, much like we how we do union member selection for errors in relationship checking!) + finalAlternative = result; + } } - return result; + return finalAlternative!; } // EXPRESSION TYPE CHECKING @@ -29148,10 +29343,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If no inferences have been made, and none of the type parameters for which we are inferring // specify default types, nothing is gained from instantiating as type parameters would just be // replaced with their constraints similar to the apparent type. - if (inferenceContext && contextFlags! & ContextFlags.Signature && some(inferenceContext.inferences, hasInferenceCandidatesOrDefault)) { + if (inferenceContext && contextFlags! & ContextFlags.Signature && some(flatMap(flattenInferenceContextAlternatives(inferenceContext), c => c.inferences), hasInferenceCandidatesOrDefault)) { // For contextual signatures we incorporate all inferences made so far, e.g. from return // types as well as arguments to the left in a function call. - return instantiateInstantiableTypes(contextualType, inferenceContext.nonFixingMapper); + return getUnionType(map( + flattenInferenceContextAlternatives(inferenceContext), + c => instantiateInstantiableTypes(contextualType, c.nonFixingMapper) + )); } if (inferenceContext?.returnMapper) { // For other purposes (e.g. determining whether to produce literal types) we only @@ -32072,25 +32270,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // 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. const restType = getEffectiveRestType(contextualSignature); - const mapper = inferenceContext && (restType && restType.flags & TypeFlags.TypeParameter ? inferenceContext.nonFixingMapper : inferenceContext.mapper); + const mapper = inferenceContext && (restType && restType.flags & TypeFlags.TypeParameter ? inferenceContext.nonFixingMapper : getMapperFromContext(inferenceContext)); const sourceSignature = mapper ? instantiateSignature(contextualSignature, mapper) : contextualSignature; applyToParameterTypes(sourceSignature, signature, (source, target) => { // Type parameters from outer context referenced by source type are fixed by instantiation of the source type - inferTypes(context.inferences, source, target); + inferTypes(context, source, target); }); if (!inferenceContext) { applyToReturnTypes(contextualSignature, signature, (source, target) => { - inferTypes(context.inferences, source, target, InferencePriority.ReturnType); + inferTypes(context, source, target, InferencePriority.ReturnType); }); } - return getSignatureInstantiation(signature, getInferredTypes(context), isInJSFile(contextualSignature.declaration)); + // We pass `returnFalse` as the acceptor so the last overload of all alternatives are chosen - + // this matches historical precedent, but there's probably a better option here. + return getSignatureInstantiation(signature, getInferredTypes(context, returnFalse), isInJSFile(contextualSignature.declaration)); } - function inferJsxTypeArguments(node: JsxOpeningLikeElement, signature: Signature, checkMode: CheckMode, context: InferenceContext): Type[] { + function inferJsxTypeArguments(node: JsxOpeningLikeElement, signature: Signature, checkMode: CheckMode, context: InferenceContext, accept: (types: Type[]) => boolean): Type[] { const paramType = getEffectiveFirstArgumentForJsxSignature(signature, node); const checkAttrType = checkExpressionWithContextualType(node.attributes, paramType, context, checkMode); - inferTypes(context.inferences, checkAttrType, paramType); - return getInferredTypes(context); + inferTypes(context, checkAttrType, paramType); + return getInferredTypes(context, accept); } function getThisArgumentType(thisArgumentNode: LeftHandSideExpression | undefined) { @@ -32103,9 +32303,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { thisArgumentType; } - function inferTypeArguments(node: CallLikeExpression, signature: Signature, args: readonly Expression[], checkMode: CheckMode, context: InferenceContext): Type[] { + function inferTypeArguments(node: CallLikeExpression, signature: Signature, args: readonly Expression[], checkMode: CheckMode, context: InferenceContext, accept: (types: Type[]) => boolean): Type[] { if (isJsxOpeningLikeElement(node)) { - return inferJsxTypeArguments(node, signature, checkMode, context); + return inferJsxTypeArguments(node, signature, checkMode, context, accept); } // If a contextual type is available, infer from that type to the return type of the call expression. For @@ -32148,7 +32348,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { getOrCreateTypeFromSignature(getSignatureInstantiationWithoutFillingInTypeArguments(contextualSignature, contextualSignature.typeParameters)) : instantiatedType; // Inferences made from return types have lower priority than all other inferences. - inferTypes(context.inferences, inferenceSourceType, inferenceTargetType, InferencePriority.ReturnType); + inferTypes(context, inferenceSourceType, inferenceTargetType, InferencePriority.ReturnType); } // Create a type mapper for instantiating generic contextual types using the inferences made // from the return type. We need a separate inference pass here because (a) instantiation of @@ -32156,7 +32356,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // outer arguments), and (b) we don't want any further inferences going into this context. const returnContext = createInferenceContext(signature.typeParameters!, signature, context.flags); const returnSourceType = instantiateType(contextualType, outerContext && outerContext.returnMapper); - inferTypes(returnContext.inferences, returnSourceType, inferenceTargetType); + inferTypes(returnContext, returnSourceType, inferenceTargetType); context.returnMapper = some(returnContext.inferences, hasInferenceCandidates) ? getMapperFromContext(cloneInferredPartOfContext(returnContext)) : undefined; } } @@ -32174,7 +32374,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const thisType = getThisTypeOfSignature(signature); if (thisType && couldContainTypeVariables(thisType)) { const thisArgumentNode = getThisArgumentOfCall(node); - inferTypes(context.inferences, getThisArgumentType(thisArgumentNode), thisType); + inferTypes(context, getThisArgumentType(thisArgumentNode), thisType); } for (let i = 0; i < argCount; i++) { @@ -32183,17 +32383,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const paramType = getTypeAtPosition(signature, i); if (couldContainTypeVariables(paramType)) { const argType = checkExpressionWithContextualType(arg, paramType, context, checkMode); - inferTypes(context.inferences, argType, paramType); + inferTypes(context, argType, paramType); } } } if (restType && couldContainTypeVariables(restType)) { const spreadType = getSpreadArgumentType(args, argCount, args.length, restType, context, checkMode); - inferTypes(context.inferences, spreadType, restType); + inferTypes(context, spreadType, restType); } - return getInferredTypes(context); + return getInferredTypes(context, accept); } function getMutableArrayOrTupleType(type: Type) { @@ -33020,6 +33220,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let checkCandidate: Signature; let inferenceContext: InferenceContext | undefined; + /** + * Used by inference to accept or reject inference results, allowing it to explore multiple inference choices + * - it will still always return the final result, even if all of them would be rejected by this function. + */ + const acceptor = (types: Type[]): boolean => { + const checkCandidate = getSignatureInstantiation(candidate, types, isInJSFile(candidate.declaration), inferenceContext && inferenceContext.inferredTypeParameters); + if (getNonArrayRestType(candidate) && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma)) { + return false; + } + if (getSignatureApplicabilityError(node, args, checkCandidate, relation, argCheckMode, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) { + return false; + } + return true; + }; + if (candidate.typeParameters) { let typeArgumentTypes: Type[] | undefined; if (some(typeArguments)) { @@ -33031,7 +33246,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else { inferenceContext = createInferenceContext(candidate.typeParameters, candidate, /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None); - typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode | CheckMode.SkipGenericFunctions, inferenceContext); + typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode | CheckMode.SkipGenericFunctions, inferenceContext, acceptor); argCheckMode |= inferenceContext.flags & InferenceFlags.SkippedGenericFunction ? CheckMode.SkipGenericFunctions : CheckMode.Normal; } checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext && inferenceContext.inferredTypeParameters); @@ -33056,7 +33271,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // round of type inference and applicability checking for this particular candidate. argCheckMode = checkMode & CheckMode.IsForStringLiteralArgumentCompletions; if (inferenceContext) { - const typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode, inferenceContext); + const typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode, inferenceContext, acceptor); checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext.inferredTypeParameters); // If the original signature has a generic rest type, instantiation may produce a // signature with different arity and we need to perform another arity check. @@ -33182,7 +33397,9 @@ 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 typeArgumentTypes = inferTypeArguments(node, candidate, args, checkMode | CheckMode.SkipContextSensitive | CheckMode.SkipGenericFunctions, inferenceContext); + // By passing `returnFalse` for the `accept` function, we pick the last alternative for the error signature, which matches historic behavior. + // A better, "closer" inference choice (by some heuristic) might be available, and may be a way to improve error messages. + const typeArgumentTypes = inferTypeArguments(node, candidate, args, checkMode | CheckMode.SkipContextSensitive | CheckMode.SkipGenericFunctions, inferenceContext, returnFalse); return createSignatureInstantiation(candidate, typeArgumentTypes); } @@ -34623,7 +34840,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (declaration.type) { const typeNode = getEffectiveTypeAnnotationNode(declaration); if (typeNode) { - inferTypes(inferenceContext.inferences, getTypeFromTypeNode(typeNode), getTypeAtPosition(context, i)); + inferTypes(inferenceContext, getTypeFromTypeNode(typeNode), getTypeAtPosition(context, i)); } } } @@ -35548,7 +35765,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } instantiatedContextualSignature ||= inferenceContext ? - instantiateSignature(contextualSignature, inferenceContext.mapper) : contextualSignature; + instantiateSignature(contextualSignature, getMapperFromContext(inferenceContext)) : contextualSignature; assignContextualParameterTypes(signature, instantiatedContextualSignature); } else { @@ -37150,7 +37367,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isConstTypeParameterContext(node: Expression) { - const contextualType = getContextualType(node, ContextFlags.None); + // ContextFlags.Signature forces us to instantiate the contextual type with + // WIP inference results, which can reveal members whose current contextual type + // is a const type parameter. TODO: Maybe rename the flag to reflect its broader use? + const contextualType = getContextualType(node, ContextFlags.Signature); return !!contextualType && someType(contextualType, isConstTypeVariable); } @@ -37217,21 +37437,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const instantiatedSignature = getSignatureInstantiationWithoutFillingInTypeArguments(signature, uniqueTypeParameters); // Infer from the parameters of the instantiated signature to the parameters of the // contextual signature starting with an empty set of inference candidates. - const inferences = map(context.inferences, info => createInferenceInfo(info.typeParameter)); + const subcontext = cloneInferenceContext(context); + subcontext.inferences = map(context.inferences, info => createInferenceInfo(info.typeParameter)); applyToParameterTypes(instantiatedSignature, contextualSignature, (source, target) => { - inferTypes(inferences, source, target, /*priority*/ 0, /*contravariant*/ true); + inferTypes(subcontext, source, target, /*priority*/ 0, /*contravariant*/ true); }); - if (some(inferences, hasInferenceCandidates)) { + if (some(subcontext.inferences, hasInferenceCandidates)) { // We have inference candidates, indicating that one or more type parameters are referenced // in the parameter types of the contextual signature. Now also infer from the return type. applyToReturnTypes(instantiatedSignature, contextualSignature, (source, target) => { - inferTypes(inferences, source, target); + inferTypes(subcontext, source, target); }); // If the type parameters for which we produced candidates do not have any inferences yet, // we adopt the new inference candidates and add the type parameters of the expression type // to the set of inferred type parameters for the outer function return type. - if (!hasOverlappingInferences(context.inferences, inferences)) { - mergeInferences(context.inferences, inferences); + if (!hasOverlappingInferences(context.inferences, subcontext.inferences)) { + mergeInferenceContexts(context, subcontext); context.inferredTypeParameters = concatenate(context.inferredTypeParameters, uniqueTypeParameters); return getOrCreateTypeFromSignature(instantiatedSignature); } @@ -37271,14 +37492,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function mergeInferences(target: InferenceInfo[], source: InferenceInfo[]) { + function mergeInferences(target: InferenceInfo[], source: InferenceInfo[], clone = false) { for (let i = 0; i < target.length; i++) { if (!hasInferenceCandidates(target[i]) && hasInferenceCandidates(source[i])) { - target[i] = source[i]; + target[i] = clone ? { + ...source[i], + candidates: source[i].candidates && [...source[i].candidates!], + contraCandidates: source[i].contraCandidates && [...source[i].contraCandidates!] + } : source[i]; } } } + function mergeInferenceContexts(target: InferenceContext, source: InferenceContext, cloneInferences = false) { + mergeInferences(target.inferences, source.inferences, cloneInferences); + // refresh mappers for new inference objects + target.mapper = makeFixingMapperForContext(target); + target.nonFixingMapper = makeNonFixingMapperForContext(target); + } + function getUniqueTypeParameters(context: InferenceContext, typeParameters: readonly TypeParameter[]): readonly TypeParameter[] { const result: TypeParameter[] = []; let oldTypeParameters: TypeParameter[] | undefined; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index df0ba774ae5b3..17c67a8f1b19c 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -6685,8 +6685,6 @@ export interface Signature { /** @internal */ canonicalSignatureCache?: Signature; // Canonical version of signature (deferred) /** @internal */ - baseSignatureCache?: Signature; // Base version of signature (deferred) - /** @internal */ optionalCallSignatureCache?: { inner?: Signature, outer?: Signature }; // Optional chained call version of signature (deferred) /** @internal */ isolatedSignatureType?: ObjectType; // A manufactured type that just contains the signature for purposes of signature comparison @@ -6794,6 +6792,9 @@ export interface InferenceContext { returnMapper?: TypeMapper; // Type mapper for inferences from return types (if any) inferredTypeParameters?: readonly TypeParameter[]; // Inferred type parameters for function result intraExpressionInferenceSites?: IntraExpressionInferenceSite[]; + freeTypeVariables?: InferenceInfo[]; // Extra inferences made for type parameters found during inference + freeTypeVariableSourceSignatures?: Map>; // For each recusion identity on the source stack, a cached mapping of signature copies made + alternatives?: InferenceContext[] } /** @internal */ diff --git a/tests/baselines/reference/flatArrayNoExcessiveStackDepth.errors.txt b/tests/baselines/reference/flatArrayNoExcessiveStackDepth.errors.txt index 8933563702677..97aaa56294068 100644 --- a/tests/baselines/reference/flatArrayNoExcessiveStackDepth.errors.txt +++ b/tests/baselines/reference/flatArrayNoExcessiveStackDepth.errors.txt @@ -5,7 +5,7 @@ tests/cases/compiler/flatArrayNoExcessiveStackDepth.ts(20,5): error TS2322: Type Type 'unknown' is not assignable to type 'Arr extends readonly (infer InnerArr)[] ? FlatArray : Arr'. Type 'FlatArray' is not assignable to type 'FlatArray'. Type 'InnerArr' is not assignable to type 'FlatArray'. - Type 'InnerArr' is not assignable to type '(InnerArr extends readonly (infer InnerArr)[] ? FlatArray : InnerArr) & InnerArr'. + Type 'InnerArr' is not assignable to type 'InnerArr & (InnerArr extends readonly (infer InnerArr)[] ? FlatArray : InnerArr)'. Type 'InnerArr' is not assignable to type 'InnerArr extends readonly (infer InnerArr)[] ? FlatArray : InnerArr'. @@ -38,7 +38,7 @@ tests/cases/compiler/flatArrayNoExcessiveStackDepth.ts(20,5): error TS2322: Type !!! error TS2322: Type 'unknown' is not assignable to type 'Arr extends readonly (infer InnerArr)[] ? FlatArray : Arr'. !!! error TS2322: Type 'FlatArray' is not assignable to type 'FlatArray'. !!! error TS2322: Type 'InnerArr' is not assignable to type 'FlatArray'. -!!! error TS2322: Type 'InnerArr' is not assignable to type '(InnerArr extends readonly (infer InnerArr)[] ? FlatArray : InnerArr) & InnerArr'. +!!! error TS2322: Type 'InnerArr' is not assignable to type 'InnerArr & (InnerArr extends readonly (infer InnerArr)[] ? FlatArray : InnerArr)'. !!! error TS2322: Type 'InnerArr' is not assignable to type 'InnerArr extends readonly (infer InnerArr)[] ? FlatArray : InnerArr'. } \ No newline at end of file diff --git a/tests/baselines/reference/genericCallToOverloadedMethodWithOverloadedArguments.errors.txt b/tests/baselines/reference/genericCallToOverloadedMethodWithOverloadedArguments.errors.txt deleted file mode 100644 index 15d4c9bf16711..0000000000000 --- a/tests/baselines/reference/genericCallToOverloadedMethodWithOverloadedArguments.errors.txt +++ /dev/null @@ -1,153 +0,0 @@ -tests/cases/conformance/types/typeRelationships/typeInference/genericCallToOverloadedMethodWithOverloadedArguments.ts(23,38): error TS2345: Argument of type '{ (n: number): Promise; (s: string): Promise; }' is not assignable to parameter of type '(x: number) => Promise'. - Type 'Promise' is not assignable to type 'Promise'. - Type 'number' is not assignable to type 'string'. -tests/cases/conformance/types/typeRelationships/typeInference/genericCallToOverloadedMethodWithOverloadedArguments.ts(52,38): error TS2769: No overload matches this call. - Overload 1 of 2, '(cb: (x: number) => Promise): Promise', gave the following error. - Argument of type '{ (n: number): Promise; (s: string): Promise; }' is not assignable to parameter of type '(x: number) => Promise'. - Type 'Promise' is not assignable to type 'Promise'. - Type 'number' is not assignable to type 'string'. - Overload 2 of 2, '(cb: (x: number) => Promise, error?: (error: any) => Promise): Promise', gave the following error. - Argument of type '{ (n: number): Promise; (s: string): Promise; }' is not assignable to parameter of type '(x: number) => Promise'. - Type 'Promise' is not assignable to type 'Promise'. -tests/cases/conformance/types/typeRelationships/typeInference/genericCallToOverloadedMethodWithOverloadedArguments.ts(68,38): error TS2769: No overload matches this call. - Overload 1 of 3, '(cb: (x: number) => Promise): Promise', gave the following error. - Argument of type '{ (n: number): Promise; (s: string): Promise; }' is not assignable to parameter of type '(x: number) => Promise'. - Type 'Promise' is not assignable to type 'Promise'. - Type 'number' is not assignable to type 'string'. - Overload 2 of 3, '(cb: (x: number) => Promise, error?: (error: any) => Promise): Promise', gave the following error. - Argument of type '{ (n: number): Promise; (s: string): Promise; }' is not assignable to parameter of type '(x: number) => Promise'. - Type 'Promise' is not assignable to type 'Promise'. - Overload 3 of 3, '(cb: (x: number) => Promise, error?: (error: any) => string, progress?: (preservation: any) => void): Promise', gave the following error. - Argument of type '{ (n: number): Promise; (s: string): Promise; }' is not assignable to parameter of type '(x: number) => Promise'. - Type 'Promise' is not assignable to type 'Promise'. -tests/cases/conformance/types/typeRelationships/typeInference/genericCallToOverloadedMethodWithOverloadedArguments.ts(84,38): error TS2769: No overload matches this call. - Overload 1 of 2, '(cb: (x: number) => Promise): Promise', gave the following error. - Argument of type '{ (n: number): Promise; (s: string): Promise; (b: boolean): Promise; }' is not assignable to parameter of type '(x: number) => Promise'. - Type 'Promise' is not assignable to type 'Promise'. - Type 'number' is not assignable to type 'boolean'. - Overload 2 of 2, '(cb: (x: number) => Promise, error?: (error: any) => Promise): Promise', gave the following error. - Argument of type '{ (n: number): Promise; (s: string): Promise; (b: boolean): Promise; }' is not assignable to parameter of type '(x: number) => Promise'. - Type 'Promise' is not assignable to type 'Promise'. - - -==== tests/cases/conformance/types/typeRelationships/typeInference/genericCallToOverloadedMethodWithOverloadedArguments.ts (4 errors) ==== - module m1 { - interface Promise { - then(cb: (x: T) => Promise): Promise; - } - - declare function testFunction(n: number): Promise; - - var numPromise: Promise; - var newPromise = numPromise.then(testFunction); - } - - ////////////////////////////////////// - - module m2 { - interface Promise { - then(cb: (x: T) => Promise): Promise; - } - - declare function testFunction(n: number): Promise; - declare function testFunction(s: string): Promise; - - var numPromise: Promise; - var newPromise = numPromise.then(testFunction); - ~~~~~~~~~~~~ -!!! error TS2345: Argument of type '{ (n: number): Promise; (s: string): Promise; }' is not assignable to parameter of type '(x: number) => Promise'. -!!! error TS2345: Type 'Promise' is not assignable to type 'Promise'. -!!! error TS2345: Type 'number' is not assignable to type 'string'. - } - - ////////////////////////////////////// - - module m3 { - interface Promise { - then(cb: (x: T) => Promise): Promise; - then(cb: (x: T) => Promise, error?: (error: any) => Promise): Promise; - } - - declare function testFunction(n: number): Promise; - - var numPromise: Promise; - var newPromise = numPromise.then(testFunction); - } - - ////////////////////////////////////// - - module m4 { - interface Promise { - then(cb: (x: T) => Promise): Promise; - then(cb: (x: T) => Promise, error?: (error: any) => Promise): Promise; - } - - declare function testFunction(n: number): Promise; - declare function testFunction(s: string): Promise; - - var numPromise: Promise; - var newPromise = numPromise.then(testFunction); - ~~~~~~~~~~~~ -!!! error TS2769: No overload matches this call. -!!! error TS2769: Overload 1 of 2, '(cb: (x: number) => Promise): Promise', gave the following error. -!!! error TS2769: Argument of type '{ (n: number): Promise; (s: string): Promise; }' is not assignable to parameter of type '(x: number) => Promise'. -!!! error TS2769: Type 'Promise' is not assignable to type 'Promise'. -!!! error TS2769: Type 'number' is not assignable to type 'string'. -!!! error TS2769: Overload 2 of 2, '(cb: (x: number) => Promise, error?: (error: any) => Promise): Promise', gave the following error. -!!! error TS2769: Argument of type '{ (n: number): Promise; (s: string): Promise; }' is not assignable to parameter of type '(x: number) => Promise'. -!!! error TS2769: Type 'Promise' is not assignable to type 'Promise'. - } - - ////////////////////////////////////// - - module m5 { - interface Promise { - then(cb: (x: T) => Promise): Promise; - then(cb: (x: T) => Promise, error?: (error: any) => Promise): Promise; - then(cb: (x: T) => Promise, error?: (error: any) => U, progress?: (preservation: any) => void): Promise; - } - - declare function testFunction(n: number): Promise; - declare function testFunction(s: string): Promise; - - var numPromise: Promise; - var newPromise = numPromise.then(testFunction); - ~~~~~~~~~~~~ -!!! error TS2769: No overload matches this call. -!!! error TS2769: Overload 1 of 3, '(cb: (x: number) => Promise): Promise', gave the following error. -!!! error TS2769: Argument of type '{ (n: number): Promise; (s: string): Promise; }' is not assignable to parameter of type '(x: number) => Promise'. -!!! error TS2769: Type 'Promise' is not assignable to type 'Promise'. -!!! error TS2769: Type 'number' is not assignable to type 'string'. -!!! error TS2769: Overload 2 of 3, '(cb: (x: number) => Promise, error?: (error: any) => Promise): Promise', gave the following error. -!!! error TS2769: Argument of type '{ (n: number): Promise; (s: string): Promise; }' is not assignable to parameter of type '(x: number) => Promise'. -!!! error TS2769: Type 'Promise' is not assignable to type 'Promise'. -!!! error TS2769: Overload 3 of 3, '(cb: (x: number) => Promise, error?: (error: any) => string, progress?: (preservation: any) => void): Promise', gave the following error. -!!! error TS2769: Argument of type '{ (n: number): Promise; (s: string): Promise; }' is not assignable to parameter of type '(x: number) => Promise'. -!!! error TS2769: Type 'Promise' is not assignable to type 'Promise'. - } - - ////////////////////////////////////// - - module m6 { - interface Promise { - then(cb: (x: T) => Promise): Promise; - then(cb: (x: T) => Promise, error?: (error: any) => Promise): Promise; - } - - declare function testFunction(n: number): Promise; - declare function testFunction(s: string): Promise; - declare function testFunction(b: boolean): Promise; - - var numPromise: Promise; - var newPromise = numPromise.then(testFunction); - ~~~~~~~~~~~~ -!!! error TS2769: No overload matches this call. -!!! error TS2769: Overload 1 of 2, '(cb: (x: number) => Promise): Promise', gave the following error. -!!! error TS2769: Argument of type '{ (n: number): Promise; (s: string): Promise; (b: boolean): Promise; }' is not assignable to parameter of type '(x: number) => Promise'. -!!! error TS2769: Type 'Promise' is not assignable to type 'Promise'. -!!! error TS2769: Type 'number' is not assignable to type 'boolean'. -!!! error TS2769: Overload 2 of 2, '(cb: (x: number) => Promise, error?: (error: any) => Promise): Promise', gave the following error. -!!! error TS2769: Argument of type '{ (n: number): Promise; (s: string): Promise; (b: boolean): Promise; }' is not assignable to parameter of type '(x: number) => Promise'. -!!! error TS2769: Type 'Promise' is not assignable to type 'Promise'. - } - \ No newline at end of file diff --git a/tests/baselines/reference/genericCallToOverloadedMethodWithOverloadedArguments.types b/tests/baselines/reference/genericCallToOverloadedMethodWithOverloadedArguments.types index f9d17fc71b371..07a2278422f7e 100644 --- a/tests/baselines/reference/genericCallToOverloadedMethodWithOverloadedArguments.types +++ b/tests/baselines/reference/genericCallToOverloadedMethodWithOverloadedArguments.types @@ -49,8 +49,8 @@ module m2 { >numPromise : Promise var newPromise = numPromise.then(testFunction); ->newPromise : Promise ->numPromise.then(testFunction) : Promise +>newPromise : Promise +>numPromise.then(testFunction) : Promise >numPromise.then : (cb: (x: number) => Promise) => Promise >numPromise : Promise >then : (cb: (x: number) => Promise) => Promise @@ -123,8 +123,8 @@ module m4 { >numPromise : Promise var newPromise = numPromise.then(testFunction); ->newPromise : Promise ->numPromise.then(testFunction) : Promise +>newPromise : Promise +>numPromise.then(testFunction) : Promise >numPromise.then : { (cb: (x: number) => Promise): Promise; (cb: (x: number) => Promise, error?: (error: any) => Promise): Promise; } >numPromise : Promise >then : { (cb: (x: number) => Promise): Promise; (cb: (x: number) => Promise, error?: (error: any) => Promise): Promise; } @@ -171,8 +171,8 @@ module m5 { >numPromise : Promise var newPromise = numPromise.then(testFunction); ->newPromise : Promise ->numPromise.then(testFunction) : Promise +>newPromise : Promise +>numPromise.then(testFunction) : Promise >numPromise.then : { (cb: (x: number) => Promise): Promise; (cb: (x: number) => Promise, error?: (error: any) => Promise): Promise; (cb: (x: number) => Promise, error?: (error: any) => U, progress?: (preservation: any) => void): Promise; } >numPromise : Promise >then : { (cb: (x: number) => Promise): Promise; (cb: (x: number) => Promise, error?: (error: any) => Promise): Promise; (cb: (x: number) => Promise, error?: (error: any) => U, progress?: (preservation: any) => void): Promise; } @@ -214,8 +214,8 @@ module m6 { >numPromise : Promise var newPromise = numPromise.then(testFunction); ->newPromise : Promise ->numPromise.then(testFunction) : Promise +>newPromise : Promise +>numPromise.then(testFunction) : Promise >numPromise.then : { (cb: (x: number) => Promise): Promise; (cb: (x: number) => Promise, error?: (error: any) => Promise): Promise; } >numPromise : Promise >then : { (cb: (x: number) => Promise): Promise; (cb: (x: number) => Promise, error?: (error: any) => Promise): Promise; } diff --git a/tests/baselines/reference/genericCallWithOverloadedConstructorTypedArguments.types b/tests/baselines/reference/genericCallWithOverloadedConstructorTypedArguments.types index 9becb06eb85ab..7230d45004257 100644 --- a/tests/baselines/reference/genericCallWithOverloadedConstructorTypedArguments.types +++ b/tests/baselines/reference/genericCallWithOverloadedConstructorTypedArguments.types @@ -100,8 +100,8 @@ module GenericParameter { >a : { new (x: boolean): string; new (x: number): boolean; } var r9 = foo6(b); // new any => string; new(x:any, y?:any) => string ->r9 : { new (x: unknown): string; new (x: unknown, y?: unknown): string; } ->foo6(b) : { new (x: unknown): string; new (x: unknown, y?: unknown): string; } +>r9 : { new (x: number): string; new (x: number, y?: number): string; } +>foo6(b) : { new (x: number): string; new (x: number, y?: number): string; } >foo6 : (cb: { new (x: T): string; new (x: T, y?: T): string; }) => { new (x: T): string; new (x: T, y?: T): string; } >b : { new (x: T): string; new (x: number): T; } @@ -118,8 +118,8 @@ module GenericParameter { } var r13 = foo7(1, b); // new any => string; new(x:any, y?:any) => string ->r13 : { new (x: unknown): string; new (x: unknown, y?: unknown): string; } ->foo7(1, b) : { new (x: unknown): string; new (x: unknown, y?: unknown): string; } +>r13 : { new (x: number): string; new (x: number, y?: number): string; } +>foo7(1, b) : { new (x: number): string; new (x: number, y?: number): string; } >foo7 : (x: T, cb: { new (x: T): string; new (x: T, y?: T): string; }) => { new (x: T): string; new (x: T, y?: T): string; } >1 : 1 >b : { new (x: T): string; new (x: number): T; } @@ -135,15 +135,15 @@ module GenericParameter { >x : number var r14 = foo7(1, c); // new any => string; new(x:any, y?:any) => string ->r14 : { new (x: unknown): string; new (x: unknown, y?: unknown): string; } ->foo7(1, c) : { new (x: unknown): string; new (x: unknown, y?: unknown): string; } +>r14 : { new (x: 1): string; new (x: 1, y?: 1): string; } +>foo7(1, c) : { new (x: 1): string; new (x: 1, y?: 1): string; } >foo7 : (x: T, cb: { new (x: T): string; new (x: T, y?: T): string; }) => { new (x: T): string; new (x: T, y?: T): string; } >1 : 1 >c : { (x: number): T; new (x: T): string; } var r15 = foo7(1, c2); // new any => string; new(x:any, y?:any) => string ->r15 : { new (x: unknown): string; new (x: unknown, y?: unknown): string; } ->foo7(1, c2) : { new (x: unknown): string; new (x: unknown, y?: unknown): string; } +>r15 : { new (x: number): string; new (x: number, y?: number): string; } +>foo7(1, c2) : { new (x: number): string; new (x: number, y?: number): string; } >foo7 : (x: T, cb: { new (x: T): string; new (x: T, y?: T): string; }) => { new (x: T): string; new (x: T, y?: T): string; } >1 : 1 >c2 : { new (x: T): string; new (x: number): T; } diff --git a/tests/baselines/reference/genericCallWithOverloadedConstructorTypedArguments2.types b/tests/baselines/reference/genericCallWithOverloadedConstructorTypedArguments2.types index a975cb761df40..0688f547b8021 100644 --- a/tests/baselines/reference/genericCallWithOverloadedConstructorTypedArguments2.types +++ b/tests/baselines/reference/genericCallWithOverloadedConstructorTypedArguments2.types @@ -93,8 +93,8 @@ module GenericParameter { } var r13 = foo7(1, a); // ok ->r13 : { new (x: unknown): string; new (x: unknown, y?: unknown): string; } ->foo7(1, a) : { new (x: unknown): string; new (x: unknown, y?: unknown): string; } +>r13 : { new (x: 1): string; new (x: 1, y?: 1): string; } +>foo7(1, a) : { new (x: 1): string; new (x: 1, y?: 1): string; } >foo7 : (x: T, cb: { new (x: T): string; new (x: T, y?: T): string; }) => { new (x: T): string; new (x: T, y?: T): string; } >1 : 1 >a : new (x: T) => T @@ -105,8 +105,8 @@ module GenericParameter { >x : number var r14 = foo7(1, c); // ok ->r14 : { new (x: unknown): string; new (x: unknown, y?: unknown): string; } ->foo7(1, c) : { new (x: unknown): string; new (x: unknown, y?: unknown): string; } +>r14 : { new (x: number): string; new (x: number, y?: number): string; } +>foo7(1, c) : { new (x: number): string; new (x: number, y?: number): string; } >foo7 : (x: T, cb: { new (x: T): string; new (x: T, y?: T): string; }) => { new (x: T): string; new (x: T, y?: T): string; } >1 : 1 >c : { new (x: T): number; new (x: number): T; } diff --git a/tests/baselines/reference/genericCallWithOverloadedFunctionTypedArguments.types b/tests/baselines/reference/genericCallWithOverloadedFunctionTypedArguments.types index 6360ee82417c5..e4f34769aa48d 100644 --- a/tests/baselines/reference/genericCallWithOverloadedFunctionTypedArguments.types +++ b/tests/baselines/reference/genericCallWithOverloadedFunctionTypedArguments.types @@ -137,8 +137,8 @@ module GenericParameter { >x : any var r13 = foo7(1, (x: T) => ''); // any => string (+1 overload) [inferences are made for T, but lambda not contextually typed] ->r13 : { (x: unknown): string; (x: unknown, y?: unknown): string; } ->foo7(1, (x: T) => '') : { (x: unknown): string; (x: unknown, y?: unknown): string; } +>r13 : { (x: 1): string; (x: 1, y?: 1): string; } +>foo7(1, (x: T) => '') : { (x: 1): string; (x: 1, y?: 1): string; } >foo7 : (x: T, cb: { (x: T): string; (x: T, y?: T): string; }) => { (x: T): string; (x: T, y?: T): string; } >1 : 1 >(x: T) => '' : (x: T) => string @@ -151,8 +151,8 @@ module GenericParameter { >x : number var r14 = foo7(1, a); // any => string (+1 overload) [inferences are made for T, but lambda not contextually typed] ->r14 : { (x: unknown): string; (x: unknown, y?: unknown): string; } ->foo7(1, a) : { (x: unknown): string; (x: unknown, y?: unknown): string; } +>r14 : { (x: number): string; (x: number, y?: number): string; } +>foo7(1, a) : { (x: number): string; (x: number, y?: number): string; } >foo7 : (x: T, cb: { (x: T): string; (x: T, y?: T): string; }) => { (x: T): string; (x: T, y?: T): string; } >1 : 1 >a : { (x: T): string; (x: number): T; } diff --git a/tests/baselines/reference/genericCallWithOverloadedFunctionTypedArguments2.types b/tests/baselines/reference/genericCallWithOverloadedFunctionTypedArguments2.types index 626a38bb7dbab..3e7d196438317 100644 --- a/tests/baselines/reference/genericCallWithOverloadedFunctionTypedArguments2.types +++ b/tests/baselines/reference/genericCallWithOverloadedFunctionTypedArguments2.types @@ -88,8 +88,8 @@ module GenericParameter { } var r13 = foo7(1, (x: T) => x); // ok ->r13 : { (x: unknown): string; (x: unknown, y?: unknown): string; } ->foo7(1, (x: T) => x) : { (x: unknown): string; (x: unknown, y?: unknown): string; } +>r13 : { (x: 1): string; (x: 1, y?: 1): string; } +>foo7(1, (x: T) => x) : { (x: 1): string; (x: 1, y?: 1): string; } >foo7 : (x: T, cb: { (x: T): string; (x: T, y?: T): string; }) => { (x: T): string; (x: T, y?: T): string; } >1 : 1 >(x: T) => x : (x: T) => T @@ -102,8 +102,8 @@ module GenericParameter { >x : number var r14 = foo7(1, a); // ok ->r14 : { (x: unknown): string; (x: unknown, y?: unknown): string; } ->foo7(1, a) : { (x: unknown): string; (x: unknown, y?: unknown): string; } +>r14 : { (x: number): string; (x: number, y?: number): string; } +>foo7(1, a) : { (x: number): string; (x: number, y?: number): string; } >foo7 : (x: T, cb: { (x: T): string; (x: T, y?: T): string; }) => { (x: T): string; (x: T, y?: T): string; } >1 : 1 >a : { (x: T): number; (x: number): T; } diff --git a/tests/baselines/reference/getParameterNameAtPosition.types b/tests/baselines/reference/getParameterNameAtPosition.types index 8eb527b41ec71..d74848ec3b39c 100644 --- a/tests/baselines/reference/getParameterNameAtPosition.types +++ b/tests/baselines/reference/getParameterNameAtPosition.types @@ -23,7 +23,7 @@ declare function fn(implementation?: (...args: Y) => any): Mock cases(fn(opts => { })); >cases(fn(opts => { })) : void >cases : (tester: Tester) => void ->fn(opts => { }) : Mock<[opts: any]> +>fn(opts => { }) : Mock<[opts: any, done: (...args: any[]) => any]> >fn : (implementation?: ((...args: Y) => any) | undefined) => Mock >opts => { } : (opts: any) => void >opts : any diff --git a/tests/baselines/reference/overloadInferenceAlternativesAndConstContexts.js b/tests/baselines/reference/overloadInferenceAlternativesAndConstContexts.js new file mode 100644 index 0000000000000..a9e6c844ec6df --- /dev/null +++ b/tests/baselines/reference/overloadInferenceAlternativesAndConstContexts.js @@ -0,0 +1,18 @@ +//// [overloadInferenceAlternativesAndConstContexts.ts] +declare function sfc(props: { x: T1, y: T1 }): 1; +declare function sfc(props: { a: T2, b: T2 }): T2; +declare function sfc(props: { q: T3, t: T3 }): 3; + +declare function factory< + TProps, + TResult +>(tag: (props: TProps) => TResult, props: TProps, key?: string): TResult; + +const result = factory(sfc, {a: 0, b: 0}); +const result2 = factory<{a: 0, b: 0}, 0>(sfc, {a: 0, b: 0}); + + +//// [overloadInferenceAlternativesAndConstContexts.js] +"use strict"; +var result = factory(sfc, { a: 0, b: 0 }); +var result2 = factory(sfc, { a: 0, b: 0 }); diff --git a/tests/baselines/reference/overloadInferenceAlternativesAndConstContexts.symbols b/tests/baselines/reference/overloadInferenceAlternativesAndConstContexts.symbols new file mode 100644 index 0000000000000..8f3dfbbe266a0 --- /dev/null +++ b/tests/baselines/reference/overloadInferenceAlternativesAndConstContexts.symbols @@ -0,0 +1,64 @@ +=== tests/cases/compiler/overloadInferenceAlternativesAndConstContexts.ts === +declare function sfc(props: { x: T1, y: T1 }): 1; +>sfc : Symbol(sfc, Decl(overloadInferenceAlternativesAndConstContexts.ts, 0, 0), Decl(overloadInferenceAlternativesAndConstContexts.ts, 0, 53), Decl(overloadInferenceAlternativesAndConstContexts.ts, 1, 60)) +>T1 : Symbol(T1, Decl(overloadInferenceAlternativesAndConstContexts.ts, 0, 21)) +>props : Symbol(props, Decl(overloadInferenceAlternativesAndConstContexts.ts, 0, 25)) +>x : Symbol(x, Decl(overloadInferenceAlternativesAndConstContexts.ts, 0, 33)) +>T1 : Symbol(T1, Decl(overloadInferenceAlternativesAndConstContexts.ts, 0, 21)) +>y : Symbol(y, Decl(overloadInferenceAlternativesAndConstContexts.ts, 0, 40)) +>T1 : Symbol(T1, Decl(overloadInferenceAlternativesAndConstContexts.ts, 0, 21)) + +declare function sfc(props: { a: T2, b: T2 }): T2; +>sfc : Symbol(sfc, Decl(overloadInferenceAlternativesAndConstContexts.ts, 0, 0), Decl(overloadInferenceAlternativesAndConstContexts.ts, 0, 53), Decl(overloadInferenceAlternativesAndConstContexts.ts, 1, 60)) +>T2 : Symbol(T2, Decl(overloadInferenceAlternativesAndConstContexts.ts, 1, 21)) +>props : Symbol(props, Decl(overloadInferenceAlternativesAndConstContexts.ts, 1, 31)) +>a : Symbol(a, Decl(overloadInferenceAlternativesAndConstContexts.ts, 1, 39)) +>T2 : Symbol(T2, Decl(overloadInferenceAlternativesAndConstContexts.ts, 1, 21)) +>b : Symbol(b, Decl(overloadInferenceAlternativesAndConstContexts.ts, 1, 46)) +>T2 : Symbol(T2, Decl(overloadInferenceAlternativesAndConstContexts.ts, 1, 21)) +>T2 : Symbol(T2, Decl(overloadInferenceAlternativesAndConstContexts.ts, 1, 21)) + +declare function sfc(props: { q: T3, t: T3 }): 3; +>sfc : Symbol(sfc, Decl(overloadInferenceAlternativesAndConstContexts.ts, 0, 0), Decl(overloadInferenceAlternativesAndConstContexts.ts, 0, 53), Decl(overloadInferenceAlternativesAndConstContexts.ts, 1, 60)) +>T3 : Symbol(T3, Decl(overloadInferenceAlternativesAndConstContexts.ts, 2, 21)) +>props : Symbol(props, Decl(overloadInferenceAlternativesAndConstContexts.ts, 2, 25)) +>q : Symbol(q, Decl(overloadInferenceAlternativesAndConstContexts.ts, 2, 33)) +>T3 : Symbol(T3, Decl(overloadInferenceAlternativesAndConstContexts.ts, 2, 21)) +>t : Symbol(t, Decl(overloadInferenceAlternativesAndConstContexts.ts, 2, 40)) +>T3 : Symbol(T3, Decl(overloadInferenceAlternativesAndConstContexts.ts, 2, 21)) + +declare function factory< +>factory : Symbol(factory, Decl(overloadInferenceAlternativesAndConstContexts.ts, 2, 53)) + + TProps, +>TProps : Symbol(TProps, Decl(overloadInferenceAlternativesAndConstContexts.ts, 4, 25)) + + TResult +>TResult : Symbol(TResult, Decl(overloadInferenceAlternativesAndConstContexts.ts, 5, 11)) + +>(tag: (props: TProps) => TResult, props: TProps, key?: string): TResult; +>tag : Symbol(tag, Decl(overloadInferenceAlternativesAndConstContexts.ts, 7, 2)) +>props : Symbol(props, Decl(overloadInferenceAlternativesAndConstContexts.ts, 7, 8)) +>TProps : Symbol(TProps, Decl(overloadInferenceAlternativesAndConstContexts.ts, 4, 25)) +>TResult : Symbol(TResult, Decl(overloadInferenceAlternativesAndConstContexts.ts, 5, 11)) +>props : Symbol(props, Decl(overloadInferenceAlternativesAndConstContexts.ts, 7, 34)) +>TProps : Symbol(TProps, Decl(overloadInferenceAlternativesAndConstContexts.ts, 4, 25)) +>key : Symbol(key, Decl(overloadInferenceAlternativesAndConstContexts.ts, 7, 49)) +>TResult : Symbol(TResult, Decl(overloadInferenceAlternativesAndConstContexts.ts, 5, 11)) + +const result = factory(sfc, {a: 0, b: 0}); +>result : Symbol(result, Decl(overloadInferenceAlternativesAndConstContexts.ts, 9, 5)) +>factory : Symbol(factory, Decl(overloadInferenceAlternativesAndConstContexts.ts, 2, 53)) +>sfc : Symbol(sfc, Decl(overloadInferenceAlternativesAndConstContexts.ts, 0, 0), Decl(overloadInferenceAlternativesAndConstContexts.ts, 0, 53), Decl(overloadInferenceAlternativesAndConstContexts.ts, 1, 60)) +>a : Symbol(a, Decl(overloadInferenceAlternativesAndConstContexts.ts, 9, 29)) +>b : Symbol(b, Decl(overloadInferenceAlternativesAndConstContexts.ts, 9, 34)) + +const result2 = factory<{a: 0, b: 0}, 0>(sfc, {a: 0, b: 0}); +>result2 : Symbol(result2, Decl(overloadInferenceAlternativesAndConstContexts.ts, 10, 5)) +>factory : Symbol(factory, Decl(overloadInferenceAlternativesAndConstContexts.ts, 2, 53)) +>a : Symbol(a, Decl(overloadInferenceAlternativesAndConstContexts.ts, 10, 25)) +>b : Symbol(b, Decl(overloadInferenceAlternativesAndConstContexts.ts, 10, 30)) +>sfc : Symbol(sfc, Decl(overloadInferenceAlternativesAndConstContexts.ts, 0, 0), Decl(overloadInferenceAlternativesAndConstContexts.ts, 0, 53), Decl(overloadInferenceAlternativesAndConstContexts.ts, 1, 60)) +>a : Symbol(a, Decl(overloadInferenceAlternativesAndConstContexts.ts, 10, 47)) +>b : Symbol(b, Decl(overloadInferenceAlternativesAndConstContexts.ts, 10, 52)) + diff --git a/tests/baselines/reference/overloadInferenceAlternativesAndConstContexts.types b/tests/baselines/reference/overloadInferenceAlternativesAndConstContexts.types new file mode 100644 index 0000000000000..d917f8e020e97 --- /dev/null +++ b/tests/baselines/reference/overloadInferenceAlternativesAndConstContexts.types @@ -0,0 +1,54 @@ +=== tests/cases/compiler/overloadInferenceAlternativesAndConstContexts.ts === +declare function sfc(props: { x: T1, y: T1 }): 1; +>sfc : { (props: { x: T1; y: T1;}): 1; (props: { a: T2; b: T2; }): T2; (props: { q: T3; t: T3; }): 3; } +>props : { x: T1; y: T1; } +>x : T1 +>y : T1 + +declare function sfc(props: { a: T2, b: T2 }): T2; +>sfc : { (props: { x: T1; y: T1; }): 1; (props: { a: T2; b: T2;}): T2; (props: { q: T3; t: T3; }): 3; } +>props : { a: T2; b: T2; } +>a : T2 +>b : T2 + +declare function sfc(props: { q: T3, t: T3 }): 3; +>sfc : { (props: { x: T1; y: T1; }): 1; (props: { a: T2; b: T2; }): T2; (props: { q: T3; t: T3;}): 3; } +>props : { q: T3; t: T3; } +>q : T3 +>t : T3 + +declare function factory< +>factory : (tag: (props: TProps) => TResult, props: TProps, key?: string) => TResult + + TProps, + TResult +>(tag: (props: TProps) => TResult, props: TProps, key?: string): TResult; +>tag : (props: TProps) => TResult +>props : TProps +>props : TProps +>key : string | undefined + +const result = factory(sfc, {a: 0, b: 0}); +>result : 0 +>factory(sfc, {a: 0, b: 0}) : 0 +>factory : (tag: (props: TProps) => TResult, props: TProps, key?: string | undefined) => TResult +>sfc : { (props: { x: T1; y: T1; }): 1; (props: { a: T2; b: T2; }): T2; (props: { q: T3; t: T3; }): 3; } +>{a: 0, b: 0} : { a: 0; b: 0; } +>a : 0 +>0 : 0 +>b : 0 +>0 : 0 + +const result2 = factory<{a: 0, b: 0}, 0>(sfc, {a: 0, b: 0}); +>result2 : 0 +>factory<{a: 0, b: 0}, 0>(sfc, {a: 0, b: 0}) : 0 +>factory : (tag: (props: TProps) => TResult, props: TProps, key?: string | undefined) => TResult +>a : 0 +>b : 0 +>sfc : { (props: { x: T1; y: T1; }): 1; (props: { a: T2; b: T2; }): T2; (props: { q: T3; t: T3; }): 3; } +>{a: 0, b: 0} : { a: 0; b: 0; } +>a : 0 +>0 : 0 +>b : 0 +>0 : 0 + diff --git a/tests/baselines/reference/overloadedGenericInference.js b/tests/baselines/reference/overloadedGenericInference.js new file mode 100644 index 0000000000000..d73f2357381c5 --- /dev/null +++ b/tests/baselines/reference/overloadedGenericInference.js @@ -0,0 +1,25 @@ +//// [overloadedGenericInference.ts] +// #35501 +declare function fn(x: string): string; +declare function fn(x: string[]): string; + +declare function map(fn: (item: A) => R, list: A[]): R[]; + +const mapped = map(fn, ['1']); + +// #30294 (partial fix) +declare class C { + static x(y: number): number; + static x(): number; +} +C.x.call(C, 1); // ok +C.x.call(C); // ok +C.x.call(1); // ok (not an error because the `this` type of `x` is not constrained) + + +//// [overloadedGenericInference.js] +"use strict"; +const mapped = map(fn, ['1']); +C.x.call(C, 1); // ok +C.x.call(C); // ok +C.x.call(1); // ok (not an error because the `this` type of `x` is not constrained) diff --git a/tests/baselines/reference/overloadedGenericInference.symbols b/tests/baselines/reference/overloadedGenericInference.symbols new file mode 100644 index 0000000000000..340f4482d3f7d --- /dev/null +++ b/tests/baselines/reference/overloadedGenericInference.symbols @@ -0,0 +1,61 @@ +=== tests/cases/compiler/overloadedGenericInference.ts === +// #35501 +declare function fn(x: string): string; +>fn : Symbol(fn, Decl(overloadedGenericInference.ts, 0, 0), Decl(overloadedGenericInference.ts, 1, 39)) +>x : Symbol(x, Decl(overloadedGenericInference.ts, 1, 20)) + +declare function fn(x: string[]): string; +>fn : Symbol(fn, Decl(overloadedGenericInference.ts, 0, 0), Decl(overloadedGenericInference.ts, 1, 39)) +>x : Symbol(x, Decl(overloadedGenericInference.ts, 2, 20)) + +declare function map(fn: (item: A) => R, list: A[]): R[]; +>map : Symbol(map, Decl(overloadedGenericInference.ts, 2, 41)) +>A : Symbol(A, Decl(overloadedGenericInference.ts, 4, 21)) +>R : Symbol(R, Decl(overloadedGenericInference.ts, 4, 23)) +>fn : Symbol(fn, Decl(overloadedGenericInference.ts, 4, 27)) +>item : Symbol(item, Decl(overloadedGenericInference.ts, 4, 32)) +>A : Symbol(A, Decl(overloadedGenericInference.ts, 4, 21)) +>R : Symbol(R, Decl(overloadedGenericInference.ts, 4, 23)) +>list : Symbol(list, Decl(overloadedGenericInference.ts, 4, 46)) +>A : Symbol(A, Decl(overloadedGenericInference.ts, 4, 21)) +>R : Symbol(R, Decl(overloadedGenericInference.ts, 4, 23)) + +const mapped = map(fn, ['1']); +>mapped : Symbol(mapped, Decl(overloadedGenericInference.ts, 6, 5)) +>map : Symbol(map, Decl(overloadedGenericInference.ts, 2, 41)) +>fn : Symbol(fn, Decl(overloadedGenericInference.ts, 0, 0), Decl(overloadedGenericInference.ts, 1, 39)) + +// #30294 (partial fix) +declare class C { +>C : Symbol(C, Decl(overloadedGenericInference.ts, 6, 30)) + + static x(y: number): number; +>x : Symbol(C.x, Decl(overloadedGenericInference.ts, 9, 17), Decl(overloadedGenericInference.ts, 10, 32)) +>y : Symbol(y, Decl(overloadedGenericInference.ts, 10, 13)) + + static x(): number; +>x : Symbol(C.x, Decl(overloadedGenericInference.ts, 9, 17), Decl(overloadedGenericInference.ts, 10, 32)) +} +C.x.call(C, 1); // ok +>C.x.call : Symbol(CallableFunction.call, Decl(lib.es5.d.ts, --, --)) +>C.x : Symbol(C.x, Decl(overloadedGenericInference.ts, 9, 17), Decl(overloadedGenericInference.ts, 10, 32)) +>C : Symbol(C, Decl(overloadedGenericInference.ts, 6, 30)) +>x : Symbol(C.x, Decl(overloadedGenericInference.ts, 9, 17), Decl(overloadedGenericInference.ts, 10, 32)) +>call : Symbol(CallableFunction.call, Decl(lib.es5.d.ts, --, --)) +>C : Symbol(C, Decl(overloadedGenericInference.ts, 6, 30)) + +C.x.call(C); // ok +>C.x.call : Symbol(CallableFunction.call, Decl(lib.es5.d.ts, --, --)) +>C.x : Symbol(C.x, Decl(overloadedGenericInference.ts, 9, 17), Decl(overloadedGenericInference.ts, 10, 32)) +>C : Symbol(C, Decl(overloadedGenericInference.ts, 6, 30)) +>x : Symbol(C.x, Decl(overloadedGenericInference.ts, 9, 17), Decl(overloadedGenericInference.ts, 10, 32)) +>call : Symbol(CallableFunction.call, Decl(lib.es5.d.ts, --, --)) +>C : Symbol(C, Decl(overloadedGenericInference.ts, 6, 30)) + +C.x.call(1); // ok (not an error because the `this` type of `x` is not constrained) +>C.x.call : Symbol(CallableFunction.call, Decl(lib.es5.d.ts, --, --)) +>C.x : Symbol(C.x, Decl(overloadedGenericInference.ts, 9, 17), Decl(overloadedGenericInference.ts, 10, 32)) +>C : Symbol(C, Decl(overloadedGenericInference.ts, 6, 30)) +>x : Symbol(C.x, Decl(overloadedGenericInference.ts, 9, 17), Decl(overloadedGenericInference.ts, 10, 32)) +>call : Symbol(CallableFunction.call, Decl(lib.es5.d.ts, --, --)) + diff --git a/tests/baselines/reference/overloadedGenericInference.types b/tests/baselines/reference/overloadedGenericInference.types new file mode 100644 index 0000000000000..064773305bd15 --- /dev/null +++ b/tests/baselines/reference/overloadedGenericInference.types @@ -0,0 +1,63 @@ +=== tests/cases/compiler/overloadedGenericInference.ts === +// #35501 +declare function fn(x: string): string; +>fn : { (x: string): string; (x: string[]): string; } +>x : string + +declare function fn(x: string[]): string; +>fn : { (x: string): string; (x: string[]): string; } +>x : string[] + +declare function map(fn: (item: A) => R, list: A[]): R[]; +>map : (fn: (item: A) => R, list: A[]) => R[] +>fn : (item: A) => R +>item : A +>list : A[] + +const mapped = map(fn, ['1']); +>mapped : string[] +>map(fn, ['1']) : string[] +>map : (fn: (item: A) => R, list: A[]) => R[] +>fn : { (x: string): string; (x: string[]): string; } +>['1'] : string[] +>'1' : "1" + +// #30294 (partial fix) +declare class C { +>C : C + + static x(y: number): number; +>x : { (y: number): number; (): number; } +>y : number + + static x(): number; +>x : { (y: number): number; (): number; } +} +C.x.call(C, 1); // ok +>C.x.call(C, 1) : number +>C.x.call : (this: (this: T, ...args: A) => R, thisArg: T, ...args: A) => R +>C.x : { (y: number): number; (): number; } +>C : typeof C +>x : { (y: number): number; (): number; } +>call : (this: (this: T, ...args: A) => R, thisArg: T, ...args: A) => R +>C : typeof C +>1 : 1 + +C.x.call(C); // ok +>C.x.call(C) : number +>C.x.call : (this: (this: T, ...args: A) => R, thisArg: T, ...args: A) => R +>C.x : { (y: number): number; (): number; } +>C : typeof C +>x : { (y: number): number; (): number; } +>call : (this: (this: T, ...args: A) => R, thisArg: T, ...args: A) => R +>C : typeof C + +C.x.call(1); // ok (not an error because the `this` type of `x` is not constrained) +>C.x.call(1) : number +>C.x.call : (this: (this: T, ...args: A) => R, thisArg: T, ...args: A) => R +>C.x : { (y: number): number; (): number; } +>C : typeof C +>x : { (y: number): number; (): number; } +>call : (this: (this: T, ...args: A) => R, thisArg: T, ...args: A) => R +>1 : 1 + diff --git a/tests/baselines/reference/promisePermutations.errors.txt b/tests/baselines/reference/promisePermutations.errors.txt index 766c92653f6da..54806260a5b9d 100644 --- a/tests/baselines/reference/promisePermutations.errors.txt +++ b/tests/baselines/reference/promisePermutations.errors.txt @@ -105,32 +105,9 @@ tests/cases/compiler/promisePermutations.ts(152,36): error TS2769: No overload m The last overload gave the following error. Argument of type '(x: any) => IPromise' is not assignable to parameter of type '(error: any) => Promise'. Property 'catch' is missing in type 'IPromise' but required in type 'Promise'. -tests/cases/compiler/promisePermutations.ts(156,21): error TS2769: No overload matches this call. - The last overload gave the following error. - Argument of type '{ (x: number): IPromise; (x: string): IPromise; }' is not assignable to parameter of type '(value: number) => IPromise'. - Type 'IPromise' is not assignable to type 'IPromise'. - Type 'number' is not assignable to type 'string'. -tests/cases/compiler/promisePermutations.ts(158,21): error TS2769: No overload matches this call. - The last overload gave the following error. - Argument of type '{ (x: number): IPromise; (x: string): IPromise; }' is not assignable to parameter of type '(value: number) => IPromise'. - Type 'IPromise' is not assignable to type 'IPromise'. -tests/cases/compiler/promisePermutations.ts(159,21): error TS2769: No overload matches this call. - The last overload gave the following error. - Argument of type '{ (x: number): Promise; (x: string): Promise; }' is not assignable to parameter of type '(value: number) => Promise'. - Type 'Promise' is not assignable to type 'Promise'. - Type 'number' is not assignable to type 'string'. -tests/cases/compiler/promisePermutations.ts(160,21): error TS2769: No overload matches this call. - The last overload gave the following error. - Argument of type '{ (x: number): Promise; (x: string): Promise; }' is not assignable to parameter of type '(value: number) => IPromise'. - Call signature return types 'Promise' and 'IPromise' are incompatible. - The types of 'then' are incompatible between these types. - Type '{ (onfulfilled?: (value: number) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; (success?: (value: number) => Promise, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => Promise, error?: (error: any) => U, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise; }' is not assignable to type '{ (success?: (value: string) => IPromise, error?: (error: any) => IPromise, progress?: (progress: any) => void): IPromise; (success?: (value: string) => IPromise, error?: (error: any) => U, progress?: (progress: any) => void): IPromise; (success?: (value: string) => U, error?: (error: any) => IPromise, progress?: (progress: any) => void): IPromise; (success?: (value: string) => U, error?: (error: any) => U, progress?: (progress: any) => void): IPromise; }'. - Types of parameters 'onfulfilled' and 'success' are incompatible. - Types of parameters 'value' and 'value' are incompatible. - Type 'number' is not assignable to type 'string'. -==== tests/cases/compiler/promisePermutations.ts (33 errors) ==== +==== tests/cases/compiler/promisePermutations.ts (29 errors) ==== interface Promise { then(success?: (value: T) => Promise, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; then(success?: (value: T) => Promise, error?: (error: any) => U, progress?: (progress: any) => void): Promise; @@ -453,41 +430,10 @@ tests/cases/compiler/promisePermutations.ts(160,21): error TS2769: No overload m var r11: IPromise; var r11a = r11.then(testFunction11, testFunction11, testFunction11); // error - ~~~~~~~~~~~~~~ -!!! error TS2769: No overload matches this call. -!!! error TS2769: The last overload gave the following error. -!!! error TS2769: Argument of type '{ (x: number): IPromise; (x: string): IPromise; }' is not assignable to parameter of type '(value: number) => IPromise'. -!!! error TS2769: Type 'IPromise' is not assignable to type 'IPromise'. -!!! error TS2769: Type 'number' is not assignable to type 'string'. -!!! related TS2771 tests/cases/compiler/promisePermutations.ts:13:5: The last overload is declared here. var s11: Promise; var s11a = s11.then(testFunction11, testFunction11, testFunction11); // ok - ~~~~~~~~~~~~~~ -!!! error TS2769: No overload matches this call. -!!! error TS2769: The last overload gave the following error. -!!! error TS2769: Argument of type '{ (x: number): IPromise; (x: string): IPromise; }' is not assignable to parameter of type '(value: number) => IPromise'. -!!! error TS2769: Type 'IPromise' is not assignable to type 'IPromise'. -!!! related TS2771 tests/cases/compiler/promisePermutations.ts:5:5: The last overload is declared here. var s11b = s11.then(testFunction11P, testFunction11P, testFunction11P); // error - ~~~~~~~~~~~~~~~ -!!! error TS2769: No overload matches this call. -!!! error TS2769: The last overload gave the following error. -!!! error TS2769: Argument of type '{ (x: number): Promise; (x: string): Promise; }' is not assignable to parameter of type '(value: number) => Promise'. -!!! error TS2769: Type 'Promise' is not assignable to type 'Promise'. -!!! error TS2769: Type 'number' is not assignable to type 'string'. -!!! related TS2771 tests/cases/compiler/promisePermutations.ts:5:5: The last overload is declared here. var s11c = s11.then(testFunction11P, testFunction11, testFunction11); // error - ~~~~~~~~~~~~~~~ -!!! error TS2769: No overload matches this call. -!!! error TS2769: The last overload gave the following error. -!!! error TS2769: Argument of type '{ (x: number): Promise; (x: string): Promise; }' is not assignable to parameter of type '(value: number) => IPromise'. -!!! error TS2769: Call signature return types 'Promise' and 'IPromise' are incompatible. -!!! error TS2769: The types of 'then' are incompatible between these types. -!!! error TS2769: Type '{ (onfulfilled?: (value: number) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; (success?: (value: number) => Promise, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => Promise, error?: (error: any) => U, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise; }' is not assignable to type '{ (success?: (value: string) => IPromise, error?: (error: any) => IPromise, progress?: (progress: any) => void): IPromise; (success?: (value: string) => IPromise, error?: (error: any) => U, progress?: (progress: any) => void): IPromise; (success?: (value: string) => U, error?: (error: any) => IPromise, progress?: (progress: any) => void): IPromise; (success?: (value: string) => U, error?: (error: any) => U, progress?: (progress: any) => void): IPromise; }'. -!!! error TS2769: Types of parameters 'onfulfilled' and 'success' are incompatible. -!!! error TS2769: Types of parameters 'value' and 'value' are incompatible. -!!! error TS2769: Type 'number' is not assignable to type 'string'. -!!! related TS2771 tests/cases/compiler/promisePermutations.ts:5:5: The last overload is declared here. var r12 = testFunction12(x => x); var r12a = r12.then(testFunction12, testFunction12, testFunction12); // ok diff --git a/tests/baselines/reference/promisePermutations.types b/tests/baselines/reference/promisePermutations.types index 1ad75706168dc..4d757e49ae859 100644 --- a/tests/baselines/reference/promisePermutations.types +++ b/tests/baselines/reference/promisePermutations.types @@ -1169,8 +1169,8 @@ var r11: IPromise; >r11 : IPromise var r11a = r11.then(testFunction11, testFunction11, testFunction11); // error ->r11a : IPromise ->r11.then(testFunction11, testFunction11, testFunction11) : IPromise +>r11a : IPromise +>r11.then(testFunction11, testFunction11, testFunction11) : IPromise >r11.then : { (success?: (value: number) => IPromise, error?: (error: any) => IPromise, progress?: (progress: any) => void): IPromise; (success?: (value: number) => IPromise, error?: (error: any) => U, progress?: (progress: any) => void): IPromise; (success?: (value: number) => U, error?: (error: any) => IPromise, progress?: (progress: any) => void): IPromise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): IPromise; } >r11 : IPromise >then : { (success?: (value: number) => IPromise, error?: (error: any) => IPromise, progress?: (progress: any) => void): IPromise; (success?: (value: number) => IPromise, error?: (error: any) => U, progress?: (progress: any) => void): IPromise; (success?: (value: number) => U, error?: (error: any) => IPromise, progress?: (progress: any) => void): IPromise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): IPromise; } @@ -1182,8 +1182,8 @@ var s11: Promise; >s11 : Promise var s11a = s11.then(testFunction11, testFunction11, testFunction11); // ok ->s11a : Promise ->s11.then(testFunction11, testFunction11, testFunction11) : Promise +>s11a : Promise> +>s11.then(testFunction11, testFunction11, testFunction11) : Promise> >s11.then : { (onfulfilled?: (value: number) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; (success?: (value: number) => Promise, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => Promise, error?: (error: any) => U, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise; } >s11 : Promise >then : { (onfulfilled?: (value: number) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; (success?: (value: number) => Promise, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => Promise, error?: (error: any) => U, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise; } @@ -1192,8 +1192,8 @@ var s11a = s11.then(testFunction11, testFunction11, testFunction11); // ok >testFunction11 : { (x: number): IPromise; (x: string): IPromise; } var s11b = s11.then(testFunction11P, testFunction11P, testFunction11P); // error ->s11b : Promise ->s11.then(testFunction11P, testFunction11P, testFunction11P) : Promise +>s11b : Promise +>s11.then(testFunction11P, testFunction11P, testFunction11P) : Promise >s11.then : { (onfulfilled?: (value: number) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; (success?: (value: number) => Promise, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => Promise, error?: (error: any) => U, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise; } >s11 : Promise >then : { (onfulfilled?: (value: number) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; (success?: (value: number) => Promise, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => Promise, error?: (error: any) => U, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise; } @@ -1202,8 +1202,8 @@ var s11b = s11.then(testFunction11P, testFunction11P, testFunction11P); // error >testFunction11P : { (x: number): Promise; (x: string): Promise; } var s11c = s11.then(testFunction11P, testFunction11, testFunction11); // error ->s11c : Promise ->s11.then(testFunction11P, testFunction11, testFunction11) : Promise +>s11c : Promise> +>s11.then(testFunction11P, testFunction11, testFunction11) : Promise> >s11.then : { (onfulfilled?: (value: number) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; (success?: (value: number) => Promise, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => Promise, error?: (error: any) => U, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise; } >s11 : Promise >then : { (onfulfilled?: (value: number) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; (success?: (value: number) => Promise, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => Promise, error?: (error: any) => U, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise; } diff --git a/tests/baselines/reference/promisePermutations2.errors.txt b/tests/baselines/reference/promisePermutations2.errors.txt index 4c202914eea6e..52c85859c14a6 100644 --- a/tests/baselines/reference/promisePermutations2.errors.txt +++ b/tests/baselines/reference/promisePermutations2.errors.txt @@ -69,26 +69,9 @@ tests/cases/compiler/promisePermutations2.ts(143,35): error TS2769: No overload Argument of type '(x: any) => IPromise' is not assignable to parameter of type '(error: any) => IPromise'. tests/cases/compiler/promisePermutations2.ts(151,36): error TS2345: Argument of type '(x: any) => IPromise' is not assignable to parameter of type '(error: any) => Promise'. Property 'catch' is missing in type 'IPromise' but required in type 'Promise'. -tests/cases/compiler/promisePermutations2.ts(155,21): error TS2769: No overload matches this call. - The last overload gave the following error. - Argument of type '{ (x: number): IPromise; (x: string): IPromise; }' is not assignable to parameter of type '(value: number) => IPromise'. - Type 'IPromise' is not assignable to type 'IPromise'. - Type 'number' is not assignable to type 'string'. -tests/cases/compiler/promisePermutations2.ts(157,21): error TS2345: Argument of type '{ (x: number): IPromise; (x: string): IPromise; }' is not assignable to parameter of type '(value: number) => IPromise'. - Type 'IPromise' is not assignable to type 'IPromise'. -tests/cases/compiler/promisePermutations2.ts(158,21): error TS2345: Argument of type '{ (x: number): Promise; (x: string): Promise; }' is not assignable to parameter of type '(value: number) => Promise'. - Type 'Promise' is not assignable to type 'Promise'. - Type 'number' is not assignable to type 'string'. -tests/cases/compiler/promisePermutations2.ts(159,21): error TS2345: Argument of type '{ (x: number): Promise; (x: string): Promise; }' is not assignable to parameter of type '(value: number) => IPromise'. - Call signature return types 'Promise' and 'IPromise' are incompatible. - The types of 'then' are incompatible between these types. - Type '{ (onfulfilled?: (value: number) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise; }' is not assignable to type '{ (success?: (value: string) => IPromise, error?: (error: any) => IPromise, progress?: (progress: any) => void): IPromise; (success?: (value: string) => IPromise, error?: (error: any) => U, progress?: (progress: any) => void): IPromise; (success?: (value: string) => U, error?: (error: any) => IPromise, progress?: (progress: any) => void): IPromise; (success?: (value: string) => U, error?: (error: any) => U, progress?: (progress: any) => void): IPromise; }'. - Types of parameters 'onfulfilled' and 'success' are incompatible. - Types of parameters 'value' and 'value' are incompatible. - Type 'number' is not assignable to type 'string'. -==== tests/cases/compiler/promisePermutations2.ts (33 errors) ==== +==== tests/cases/compiler/promisePermutations2.ts (29 errors) ==== // same as promisePermutations but without the same overloads in Promise interface Promise { @@ -356,32 +339,10 @@ tests/cases/compiler/promisePermutations2.ts(159,21): error TS2345: Argument of var r11: IPromise; var r11a = r11.then(testFunction11, testFunction11, testFunction11); // error - ~~~~~~~~~~~~~~ -!!! error TS2769: No overload matches this call. -!!! error TS2769: The last overload gave the following error. -!!! error TS2769: Argument of type '{ (x: number): IPromise; (x: string): IPromise; }' is not assignable to parameter of type '(value: number) => IPromise'. -!!! error TS2769: Type 'IPromise' is not assignable to type 'IPromise'. -!!! error TS2769: Type 'number' is not assignable to type 'string'. -!!! related TS2771 tests/cases/compiler/promisePermutations2.ts:12:5: The last overload is declared here. var s11: Promise; var s11a = s11.then(testFunction11, testFunction11, testFunction11); // ok - ~~~~~~~~~~~~~~ -!!! error TS2345: Argument of type '{ (x: number): IPromise; (x: string): IPromise; }' is not assignable to parameter of type '(value: number) => IPromise'. -!!! error TS2345: Type 'IPromise' is not assignable to type 'IPromise'. var s11b = s11.then(testFunction11P, testFunction11P, testFunction11P); // ok - ~~~~~~~~~~~~~~~ -!!! error TS2345: Argument of type '{ (x: number): Promise; (x: string): Promise; }' is not assignable to parameter of type '(value: number) => Promise'. -!!! error TS2345: Type 'Promise' is not assignable to type 'Promise'. -!!! error TS2345: Type 'number' is not assignable to type 'string'. var s11c = s11.then(testFunction11P, testFunction11, testFunction11); // ok - ~~~~~~~~~~~~~~~ -!!! error TS2345: Argument of type '{ (x: number): Promise; (x: string): Promise; }' is not assignable to parameter of type '(value: number) => IPromise'. -!!! error TS2345: Call signature return types 'Promise' and 'IPromise' are incompatible. -!!! error TS2345: The types of 'then' are incompatible between these types. -!!! error TS2345: Type '{ (onfulfilled?: (value: number) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise; }' is not assignable to type '{ (success?: (value: string) => IPromise, error?: (error: any) => IPromise, progress?: (progress: any) => void): IPromise; (success?: (value: string) => IPromise, error?: (error: any) => U, progress?: (progress: any) => void): IPromise; (success?: (value: string) => U, error?: (error: any) => IPromise, progress?: (progress: any) => void): IPromise; (success?: (value: string) => U, error?: (error: any) => U, progress?: (progress: any) => void): IPromise; }'. -!!! error TS2345: Types of parameters 'onfulfilled' and 'success' are incompatible. -!!! error TS2345: Types of parameters 'value' and 'value' are incompatible. -!!! error TS2345: Type 'number' is not assignable to type 'string'. var r12 = testFunction12(x => x); var r12a = r12.then(testFunction12, testFunction12, testFunction12); // ok diff --git a/tests/baselines/reference/promisePermutations2.types b/tests/baselines/reference/promisePermutations2.types index af56d7088e2e6..ce9fdd7ad68ce 100644 --- a/tests/baselines/reference/promisePermutations2.types +++ b/tests/baselines/reference/promisePermutations2.types @@ -1144,8 +1144,8 @@ var r11: IPromise; >r11 : IPromise var r11a = r11.then(testFunction11, testFunction11, testFunction11); // error ->r11a : IPromise ->r11.then(testFunction11, testFunction11, testFunction11) : IPromise +>r11a : IPromise +>r11.then(testFunction11, testFunction11, testFunction11) : IPromise >r11.then : { (success?: (value: number) => IPromise, error?: (error: any) => IPromise, progress?: (progress: any) => void): IPromise; (success?: (value: number) => IPromise, error?: (error: any) => U, progress?: (progress: any) => void): IPromise; (success?: (value: number) => U, error?: (error: any) => IPromise, progress?: (progress: any) => void): IPromise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): IPromise; } >r11 : IPromise >then : { (success?: (value: number) => IPromise, error?: (error: any) => IPromise, progress?: (progress: any) => void): IPromise; (success?: (value: number) => IPromise, error?: (error: any) => U, progress?: (progress: any) => void): IPromise; (success?: (value: number) => U, error?: (error: any) => IPromise, progress?: (progress: any) => void): IPromise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): IPromise; } @@ -1157,8 +1157,8 @@ var s11: Promise; >s11 : Promise var s11a = s11.then(testFunction11, testFunction11, testFunction11); // ok ->s11a : Promise> ->s11.then(testFunction11, testFunction11, testFunction11) : Promise> +>s11a : Promise> +>s11.then(testFunction11, testFunction11, testFunction11) : Promise> >s11.then : { (onfulfilled?: (value: number) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise; } >s11 : Promise >then : { (onfulfilled?: (value: number) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise; } @@ -1167,8 +1167,8 @@ var s11a = s11.then(testFunction11, testFunction11, testFunction11); // ok >testFunction11 : { (x: number): IPromise; (x: string): IPromise; } var s11b = s11.then(testFunction11P, testFunction11P, testFunction11P); // ok ->s11b : Promise> ->s11.then(testFunction11P, testFunction11P, testFunction11P) : Promise> +>s11b : Promise> +>s11.then(testFunction11P, testFunction11P, testFunction11P) : Promise> >s11.then : { (onfulfilled?: (value: number) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise; } >s11 : Promise >then : { (onfulfilled?: (value: number) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise; } @@ -1177,8 +1177,8 @@ var s11b = s11.then(testFunction11P, testFunction11P, testFunction11P); // ok >testFunction11P : { (x: number): Promise; (x: string): Promise; } var s11c = s11.then(testFunction11P, testFunction11, testFunction11); // ok ->s11c : Promise> ->s11.then(testFunction11P, testFunction11, testFunction11) : Promise> +>s11c : Promise> +>s11.then(testFunction11P, testFunction11, testFunction11) : Promise> >s11.then : { (onfulfilled?: (value: number) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise; } >s11 : Promise >then : { (onfulfilled?: (value: number) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise; } diff --git a/tests/baselines/reference/promisePermutations3.errors.txt b/tests/baselines/reference/promisePermutations3.errors.txt index a2de90f2d05d3..16d6bd6a07e04 100644 --- a/tests/baselines/reference/promisePermutations3.errors.txt +++ b/tests/baselines/reference/promisePermutations3.errors.txt @@ -86,32 +86,9 @@ tests/cases/compiler/promisePermutations3.ts(151,36): error TS2769: No overload The last overload gave the following error. Argument of type '(x: any) => IPromise' is not assignable to parameter of type '(error: any) => Promise'. Property 'catch' is missing in type 'IPromise' but required in type 'Promise'. -tests/cases/compiler/promisePermutations3.ts(155,21): error TS2345: Argument of type '{ (x: number): IPromise; (x: string): IPromise; }' is not assignable to parameter of type '(value: number) => IPromise'. - Type 'IPromise' is not assignable to type 'IPromise'. - Type 'number' is not assignable to type 'string'. -tests/cases/compiler/promisePermutations3.ts(157,21): error TS2769: No overload matches this call. - The last overload gave the following error. - Argument of type '{ (x: number): IPromise; (x: string): IPromise; }' is not assignable to parameter of type '(value: number) => IPromise'. - Type 'IPromise' is not assignable to type 'IPromise'. -tests/cases/compiler/promisePermutations3.ts(158,21): error TS2769: No overload matches this call. - The last overload gave the following error. - Argument of type '{ (x: number): Promise; (x: string): Promise; }' is not assignable to parameter of type '(value: number) => Promise'. - Type 'Promise' is not assignable to type 'Promise'. - Type 'number' is not assignable to type 'string'. -tests/cases/compiler/promisePermutations3.ts(159,21): error TS2769: No overload matches this call. - The last overload gave the following error. - Argument of type '{ (x: number): Promise; (x: string): Promise; }' is not assignable to parameter of type '(value: number) => IPromise'. - Call signature return types 'Promise' and 'IPromise' are incompatible. - The types of 'then' are incompatible between these types. - Type '{ (onfulfilled?: (value: number) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; (success?: (value: number) => Promise, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => Promise, error?: (error: any) => U, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise; }' is not assignable to type '(success?: (value: string) => U, error?: (error: any) => U, progress?: (progress: any) => void) => IPromise'. - Types of parameters 'onfulfilled' and 'success' are incompatible. - Types of parameters 'value' and 'value' are incompatible. - Type 'number' is not assignable to type 'string'. -tests/cases/compiler/promisePermutations3.ts(165,21): error TS2345: Argument of type '{ (x: T): IPromise; (x: T, y: T): Promise; }' is not assignable to parameter of type '(value: (x: any) => any) => Promise'. - Property 'catch' is missing in type 'IPromise' but required in type 'Promise'. -==== tests/cases/compiler/promisePermutations3.ts (35 errors) ==== +==== tests/cases/compiler/promisePermutations3.ts (30 errors) ==== // same as promisePermutations but without the same overloads in IPromise interface Promise { @@ -404,46 +381,14 @@ tests/cases/compiler/promisePermutations3.ts(165,21): error TS2345: Argument of var r11: IPromise; var r11a = r11.then(testFunction11, testFunction11, testFunction11); // ok - ~~~~~~~~~~~~~~ -!!! error TS2345: Argument of type '{ (x: number): IPromise; (x: string): IPromise; }' is not assignable to parameter of type '(value: number) => IPromise'. -!!! error TS2345: Type 'IPromise' is not assignable to type 'IPromise'. -!!! error TS2345: Type 'number' is not assignable to type 'string'. var s11: Promise; var s11a = s11.then(testFunction11, testFunction11, testFunction11); // ok - ~~~~~~~~~~~~~~ -!!! error TS2769: No overload matches this call. -!!! error TS2769: The last overload gave the following error. -!!! error TS2769: Argument of type '{ (x: number): IPromise; (x: string): IPromise; }' is not assignable to parameter of type '(value: number) => IPromise'. -!!! error TS2769: Type 'IPromise' is not assignable to type 'IPromise'. -!!! related TS2771 tests/cases/compiler/promisePermutations3.ts:7:5: The last overload is declared here. var s11b = s11.then(testFunction11P, testFunction11P, testFunction11P); // error - ~~~~~~~~~~~~~~~ -!!! error TS2769: No overload matches this call. -!!! error TS2769: The last overload gave the following error. -!!! error TS2769: Argument of type '{ (x: number): Promise; (x: string): Promise; }' is not assignable to parameter of type '(value: number) => Promise'. -!!! error TS2769: Type 'Promise' is not assignable to type 'Promise'. -!!! error TS2769: Type 'number' is not assignable to type 'string'. -!!! related TS2771 tests/cases/compiler/promisePermutations3.ts:7:5: The last overload is declared here. var s11c = s11.then(testFunction11P, testFunction11, testFunction11); // error - ~~~~~~~~~~~~~~~ -!!! error TS2769: No overload matches this call. -!!! error TS2769: The last overload gave the following error. -!!! error TS2769: Argument of type '{ (x: number): Promise; (x: string): Promise; }' is not assignable to parameter of type '(value: number) => IPromise'. -!!! error TS2769: Call signature return types 'Promise' and 'IPromise' are incompatible. -!!! error TS2769: The types of 'then' are incompatible between these types. -!!! error TS2769: Type '{ (onfulfilled?: (value: number) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; (success?: (value: number) => Promise, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => Promise, error?: (error: any) => U, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise; }' is not assignable to type '(success?: (value: string) => U, error?: (error: any) => U, progress?: (progress: any) => void) => IPromise'. -!!! error TS2769: Types of parameters 'onfulfilled' and 'success' are incompatible. -!!! error TS2769: Types of parameters 'value' and 'value' are incompatible. -!!! error TS2769: Type 'number' is not assignable to type 'string'. -!!! related TS2771 tests/cases/compiler/promisePermutations3.ts:7:5: The last overload is declared here. var r12 = testFunction12(x => x); var r12a = r12.then(testFunction12, testFunction12, testFunction12); // ok var s12 = testFunction12(x => x); var s12a = s12.then(testFunction12, testFunction12, testFunction12); // ok var s12b = s12.then(testFunction12P, testFunction12P, testFunction12P); // ok - ~~~~~~~~~~~~~~~ -!!! error TS2345: Argument of type '{ (x: T): IPromise; (x: T, y: T): Promise; }' is not assignable to parameter of type '(value: (x: any) => any) => Promise'. -!!! error TS2345: Property 'catch' is missing in type 'IPromise' but required in type 'Promise'. -!!! related TS2728 /.ts/lib.es5.d.ts:--:--: 'catch' is declared here. var s12c = s12.then(testFunction12P, testFunction12, testFunction12); // ok \ No newline at end of file diff --git a/tests/baselines/reference/promisePermutations3.types b/tests/baselines/reference/promisePermutations3.types index a92245e60965d..6c977f54ce308 100644 --- a/tests/baselines/reference/promisePermutations3.types +++ b/tests/baselines/reference/promisePermutations3.types @@ -1144,8 +1144,8 @@ var r11: IPromise; >r11 : IPromise var r11a = r11.then(testFunction11, testFunction11, testFunction11); // ok ->r11a : IPromise> ->r11.then(testFunction11, testFunction11, testFunction11) : IPromise> +>r11a : IPromise> +>r11.then(testFunction11, testFunction11, testFunction11) : IPromise> >r11.then : (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void) => IPromise >r11 : IPromise >then : (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void) => IPromise @@ -1157,8 +1157,8 @@ var s11: Promise; >s11 : Promise var s11a = s11.then(testFunction11, testFunction11, testFunction11); // ok ->s11a : Promise ->s11.then(testFunction11, testFunction11, testFunction11) : Promise +>s11a : Promise> +>s11.then(testFunction11, testFunction11, testFunction11) : Promise> >s11.then : { (onfulfilled?: (value: number) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; (success?: (value: number) => Promise, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => Promise, error?: (error: any) => U, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise; } >s11 : Promise >then : { (onfulfilled?: (value: number) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; (success?: (value: number) => Promise, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => Promise, error?: (error: any) => U, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise; } @@ -1167,8 +1167,8 @@ var s11a = s11.then(testFunction11, testFunction11, testFunction11); // ok >testFunction11 : { (x: number): IPromise; (x: string): IPromise; } var s11b = s11.then(testFunction11P, testFunction11P, testFunction11P); // error ->s11b : Promise ->s11.then(testFunction11P, testFunction11P, testFunction11P) : Promise +>s11b : Promise +>s11.then(testFunction11P, testFunction11P, testFunction11P) : Promise >s11.then : { (onfulfilled?: (value: number) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; (success?: (value: number) => Promise, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => Promise, error?: (error: any) => U, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise; } >s11 : Promise >then : { (onfulfilled?: (value: number) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; (success?: (value: number) => Promise, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => Promise, error?: (error: any) => U, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise; } @@ -1177,8 +1177,8 @@ var s11b = s11.then(testFunction11P, testFunction11P, testFunction11P); // error >testFunction11P : { (x: number): Promise; (x: string): Promise; } var s11c = s11.then(testFunction11P, testFunction11, testFunction11); // error ->s11c : Promise ->s11.then(testFunction11P, testFunction11, testFunction11) : Promise +>s11c : Promise> +>s11.then(testFunction11P, testFunction11, testFunction11) : Promise> >s11.then : { (onfulfilled?: (value: number) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; (success?: (value: number) => Promise, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => Promise, error?: (error: any) => U, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise; } >s11 : Promise >then : { (onfulfilled?: (value: number) => TResult1 | PromiseLike, onrejected?: (reason: any) => TResult2 | PromiseLike): Promise; (success?: (value: number) => Promise, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => Promise, error?: (error: any) => U, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => Promise, progress?: (progress: any) => void): Promise; (success?: (value: number) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise; } @@ -1223,8 +1223,8 @@ var s12a = s12.then(testFunction12, testFunction12, testFunction12); // ok >testFunction12 : { (x: T): IPromise; (x: T, y: T): IPromise; } var s12b = s12.then(testFunction12P, testFunction12P, testFunction12P); // ok ->s12b : IPromise> ->s12.then(testFunction12P, testFunction12P, testFunction12P) : IPromise> +>s12b : IPromise> +>s12.then(testFunction12P, testFunction12P, testFunction12P) : IPromise> >s12.then : (success?: (value: (x: any) => any) => U, error?: (error: any) => U, progress?: (progress: any) => void) => IPromise >s12 : IPromise<(x: any) => any> >then : (success?: (value: (x: any) => any) => U, error?: (error: any) => U, progress?: (progress: any) => void) => IPromise diff --git a/tests/cases/compiler/overloadInferenceAlternativesAndConstContexts.ts b/tests/cases/compiler/overloadInferenceAlternativesAndConstContexts.ts new file mode 100644 index 0000000000000..54b89da71708a --- /dev/null +++ b/tests/cases/compiler/overloadInferenceAlternativesAndConstContexts.ts @@ -0,0 +1,12 @@ +// @strict: true +declare function sfc(props: { x: T1, y: T1 }): 1; +declare function sfc(props: { a: T2, b: T2 }): T2; +declare function sfc(props: { q: T3, t: T3 }): 3; + +declare function factory< + TProps, + TResult +>(tag: (props: TProps) => TResult, props: TProps, key?: string): TResult; + +const result = factory(sfc, {a: 0, b: 0}); +const result2 = factory<{a: 0, b: 0}, 0>(sfc, {a: 0, b: 0}); diff --git a/tests/cases/compiler/overloadedGenericInference.ts b/tests/cases/compiler/overloadedGenericInference.ts new file mode 100644 index 0000000000000..9a231c021a27b --- /dev/null +++ b/tests/cases/compiler/overloadedGenericInference.ts @@ -0,0 +1,18 @@ +// @target: es6 +// @strict: true +// #35501 +declare function fn(x: string): string; +declare function fn(x: string[]): string; + +declare function map(fn: (item: A) => R, list: A[]): R[]; + +const mapped = map(fn, ['1']); + +// #30294 (partial fix) +declare class C { + static x(y: number): number; + static x(): number; +} +C.x.call(C, 1); // ok +C.x.call(C); // ok +C.x.call(1); // ok (not an error because the `this` type of `x` is not constrained)