diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 77f35376da785..2d94c14eb7f49 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1010,6 +1010,7 @@ import { SignatureFlags, SignatureKind, singleElementArray, + SingleSignatureType, skipOuterExpressions, skipParentheses, skipTrivia, @@ -7313,7 +7314,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const abstractSignatures = filter(resolved.constructSignatures, signature => !!(signature.flags & SignatureFlags.Abstract)); if (some(abstractSignatures)) { - const types = map(abstractSignatures, getOrCreateTypeFromSignature); + const types = map(abstractSignatures, s => getOrCreateTypeFromSignature(s)); // count the number of type elements excluding abstract constructors const typeElementCount = resolved.callSignatures.length + (resolved.constructSignatures.length - abstractSignatures.length) + @@ -16472,17 +16473,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - function getSignatureInstantiation(signature: Signature, typeArguments: Type[] | undefined, isJavascript: boolean, inferredTypeParameters?: readonly TypeParameter[]): Signature { + function getSignatureInstantiation(signature: Signature, typeArguments: readonly Type[] | undefined, isJavascript: boolean, inferredTypeParameters?: readonly TypeParameter[]): Signature { const instantiatedSignature = getSignatureInstantiationWithoutFillingInTypeArguments(signature, fillMissingTypeArguments(typeArguments, signature.typeParameters, getMinTypeArgumentCount(signature.typeParameters), isJavascript)); if (inferredTypeParameters) { const returnSignature = getSingleCallOrConstructSignature(getReturnTypeOfSignature(instantiatedSignature)); if (returnSignature) { const newReturnSignature = cloneSignature(returnSignature); newReturnSignature.typeParameters = inferredTypeParameters; - const newReturnType = getOrCreateTypeFromSignature(newReturnSignature) as AnonymousType; - newReturnType.mapper = instantiatedSignature.mapper; const newInstantiatedSignature = cloneSignature(instantiatedSignature); - newInstantiatedSignature.resolvedReturnType = newReturnType; + newInstantiatedSignature.resolvedReturnType = getOrCreateTypeFromSignature(newReturnSignature); return newInstantiatedSignature; } } @@ -16542,6 +16541,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ); } + function getImplementationSignature(signature: Signature) { + return signature.typeParameters ? + signature.implementationSignatureCache ||= createImplementationSignature(signature) : + signature; + } + + function createImplementationSignature(signature: Signature) { + return signature.typeParameters ? instantiateSignature(signature, createTypeMapper([], [])) : signature; + } + function getBaseSignature(signature: Signature) { const typeParameters = signature.typeParameters; if (typeParameters) { @@ -16563,7 +16572,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return signature; } - function getOrCreateTypeFromSignature(signature: Signature): ObjectType { + function getOrCreateTypeFromSignature(signature: Signature, outerTypeParameters?: TypeParameter[]): ObjectType { // There are two ways to declare a construct signature, one is by declaring a class constructor // using the constructor keyword, and the other is declaring a bare construct signature in an // object type literal or interface (using the new keyword). Each way of declaring a constructor @@ -16574,7 +16583,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If declaration is undefined, it is likely to be the signature of the default constructor. const isConstructor = kind === undefined || kind === SyntaxKind.Constructor || kind === SyntaxKind.ConstructSignature || kind === SyntaxKind.ConstructorType; - const type = createObjectType(ObjectFlags.Anonymous | ObjectFlags.SingleSignatureType, signature.declaration?.symbol); + // The type must have a symbol with a `Function` flag and a declaration in order to be correctly flagged as possibly containing + // type variables by `couldContainTypeVariables` + const type = createObjectType(ObjectFlags.Anonymous | ObjectFlags.SingleSignatureType, createSymbol(SymbolFlags.Function, InternalSymbolName.Function)) as SingleSignatureType; + if (signature.declaration && !nodeIsSynthesized(signature.declaration)) { // skip synthetic declarations - keeping those around could be bad, since they lack a parent pointer + type.symbol.declarations = [signature.declaration]; + type.symbol.valueDeclaration = signature.declaration; + } + outerTypeParameters ||= signature.declaration && getOuterTypeParameters(signature.declaration, /*includeThisTypes*/ true); + type.outerTypeParameters = outerTypeParameters; + type.members = emptySymbols; type.properties = emptyArray; type.callSignatures = !isConstructor ? [signature] : emptyArray; @@ -20564,14 +20582,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return createTypeMapper(map(forwardInferences, i => i.typeParameter), map(forwardInferences, () => unknownType)); } - /** - * Return a type mapper that combines the context's return mapper with a mapper that erases any additional type parameters - * to their inferences at the time of creation. - */ - function createOuterReturnMapper(context: InferenceContext) { - return context.outerReturnMapper ??= mergeTypeMappers(context.returnMapper, cloneInferenceContext(context).mapper); - } - function combineTypeMappers(mapper1: TypeMapper | undefined, mapper2: TypeMapper): TypeMapper { return mapper1 ? makeCompositeTypeMapper(TypeMapKind.Composite, mapper1, mapper2) : mapper2; } @@ -20668,7 +20678,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const links = getNodeLinks(declaration); const target = type.objectFlags & ObjectFlags.Reference ? links.resolvedType! as DeferredTypeReference : type.objectFlags & ObjectFlags.Instantiated ? type.target! : type; - let typeParameters = links.outerTypeParameters; + let typeParameters = type.objectFlags & ObjectFlags.SingleSignatureType ? (type as SingleSignatureType).outerTypeParameters : links.outerTypeParameters; if (!typeParameters) { // The first time an anonymous type is instantiated we compute and store a list of the type // parameters that are in scope (and therefore potentially referenced). For type literals that @@ -20694,17 +20704,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const typeArguments = map(typeParameters, t => getMappedType(t, combinedMapper)); const newAliasSymbol = aliasSymbol || type.aliasSymbol; const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(type.aliasTypeArguments, mapper); - const id = getTypeListId(typeArguments) + getAliasId(newAliasSymbol, newAliasTypeArguments); + const id = (type.objectFlags & ObjectFlags.SingleSignatureType ? "S" : "") + getTypeListId(typeArguments) + getAliasId(newAliasSymbol, newAliasTypeArguments); if (!target.instantiations) { target.instantiations = new Map(); target.instantiations.set(getTypeListId(typeParameters) + getAliasId(target.aliasSymbol, target.aliasTypeArguments), target); } let result = target.instantiations.get(id); if (!result) { - let newMapper = createTypeMapper(typeParameters, typeArguments); - if (target.objectFlags & ObjectFlags.SingleSignatureType && mapper) { - newMapper = combineTypeMappers(newMapper, mapper); + if (type.objectFlags & ObjectFlags.SingleSignatureType) { + result = instantiateAnonymousType(type, mapper); + target.instantiations.set(id, result); + return result; } + const newMapper = createTypeMapper(typeParameters, typeArguments); result = target.objectFlags & ObjectFlags.Reference ? createDeferredTypeReference((type as DeferredTypeReference).target, (type as DeferredTypeReference).node, newMapper, newAliasSymbol, newAliasTypeArguments) : target.objectFlags & ObjectFlags.Mapped ? instantiateMappedType(target as MappedType, newMapper, newAliasSymbol, newAliasTypeArguments) : instantiateAnonymousType(target, newMapper, newAliasSymbol, newAliasTypeArguments); @@ -20902,6 +20914,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (type.objectFlags & ObjectFlags.InstantiationExpressionType) { (result as InstantiationExpressionType).node = (type as InstantiationExpressionType).node; } + if (type.objectFlags & ObjectFlags.SingleSignatureType) { + (result as SingleSignatureType).outerTypeParameters = (type as SingleSignatureType).outerTypeParameters; + } result.target = type; result.mapper = mapper; result.aliasSymbol = aliasSymbol || type.aliasSymbol; @@ -26296,6 +26311,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const result = !!(type.flags & TypeFlags.Instantiable || type.flags & TypeFlags.Object && !isNonGenericTopLevelType(type) && ( objectFlags & ObjectFlags.Reference && ((type as TypeReference).node || some(getTypeArguments(type as TypeReference), couldContainTypeVariables)) || + objectFlags & ObjectFlags.SingleSignatureType && !!length((type as SingleSignatureType).outerTypeParameters) || objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations || objectFlags & (ObjectFlags.Mapped | ObjectFlags.ReverseMapped | ObjectFlags.ObjectRestType | ObjectFlags.InstantiationExpressionType) ) || @@ -26677,6 +26693,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } + /** + * @returns `true` if `type` has the shape `[T[0]]` where `T` is `typeParameter` + */ + function isTupleOfSelf(typeParameter: TypeParameter, type: Type) { + return isTupleType(type) && getTupleElementType(type, 0) === getIndexedAccessType(typeParameter, getNumberLiteralType(0)) && !getTypeOfPropertyOfType(type, "1" as __String); + } + function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority = InferencePriority.None, contravariant = false) { let bivariant = false; let propagationType: Type; @@ -26805,6 +26828,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { inference.priority = priority; } if (priority === inference.priority) { + // Inferring A to [A[0]] is a zero information inference (it guarantees A becomes its constraint), but oft arises from generic argument list inferences + // By discarding it early, we can allow more fruitful results to be used instead. + if (isTupleOfSelf(inference.typeParameter, candidate)) { + return; + } // We make contravariant inferences only if we are in a pure contravariant position, // i.e. only if we have not descended into a bivariant position. if (contravariant && !bivariant) { @@ -35769,12 +35797,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // from the return type. We need a separate inference pass here because (a) instantiation of // the source type uses the outer context's return mapper (which excludes inferences made from // outer arguments), and (b) we don't want any further inferences going into this context. - // We use `createOuterReturnMapper` to ensure that all occurrences of outer type parameters are - // replaced with inferences produced from the outer return type or preceding outer arguments. - // This protects against circular inferences, i.e. avoiding situations where inferences reference - // type parameters for which the inferences are being made. const returnContext = createInferenceContext(signature.typeParameters!, signature, context.flags); - const returnSourceType = instantiateType(contextualType, outerContext && createOuterReturnMapper(outerContext)); + const returnSourceType = instantiateType(contextualType, outerContext && outerContext.returnMapper); inferTypes(returnContext.inferences, returnSourceType, inferenceTargetType); context.returnMapper = some(returnContext.inferences, hasInferenceCandidates) ? getMapperFromContext(cloneInferredPartOfContext(returnContext)) : undefined; } @@ -36049,6 +36073,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkMode: CheckMode, reportErrors: boolean, containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, + inferenceContext: InferenceContext | undefined, ): readonly Diagnostic[] | undefined { const errorOutputContainer: ErrorOutputContainer = { errors: undefined, skipLogging: true }; if (isJsxCallLike(node)) { @@ -36083,7 +36108,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If one or more arguments are still excluded (as indicated by CheckMode.SkipContextSensitive), // we obtain the regular type of any object literal arguments because we may not have inferred complete // parameter types yet and therefore excess property checks may yield false positives (see #17041). - const checkArgType = checkMode & CheckMode.SkipContextSensitive ? getRegularTypeOfObjectLiteral(argType) : argType; + const regularArgType = checkMode & CheckMode.SkipContextSensitive ? getRegularTypeOfObjectLiteral(argType) : argType; + // If this was inferred under a given inference context, we may need to instantiate the expression type to finish resolving + // the type variables in the expression. + const checkArgType = inferenceContext ? instantiateType(regularArgType, inferenceContext.nonFixingMapper) : regularArgType; const effectiveCheckArgumentNode = getEffectiveCheckNode(arg); if (!checkTypeRelatedToAndOptionallyElaborate(checkArgType, paramType, relation, reportErrors ? effectiveCheckArgumentNode : undefined, effectiveCheckArgumentNode, headMessage, containingMessageChain, errorOutputContainer)) { Debug.assert(!reportErrors || !!errorOutputContainer.errors, "parameter should have errors when reporting errors"); @@ -36581,7 +36609,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (headMessage) { chain = chainDiagnosticMessages(chain, headMessage); } - const diags = getSignatureApplicabilityError(node, args, last, assignableRelation, CheckMode.Normal, /*reportErrors*/ true, () => chain); + const diags = getSignatureApplicabilityError(node, args, last, assignableRelation, CheckMode.Normal, /*reportErrors*/ true, () => chain, /*inferenceContext*/ undefined); if (diags) { for (const d of diags) { if (last.declaration && candidatesForArgumentError.length > 3) { @@ -36603,7 +36631,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let i = 0; for (const c of candidatesForArgumentError) { const chain = () => chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Overload_0_of_1_2_gave_the_following_error, i + 1, candidates.length, signatureToString(c)); - const diags = getSignatureApplicabilityError(node, args, c, assignableRelation, CheckMode.Normal, /*reportErrors*/ true, chain); + const diags = getSignatureApplicabilityError(node, args, c, assignableRelation, CheckMode.Normal, /*reportErrors*/ true, chain, /*inferenceContext*/ undefined); if (diags) { if (diags.length <= min) { min = diags.length; @@ -36692,7 +36720,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (some(typeArguments) || !hasCorrectArity(node, args, candidate, signatureHelpTrailingComma)) { return undefined; } - if (getSignatureApplicabilityError(node, args, candidate, relation, CheckMode.Normal, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) { + if (getSignatureApplicabilityError(node, args, candidate, relation, CheckMode.Normal, /*reportErrors*/ false, /*containingMessageChain*/ undefined, /*inferenceContext*/ undefined)) { candidatesForArgumentError = [candidate]; return undefined; } @@ -36700,7 +36728,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } for (let candidateIndex = 0; candidateIndex < candidates.length; candidateIndex++) { - const candidate = candidates[candidateIndex]; + let candidate = candidates[candidateIndex]; if (!hasCorrectTypeArgumentArity(candidate, typeArguments) || !hasCorrectArity(node, args, candidate, signatureHelpTrailingComma)) { continue; } @@ -36709,7 +36737,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let inferenceContext: InferenceContext | undefined; if (candidate.typeParameters) { - let typeArgumentTypes: Type[] | undefined; + // If we are *inside the body of candidate*, we need to create a clone of `candidate` with differing type parameter identities, + // so our inference results for this call doesn't pollute expression types referencing the outer type parameter! + const paramLocation = candidate.typeParameters[0].symbol.declarations?.[0]?.parent; + const candidateParameterContext = paramLocation || (candidate.declaration && isConstructorDeclaration(candidate.declaration) ? candidate.declaration.parent : candidate.declaration); + if (candidateParameterContext && findAncestor(node, a => a === candidateParameterContext)) { + candidate = getImplementationSignature(candidate); + } + let typeArgumentTypes: readonly Type[] | undefined; if (some(typeArguments)) { typeArgumentTypes = checkTypeArguments(candidate, typeArguments, /*reportErrors*/ false); if (!typeArgumentTypes) { @@ -36718,8 +36753,10 @@ 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); + inferenceContext = createInferenceContext(candidate.typeParameters!, candidate, /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None); + // The resulting type arguments are instantiated with the inference context mapper, as the inferred types may still contain references to the inference context's + // type variables via contextual projection. These are kept generic until all inferences are locked in, so the dependencies expressed can pass constraint checks. + typeArgumentTypes = instantiateTypes(inferTypeArguments(node, candidate, args, argCheckMode | CheckMode.SkipGenericFunctions, inferenceContext), inferenceContext.nonFixingMapper); argCheckMode |= inferenceContext.flags & InferenceFlags.SkippedGenericFunction ? CheckMode.SkipGenericFunctions : CheckMode.Normal; } checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext && inferenceContext.inferredTypeParameters); @@ -36733,7 +36770,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else { checkCandidate = candidate; } - if (getSignatureApplicabilityError(node, args, checkCandidate, relation, argCheckMode, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) { + if (getSignatureApplicabilityError(node, args, checkCandidate, relation, argCheckMode, /*reportErrors*/ false, /*containingMessageChain*/ undefined, inferenceContext)) { // Give preference to error candidates that have no rest parameters (as they are more specific) (candidatesForArgumentError || (candidatesForArgumentError = [])).push(checkCandidate); continue; @@ -36744,7 +36781,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // round of type inference and applicability checking for this particular candidate. argCheckMode = CheckMode.Normal; if (inferenceContext) { - const typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode, inferenceContext); + const typeArgumentTypes = instantiateTypes(inferTypeArguments(node, candidate, args, argCheckMode, inferenceContext), inferenceContext.mapper); 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. @@ -36753,7 +36790,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { continue; } } - if (getSignatureApplicabilityError(node, args, checkCandidate, relation, argCheckMode, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) { + if (getSignatureApplicabilityError(node, args, checkCandidate, relation, argCheckMode, /*reportErrors*/ false, /*containingMessageChain*/ undefined, inferenceContext)) { // Give preference to error candidates that have no rest parameters (as they are more specific) (candidatesForArgumentError || (candidatesForArgumentError = [])).push(checkCandidate); continue; @@ -41479,7 +41516,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } } - return getOrCreateTypeFromSignature(instantiateSignatureInContextOf(signature, contextualSignature, context)); + // TODO: The signature may reference any outer inference contexts, but we map pop off and then apply new inference contexts, and thus get different inferred types. + // That this is cached on the *first* such attempt is not currently an issue, since expression types *also* get cached on the first pass. If we ever properly speculate, though, + // the cached "isolatedSignatureType" signature field absolutely needs to be included in the list of speculative caches. + return getOrCreateTypeFromSignature(instantiateSignatureInContextOf(signature, contextualSignature, context), flatMap(inferenceContexts, c => c && map(c.inferences, i => i.typeParameter)).slice()); } } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 1cfe3e04ba68d..5084fa37b7668 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -6540,7 +6540,7 @@ export const enum ObjectFlags { CouldContainTypeVariablesComputed = 1 << 19, // CouldContainTypeVariables flag has been computed /** @internal */ CouldContainTypeVariables = 1 << 20, // Type could contain a type variable - SingleSignatureType = 1 << 27, // A single signature type extracted from a potentially broader type + ClassOrInterface = Class | Interface, /** @internal */ RequiresWidening = ContainsWideningType | ContainsObjectOrArrayLiteral, @@ -6556,6 +6556,7 @@ export const enum ObjectFlags { ContainsSpread = 1 << 21, // Object literal contains spread operation ObjectRestType = 1 << 22, // Originates in object rest declaration InstantiationExpressionType = 1 << 23, // Originates in instantiation expression + SingleSignatureType = 1 << 27, // A single signature type extracted from a potentially broader type /** @internal */ IsClassInstanceClone = 1 << 24, // Type is a clone of a class instance type // Flags that require TypeFlags.Object and ObjectFlags.Reference @@ -6770,6 +6771,12 @@ export interface AnonymousType extends ObjectType { instantiations?: Map; // Instantiations of generic type alias (undefined if non-generic) } +/** @internal */ +// A SingleSignatureType may have bespoke outer type parameters to handle free type variable inferences +export interface SingleSignatureType extends AnonymousType { + outerTypeParameters?: TypeParameter[]; +} + /** @internal */ export interface InstantiationExpressionType extends AnonymousType { node: NodeWithTypeArguments; @@ -7055,6 +7062,8 @@ export interface Signature { isolatedSignatureType?: ObjectType; // A manufactured type that just contains the signature for purposes of signature comparison /** @internal */ instantiations?: Map; // Generic signature instantiation cache + /** @internal */ + implementationSignatureCache?: Signature; // Copy of the signature with fresh type parameters to use in checking the body of a potentially self-referential generic function (deferred) } export const enum IndexKind { @@ -7162,7 +7171,6 @@ export interface InferenceContext { mapper: TypeMapper; // Mapper that fixes inferences nonFixingMapper: TypeMapper; // Mapper that doesn't fix inferences returnMapper?: TypeMapper; // Type mapper for inferences from return types (if any) - outerReturnMapper?: TypeMapper; // Type mapper for inferences from return types of outer function (if any) inferredTypeParameters?: readonly TypeParameter[]; // Inferred type parameters for function result intraExpressionInferenceSites?: IntraExpressionInferenceSite[]; } diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 87942520f2ab0..2662a94c050e1 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -6718,11 +6718,11 @@ declare namespace ts { JSLiteral = 4096, FreshLiteral = 8192, ArrayLiteral = 16384, - SingleSignatureType = 134217728, ClassOrInterface = 3, ContainsSpread = 2097152, ObjectRestType = 4194304, InstantiationExpressionType = 8388608, + SingleSignatureType = 134217728, } interface ObjectType extends Type { objectFlags: ObjectFlags; diff --git a/tests/baselines/reference/genericCallInferenceInConditionalTypes1.types b/tests/baselines/reference/genericCallInferenceInConditionalTypes1.types index 0257dab6a9720..249599ee84d95 100644 --- a/tests/baselines/reference/genericCallInferenceInConditionalTypes1.types +++ b/tests/baselines/reference/genericCallInferenceInConditionalTypes1.types @@ -103,8 +103,8 @@ type Result1 = ComponentProps; // that could be incorrectly reused by this one type Result2 = Test<{ component: typeof ComponentWithForwardRef }>; // no `T` leak ->Result2 : Omit & { ref?: Ref | undefined; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>Result2 : PropsWithoutRef> & { ref?: Ref | undefined; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >component : >(props: PropsWithoutRef> & { ref?: Ref | undefined; }) => unknown > : ^ ^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >ComponentWithForwardRef : >(props: PropsWithoutRef> & { ref?: Ref | undefined; }) => unknown diff --git a/tests/baselines/reference/genericCallInferenceUsingThisTypeNoInvalidCacheReuseAfterMappedTypeApplication1.types b/tests/baselines/reference/genericCallInferenceUsingThisTypeNoInvalidCacheReuseAfterMappedTypeApplication1.types index 6ff710a93595e..5092a1329c93f 100644 --- a/tests/baselines/reference/genericCallInferenceUsingThisTypeNoInvalidCacheReuseAfterMappedTypeApplication1.types +++ b/tests/baselines/reference/genericCallInferenceUsingThisTypeNoInvalidCacheReuseAfterMappedTypeApplication1.types @@ -115,30 +115,30 @@ export declare const outer: ProxyMap; > : ^^^^^^^^^^^^^ export const a = inner.log(100); // Effect<100, never, never> ->a : F, this> -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->inner.log(100) : F, this> -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->inner.log : (n: N) => F, this> -> : ^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>a : Effect<100, never, never> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +>inner.log(100) : Effect<100, never, never> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +>inner.log : (n: N) => Effect +> : ^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >inner : XXX > : ^^^ ->log : (n: N) => F, this> -> : ^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>log : (n: N) => Effect +> : ^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >100 : 100 > : ^^^ export const b = outer.log(100); // Effect<100, never, XXX> ->b : F, this> -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->outer.log(100) : F, this> -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->outer.log : (n: N) => F, this> -> : ^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>b : Effect<100, never, never> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +>outer.log(100) : Effect<100, never, never> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +>outer.log : (n: N) => Effect +> : ^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >outer : ProxyMap > : ^^^^^^^^^^^^^ ->log : (n: N) => F, this> -> : ^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>log : (n: N) => Effect +> : ^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >100 : 100 > : ^^^ diff --git a/tests/baselines/reference/genericCallInferenceWithGenericLocalFunction.types b/tests/baselines/reference/genericCallInferenceWithGenericLocalFunction.types index eba6fd0e72fb2..888d2b81393a5 100644 --- a/tests/baselines/reference/genericCallInferenceWithGenericLocalFunction.types +++ b/tests/baselines/reference/genericCallInferenceWithGenericLocalFunction.types @@ -158,10 +158,10 @@ const added3 = addedSome3({ c: true }); > : ^^^^ const addP3_other = withP3({ foo: 'bar' }); ->addP3_other : (from: I) => (from2: I2) => I & I2 & { foo: string; } -> : ^ ^^ ^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->withP3({ foo: 'bar' }) : (from: I) => (from2: I2) => I & I2 & { foo: string; } -> : ^ ^^ ^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>addP3_other : (from: I) => (from2: I2) => I & I2 & { a: number; } +> : ^ ^^ ^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>withP3({ foo: 'bar' }) : (from: I) => (from2: I2) => I & I2 & { a: number; } +> : ^ ^^ ^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >withP3 :

(p: P) => (from: I) => (from2: I2) => I & I2 & P > : ^ ^^ ^^ ^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ >{ foo: 'bar' } : { foo: string; } @@ -172,12 +172,12 @@ const addP3_other = withP3({ foo: 'bar' }); > : ^^^^^ const addedSome3_other = addP3_other({ qwerty: 123 }); ->addedSome3_other : (from2: I2) => { qwerty: number; } & I2 & { foo: string; } -> : ^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->addP3_other({ qwerty: 123 }) : (from2: I2) => { qwerty: number; } & I2 & { foo: string; } -> : ^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->addP3_other : (from: I) => (from2: I2) => I & I2 & { foo: string; } -> : ^ ^^ ^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>addedSome3_other : (from2: I2) => { qwerty: number; } & I2 & { a: number; } +> : ^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>addP3_other({ qwerty: 123 }) : (from2: I2) => { qwerty: number; } & I2 & { a: number; } +> : ^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>addP3_other : (from: I) => (from2: I2) => I & I2 & { a: number; } +> : ^ ^^ ^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >{ qwerty: 123 } : { qwerty: number; } > : ^^^^^^^^^^^^^^^^^^^ >qwerty : number @@ -186,12 +186,12 @@ const addedSome3_other = addP3_other({ qwerty: 123 }); > : ^^^ const added3_other = addedSome3_other({ bazinga: true }); ->added3_other : { qwerty: number; } & { bazinga: boolean; } & { foo: string; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->addedSome3_other({ bazinga: true }) : { qwerty: number; } & { bazinga: boolean; } & { foo: string; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->addedSome3_other : (from2: I2) => { qwerty: number; } & I2 & { foo: string; } -> : ^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>added3_other : { qwerty: number; } & { bazinga: boolean; } & { a: number; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>addedSome3_other({ bazinga: true }) : { qwerty: number; } & { bazinga: boolean; } & { a: number; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>addedSome3_other : (from2: I2) => { qwerty: number; } & I2 & { a: number; } +> : ^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >{ bazinga: true } : { bazinga: true; } > : ^^^^^^^^^^^^^^^^^^ >bazinga : true diff --git a/tests/baselines/reference/genericFunctionInference1.types b/tests/baselines/reference/genericFunctionInference1.types index 93ff8f85b3541..7275fd51f97be 100644 --- a/tests/baselines/reference/genericFunctionInference1.types +++ b/tests/baselines/reference/genericFunctionInference1.types @@ -2,7 +2,7 @@ === Performance Stats === Type Count: 1,000 -Instantiation count: 1,000 +Instantiation count: 2,500 === genericFunctionInference1.ts === declare function pipe(ab: (...args: A) => B): (...args: A) => B; diff --git a/tests/baselines/reference/inferencePromiseArrays1.js b/tests/baselines/reference/inferencePromiseArrays1.js new file mode 100644 index 0000000000000..190ddef4fd4e4 --- /dev/null +++ b/tests/baselines/reference/inferencePromiseArrays1.js @@ -0,0 +1,21 @@ +//// [tests/cases/compiler/inferencePromiseArrays1.ts] //// + +//// [inferencePromiseArrays1.ts] +declare function getNum(): Promise; +declare function getStr(): Promise; +declare function useTuple(tuple: [number, string]): void; +const p1 = Promise.resolve([]).then(() => Promise.all([getNum(), getStr()])).then(useTuple); + +const p2 = Promise.resolve([]).then(()=> { + return Promise.all([0, ""]); +}) +const p3: Promise<[number, string]> = p2; + + +//// [inferencePromiseArrays1.js] +"use strict"; +const p1 = Promise.resolve([]).then(() => Promise.all([getNum(), getStr()])).then(useTuple); +const p2 = Promise.resolve([]).then(() => { + return Promise.all([0, ""]); +}); +const p3 = p2; diff --git a/tests/baselines/reference/inferencePromiseArrays1.symbols b/tests/baselines/reference/inferencePromiseArrays1.symbols new file mode 100644 index 0000000000000..c1c5d87ecdcf2 --- /dev/null +++ b/tests/baselines/reference/inferencePromiseArrays1.symbols @@ -0,0 +1,50 @@ +//// [tests/cases/compiler/inferencePromiseArrays1.ts] //// + +=== inferencePromiseArrays1.ts === +declare function getNum(): Promise; +>getNum : Symbol(getNum, Decl(inferencePromiseArrays1.ts, 0, 0)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) + +declare function getStr(): Promise; +>getStr : Symbol(getStr, Decl(inferencePromiseArrays1.ts, 0, 43)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) + +declare function useTuple(tuple: [number, string]): void; +>useTuple : Symbol(useTuple, Decl(inferencePromiseArrays1.ts, 1, 43)) +>tuple : Symbol(tuple, Decl(inferencePromiseArrays1.ts, 2, 26)) + +const p1 = Promise.resolve([]).then(() => Promise.all([getNum(), getStr()])).then(useTuple); +>p1 : Symbol(p1, Decl(inferencePromiseArrays1.ts, 3, 5)) +>Promise.resolve([]).then(() => Promise.all([getNum(), getStr()])).then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --)) +>Promise.resolve([]).then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --)) +>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) +>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --)) +>Promise.all : Symbol(PromiseConstructor.all, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) +>all : Symbol(PromiseConstructor.all, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>getNum : Symbol(getNum, Decl(inferencePromiseArrays1.ts, 0, 0)) +>getStr : Symbol(getStr, Decl(inferencePromiseArrays1.ts, 0, 43)) +>then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --)) +>useTuple : Symbol(useTuple, Decl(inferencePromiseArrays1.ts, 1, 43)) + +const p2 = Promise.resolve([]).then(()=> { +>p2 : Symbol(p2, Decl(inferencePromiseArrays1.ts, 5, 5)) +>Promise.resolve([]).then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --)) +>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) +>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --)) + + return Promise.all([0, ""]); +>Promise.all : Symbol(PromiseConstructor.all, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) +>all : Symbol(PromiseConstructor.all, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) + +}) +const p3: Promise<[number, string]> = p2; +>p3 : Symbol(p3, Decl(inferencePromiseArrays1.ts, 8, 5)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) +>p2 : Symbol(p2, Decl(inferencePromiseArrays1.ts, 5, 5)) + diff --git a/tests/baselines/reference/inferencePromiseArrays1.types b/tests/baselines/reference/inferencePromiseArrays1.types new file mode 100644 index 0000000000000..5b6ccadbca503 --- /dev/null +++ b/tests/baselines/reference/inferencePromiseArrays1.types @@ -0,0 +1,110 @@ +//// [tests/cases/compiler/inferencePromiseArrays1.ts] //// + +=== inferencePromiseArrays1.ts === +declare function getNum(): Promise; +>getNum : () => Promise +> : ^^^^^^ + +declare function getStr(): Promise; +>getStr : () => Promise +> : ^^^^^^ + +declare function useTuple(tuple: [number, string]): void; +>useTuple : (tuple: [number, string]) => void +> : ^ ^^ ^^^^^ +>tuple : [number, string] +> : ^^^^^^^^^^^^^^^^ + +const p1 = Promise.resolve([]).then(() => Promise.all([getNum(), getStr()])).then(useTuple); +>p1 : Promise +> : ^^^^^^^^^^^^^ +>Promise.resolve([]).then(() => Promise.all([getNum(), getStr()])).then(useTuple) : Promise +> : ^^^^^^^^^^^^^ +>Promise.resolve([]).then(() => Promise.all([getNum(), getStr()])).then : (onfulfilled?: ((value: [number, string]) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined) => Promise +> : ^ ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>Promise.resolve([]).then(() => Promise.all([getNum(), getStr()])) : Promise<[number, string]> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +>Promise.resolve([]).then : (onfulfilled?: ((value: never[]) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined) => Promise +> : ^ ^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>Promise.resolve([]) : Promise +> : ^^^^^^^^^^^^^^^^ +>Promise.resolve : { (): Promise; (value: T): Promise>; (value: T | PromiseLike): Promise>; } +> : ^^^^^^ ^^^ ^^ ^^ ^^^ ^^^ ^^ ^^ ^^^ ^^^ +>Promise : PromiseConstructor +> : ^^^^^^^^^^^^^^^^^^ +>resolve : { (): Promise; (value: T): Promise>; (value: T | PromiseLike): Promise>; } +> : ^^^^^^ ^^^ ^^ ^^ ^^^ ^^^ ^^ ^^ ^^^ ^^^ +>[] : never[] +> : ^^^^^^^ +>then : (onfulfilled?: ((value: never[]) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined) => Promise +> : ^ ^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>() => Promise.all([getNum(), getStr()]) : () => Promise<[number, string]> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>Promise.all([getNum(), getStr()]) : Promise<[number, string]> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +>Promise.all : { (values: Iterable>): Promise[]>; (values: T): Promise<{ -readonly [P in keyof T]: Awaited; }>; } +> : ^^^ ^^ ^^ ^^^ ^^^ ^^^^^^^^^ ^^ ^^ ^^^ ^^^ +>Promise : PromiseConstructor +> : ^^^^^^^^^^^^^^^^^^ +>all : { (values: Iterable>): Promise[]>; (values: T): Promise<{ -readonly [P in keyof T]: Awaited; }>; } +> : ^^^ ^^ ^^ ^^^ ^^^ ^^^^^^^^^ ^^ ^^ ^^^ ^^^ +>[getNum(), getStr()] : [Promise, Promise] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>getNum() : Promise +> : ^^^^^^^^^^^^^^^ +>getNum : () => Promise +> : ^^^^^^ +>getStr() : Promise +> : ^^^^^^^^^^^^^^^ +>getStr : () => Promise +> : ^^^^^^ +>then : (onfulfilled?: ((value: [number, string]) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined) => Promise +> : ^ ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>useTuple : (tuple: [number, string]) => void +> : ^ ^^ ^^^^^ + +const p2 = Promise.resolve([]).then(()=> { +>p2 : Promise<[number, string]> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +>Promise.resolve([]).then(()=> { return Promise.all([0, ""]);}) : Promise<[number, string]> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +>Promise.resolve([]).then : (onfulfilled?: ((value: never[]) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined) => Promise +> : ^ ^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>Promise.resolve([]) : Promise +> : ^^^^^^^^^^^^^^^^ +>Promise.resolve : { (): Promise; (value: T): Promise>; (value: T | PromiseLike): Promise>; } +> : ^^^^^^ ^^^ ^^ ^^ ^^^ ^^^ ^^ ^^ ^^^ ^^^ +>Promise : PromiseConstructor +> : ^^^^^^^^^^^^^^^^^^ +>resolve : { (): Promise; (value: T): Promise>; (value: T | PromiseLike): Promise>; } +> : ^^^^^^ ^^^ ^^ ^^ ^^^ ^^^ ^^ ^^ ^^^ ^^^ +>[] : never[] +> : ^^^^^^^ +>then : (onfulfilled?: ((value: never[]) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined) => Promise +> : ^ ^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>()=> { return Promise.all([0, ""]);} : () => Promise<[number, string]> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + return Promise.all([0, ""]); +>Promise.all([0, ""]) : Promise<[number, string]> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +>Promise.all : { (values: Iterable>): Promise[]>; (values: T): Promise<{ -readonly [P in keyof T]: Awaited; }>; } +> : ^^^ ^^ ^^ ^^^ ^^^ ^^^^^^^^^ ^^ ^^ ^^^ ^^^ +>Promise : PromiseConstructor +> : ^^^^^^^^^^^^^^^^^^ +>all : { (values: Iterable>): Promise[]>; (values: T): Promise<{ -readonly [P in keyof T]: Awaited; }>; } +> : ^^^ ^^ ^^ ^^^ ^^^ ^^^^^^^^^ ^^ ^^ ^^^ ^^^ +>[0, ""] : [number, string] +> : ^^^^^^^^^^^^^^^^ +>0 : 0 +> : ^ +>"" : "" +> : ^^ + +}) +const p3: Promise<[number, string]> = p2; +>p3 : Promise<[number, string]> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +>p2 : Promise<[number, string]> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/baselines/reference/nestedGenericSpreadInference.types b/tests/baselines/reference/nestedGenericSpreadInference.types index 929a9cec916aa..266c1018102b8 100644 --- a/tests/baselines/reference/nestedGenericSpreadInference.types +++ b/tests/baselines/reference/nestedGenericSpreadInference.types @@ -22,14 +22,14 @@ declare function call(x: { x: (...args: A) => T }, ...ar > : ^ const leak = call(wrap((x: T) => x), 1); ->leak : unknown -> : ^^^^^^^ ->call(wrap((x: T) => x), 1) : unknown -> : ^^^^^^^ +>leak : number +> : ^^^^^^ +>call(wrap((x: T) => x), 1) : number +> : ^^^^^^ >call : (x: { x: (...args: A) => T; }, ...args: A) => T > : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^^^^ ^^ ^^^^^ ->wrap((x: T) => x) : { x: (x: unknown) => unknown; } -> : ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^ +>wrap((x: T) => x) : { x: (x: A[0]) => A[0]; } +> : ^^^^^^ ^^^^^^^^^^^^^^^^^^ >wrap : (x: X) => { x: X; } > : ^ ^^ ^^ ^^^^^ >(x: T) => x : (x: T) => T diff --git a/tests/baselines/reference/promisePermutations.types b/tests/baselines/reference/promisePermutations.types index 0c000ea24f39e..a752a677c0a4e 100644 --- a/tests/baselines/reference/promisePermutations.types +++ b/tests/baselines/reference/promisePermutations.types @@ -2,7 +2,7 @@ === Performance Stats === Type Count: 1,000 -> 2,500 -Instantiation count: 5,000 +Instantiation count: 5,000 -> 10,000 === promisePermutations.ts === interface Promise { diff --git a/tests/baselines/reference/promiseType.types b/tests/baselines/reference/promiseType.types index c9129080e5fc5..4aec603e3f2a6 100644 --- a/tests/baselines/reference/promiseType.types +++ b/tests/baselines/reference/promiseType.types @@ -1,7 +1,7 @@ //// [tests/cases/compiler/promiseType.ts] //// === Performance Stats === -Instantiation count: 1,000 +Instantiation count: 2,500 === promiseType.ts === declare var p: Promise; diff --git a/tests/cases/compiler/inferencePromiseArrays1.ts b/tests/cases/compiler/inferencePromiseArrays1.ts new file mode 100644 index 0000000000000..1c79bff676bc4 --- /dev/null +++ b/tests/cases/compiler/inferencePromiseArrays1.ts @@ -0,0 +1,12 @@ +// @strict: true +// @target: esnext + +declare function getNum(): Promise; +declare function getStr(): Promise; +declare function useTuple(tuple: [number, string]): void; +const p1 = Promise.resolve([]).then(() => Promise.all([getNum(), getStr()])).then(useTuple); + +const p2 = Promise.resolve([]).then(()=> { + return Promise.all([0, ""]); +}) +const p3: Promise<[number, string]> = p2;