mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 12:32:08 -06:00
Propagate outer type parameters of single signature types (#57403)
This commit is contained in:
parent
6d0cc1beda
commit
e1874f3ffe
@ -967,6 +967,7 @@ import {
|
||||
SignatureFlags,
|
||||
SignatureKind,
|
||||
singleElementArray,
|
||||
SingleSignatureType,
|
||||
skipOuterExpressions,
|
||||
skipParentheses,
|
||||
skipTrivia,
|
||||
@ -7165,7 +7166,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) +
|
||||
@ -15672,7 +15673,7 @@ 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));
|
||||
@ -15736,6 +15737,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) {
|
||||
@ -15757,7 +15768,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
|
||||
@ -15768,7 +15779,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);
|
||||
// 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;
|
||||
@ -19749,7 +19769,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
|
||||
@ -19980,6 +20000,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;
|
||||
@ -25263,6 +25286,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)
|
||||
) ||
|
||||
@ -25622,6 +25646,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;
|
||||
@ -25750,6 +25781,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) {
|
||||
@ -34388,6 +34424,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
checkMode: CheckMode,
|
||||
reportErrors: boolean,
|
||||
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
|
||||
inferenceContext: InferenceContext | undefined,
|
||||
): readonly Diagnostic[] | undefined {
|
||||
const errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } = { errors: undefined, skipLogging: true };
|
||||
if (isJsxOpeningLikeElement(node)) {
|
||||
@ -34422,7 +34459,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");
|
||||
@ -34887,7 +34927,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) {
|
||||
@ -34909,7 +34949,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;
|
||||
@ -34998,7 +35038,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;
|
||||
}
|
||||
@ -35006,7 +35046,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;
|
||||
}
|
||||
@ -35015,7 +35055,12 @@ 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!
|
||||
if (candidate.declaration && findAncestor(node, a => a === candidate.declaration)) {
|
||||
candidate = getImplementationSignature(candidate);
|
||||
}
|
||||
let typeArgumentTypes: readonly Type[] | undefined;
|
||||
if (some(typeArguments)) {
|
||||
typeArgumentTypes = checkTypeArguments(candidate, typeArguments, /*reportErrors*/ false);
|
||||
if (!typeArgumentTypes) {
|
||||
@ -35024,8 +35069,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);
|
||||
@ -35039,7 +35086,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;
|
||||
@ -35050,7 +35097,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.
|
||||
@ -35059,7 +35106,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;
|
||||
@ -39515,7 +39562,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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6221,6 +6221,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
|
||||
@ -6431,6 +6432,12 @@ export interface AnonymousType extends ObjectType {
|
||||
instantiations?: Map<string, Type>; // 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;
|
||||
@ -6716,6 +6723,8 @@ export interface Signature {
|
||||
isolatedSignatureType?: ObjectType; // A manufactured type that just contains the signature for purposes of signature comparison
|
||||
/** @internal */
|
||||
instantiations?: Map<string, Signature>; // 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 {
|
||||
|
||||
@ -6598,6 +6598,7 @@ declare namespace ts {
|
||||
ContainsSpread = 2097152,
|
||||
ObjectRestType = 4194304,
|
||||
InstantiationExpressionType = 8388608,
|
||||
SingleSignatureType = 134217728,
|
||||
}
|
||||
interface ObjectType extends Type {
|
||||
objectFlags: ObjectFlags;
|
||||
|
||||
@ -0,0 +1,52 @@
|
||||
//// [tests/cases/compiler/genericCallWithinOwnBodyCastTypeParameterIdentity.ts] ////
|
||||
|
||||
//// [genericCallWithinOwnBodyCastTypeParameterIdentity.ts]
|
||||
interface Thenable<Value> {
|
||||
then<V>(
|
||||
onFulfilled: (value: Value) => V | Thenable<V>,
|
||||
): Thenable<V>;
|
||||
}
|
||||
|
||||
const toThenable = <Result, Input>(fn: (input: Input) => Result | Thenable<Result>) =>
|
||||
(input: Input): Thenable<Result> => {
|
||||
const result = fn(input)
|
||||
return {
|
||||
then<V>(onFulfilled: (value: Result) => V | Thenable<V>) {
|
||||
return toThenable<V, Result>(onFulfilled)(result as Result)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const toThenableInferred = <Result, Input>(fn: (input: Input) => Result | Thenable<Result>) =>
|
||||
(input: Input): Thenable<Result> => {
|
||||
const result = fn(input)
|
||||
return {
|
||||
then(onFulfilled) {
|
||||
return toThenableInferred(onFulfilled)(result as Result)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
//// [genericCallWithinOwnBodyCastTypeParameterIdentity.js]
|
||||
"use strict";
|
||||
var toThenable = function (fn) {
|
||||
return function (input) {
|
||||
var result = fn(input);
|
||||
return {
|
||||
then: function (onFulfilled) {
|
||||
return toThenable(onFulfilled)(result);
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
var toThenableInferred = function (fn) {
|
||||
return function (input) {
|
||||
var result = fn(input);
|
||||
return {
|
||||
then: function (onFulfilled) {
|
||||
return toThenableInferred(onFulfilled)(result);
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,104 @@
|
||||
//// [tests/cases/compiler/genericCallWithinOwnBodyCastTypeParameterIdentity.ts] ////
|
||||
|
||||
=== genericCallWithinOwnBodyCastTypeParameterIdentity.ts ===
|
||||
interface Thenable<Value> {
|
||||
>Thenable : Symbol(Thenable, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 0, 0))
|
||||
>Value : Symbol(Value, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 0, 19))
|
||||
|
||||
then<V>(
|
||||
>then : Symbol(Thenable.then, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 0, 27))
|
||||
>V : Symbol(V, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 1, 9))
|
||||
|
||||
onFulfilled: (value: Value) => V | Thenable<V>,
|
||||
>onFulfilled : Symbol(onFulfilled, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 1, 12))
|
||||
>value : Symbol(value, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 2, 22))
|
||||
>Value : Symbol(Value, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 0, 19))
|
||||
>V : Symbol(V, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 1, 9))
|
||||
>Thenable : Symbol(Thenable, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 0, 0))
|
||||
>V : Symbol(V, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 1, 9))
|
||||
|
||||
): Thenable<V>;
|
||||
>Thenable : Symbol(Thenable, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 0, 0))
|
||||
>V : Symbol(V, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 1, 9))
|
||||
}
|
||||
|
||||
const toThenable = <Result, Input>(fn: (input: Input) => Result | Thenable<Result>) =>
|
||||
>toThenable : Symbol(toThenable, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 5))
|
||||
>Result : Symbol(Result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 20))
|
||||
>Input : Symbol(Input, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 27))
|
||||
>fn : Symbol(fn, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 35))
|
||||
>input : Symbol(input, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 40))
|
||||
>Input : Symbol(Input, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 27))
|
||||
>Result : Symbol(Result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 20))
|
||||
>Thenable : Symbol(Thenable, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 0, 0))
|
||||
>Result : Symbol(Result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 20))
|
||||
|
||||
(input: Input): Thenable<Result> => {
|
||||
>input : Symbol(input, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 7, 5))
|
||||
>Input : Symbol(Input, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 27))
|
||||
>Thenable : Symbol(Thenable, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 0, 0))
|
||||
>Result : Symbol(Result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 20))
|
||||
|
||||
const result = fn(input)
|
||||
>result : Symbol(result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 8, 13))
|
||||
>fn : Symbol(fn, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 35))
|
||||
>input : Symbol(input, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 7, 5))
|
||||
|
||||
return {
|
||||
then<V>(onFulfilled: (value: Result) => V | Thenable<V>) {
|
||||
>then : Symbol(then, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 9, 16))
|
||||
>V : Symbol(V, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 10, 17))
|
||||
>onFulfilled : Symbol(onFulfilled, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 10, 20))
|
||||
>value : Symbol(value, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 10, 34))
|
||||
>Result : Symbol(Result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 20))
|
||||
>V : Symbol(V, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 10, 17))
|
||||
>Thenable : Symbol(Thenable, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 0, 0))
|
||||
>V : Symbol(V, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 10, 17))
|
||||
|
||||
return toThenable<V, Result>(onFulfilled)(result as Result)
|
||||
>toThenable : Symbol(toThenable, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 5))
|
||||
>V : Symbol(V, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 10, 17))
|
||||
>Result : Symbol(Result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 20))
|
||||
>onFulfilled : Symbol(onFulfilled, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 10, 20))
|
||||
>result : Symbol(result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 8, 13))
|
||||
>Result : Symbol(Result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 20))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const toThenableInferred = <Result, Input>(fn: (input: Input) => Result | Thenable<Result>) =>
|
||||
>toThenableInferred : Symbol(toThenableInferred, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 5))
|
||||
>Result : Symbol(Result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 28))
|
||||
>Input : Symbol(Input, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 35))
|
||||
>fn : Symbol(fn, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 43))
|
||||
>input : Symbol(input, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 48))
|
||||
>Input : Symbol(Input, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 35))
|
||||
>Result : Symbol(Result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 28))
|
||||
>Thenable : Symbol(Thenable, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 0, 0))
|
||||
>Result : Symbol(Result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 28))
|
||||
|
||||
(input: Input): Thenable<Result> => {
|
||||
>input : Symbol(input, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 17, 5))
|
||||
>Input : Symbol(Input, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 35))
|
||||
>Thenable : Symbol(Thenable, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 0, 0))
|
||||
>Result : Symbol(Result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 28))
|
||||
|
||||
const result = fn(input)
|
||||
>result : Symbol(result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 18, 13))
|
||||
>fn : Symbol(fn, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 43))
|
||||
>input : Symbol(input, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 17, 5))
|
||||
|
||||
return {
|
||||
then(onFulfilled) {
|
||||
>then : Symbol(then, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 19, 16))
|
||||
>onFulfilled : Symbol(onFulfilled, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 20, 17))
|
||||
|
||||
return toThenableInferred(onFulfilled)(result as Result)
|
||||
>toThenableInferred : Symbol(toThenableInferred, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 5))
|
||||
>onFulfilled : Symbol(onFulfilled, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 20, 17))
|
||||
>result : Symbol(result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 18, 13))
|
||||
>Result : Symbol(Result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 28))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -0,0 +1,83 @@
|
||||
//// [tests/cases/compiler/genericCallWithinOwnBodyCastTypeParameterIdentity.ts] ////
|
||||
|
||||
=== genericCallWithinOwnBodyCastTypeParameterIdentity.ts ===
|
||||
interface Thenable<Value> {
|
||||
then<V>(
|
||||
>then : <V>(onFulfilled: (value: Value) => V | Thenable<V>) => Thenable<V>
|
||||
|
||||
onFulfilled: (value: Value) => V | Thenable<V>,
|
||||
>onFulfilled : (value: Value) => V | Thenable<V>
|
||||
>value : Value
|
||||
|
||||
): Thenable<V>;
|
||||
}
|
||||
|
||||
const toThenable = <Result, Input>(fn: (input: Input) => Result | Thenable<Result>) =>
|
||||
>toThenable : <Result, Input>(fn: (input: Input) => Result | Thenable<Result>) => (input: Input) => Thenable<Result>
|
||||
><Result, Input>(fn: (input: Input) => Result | Thenable<Result>) => (input: Input): Thenable<Result> => { const result = fn(input) return { then<V>(onFulfilled: (value: Result) => V | Thenable<V>) { return toThenable<V, Result>(onFulfilled)(result as Result) } }; } : <Result, Input>(fn: (input: Input) => Result | Thenable<Result>) => (input: Input) => Thenable<Result>
|
||||
>fn : (input: Input) => Result | Thenable<Result>
|
||||
>input : Input
|
||||
|
||||
(input: Input): Thenable<Result> => {
|
||||
>(input: Input): Thenable<Result> => { const result = fn(input) return { then<V>(onFulfilled: (value: Result) => V | Thenable<V>) { return toThenable<V, Result>(onFulfilled)(result as Result) } }; } : (input: Input) => Thenable<Result>
|
||||
>input : Input
|
||||
|
||||
const result = fn(input)
|
||||
>result : Result | Thenable<Result>
|
||||
>fn(input) : Result | Thenable<Result>
|
||||
>fn : (input: Input) => Result | Thenable<Result>
|
||||
>input : Input
|
||||
|
||||
return {
|
||||
>{ then<V>(onFulfilled: (value: Result) => V | Thenable<V>) { return toThenable<V, Result>(onFulfilled)(result as Result) } } : { then<V>(onFulfilled: (value: Result) => V | Thenable<V>): Thenable<V>; }
|
||||
|
||||
then<V>(onFulfilled: (value: Result) => V | Thenable<V>) {
|
||||
>then : <V>(onFulfilled: (value: Result) => V | Thenable<V>) => Thenable<V>
|
||||
>onFulfilled : (value: Result) => V | Thenable<V>
|
||||
>value : Result
|
||||
|
||||
return toThenable<V, Result>(onFulfilled)(result as Result)
|
||||
>toThenable<V, Result>(onFulfilled)(result as Result) : Thenable<V>
|
||||
>toThenable<V, Result>(onFulfilled) : (input: Result) => Thenable<V>
|
||||
>toThenable : <Result, Input>(fn: (input: Input) => Result | Thenable<Result>) => (input: Input) => Thenable<Result>
|
||||
>onFulfilled : (value: Result) => V | Thenable<V>
|
||||
>result as Result : Result
|
||||
>result : Result | Thenable<Result>
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const toThenableInferred = <Result, Input>(fn: (input: Input) => Result | Thenable<Result>) =>
|
||||
>toThenableInferred : <Result, Input>(fn: (input: Input) => Result | Thenable<Result>) => (input: Input) => Thenable<Result>
|
||||
><Result, Input>(fn: (input: Input) => Result | Thenable<Result>) => (input: Input): Thenable<Result> => { const result = fn(input) return { then(onFulfilled) { return toThenableInferred(onFulfilled)(result as Result) } }; } : <Result, Input>(fn: (input: Input) => Result | Thenable<Result>) => (input: Input) => Thenable<Result>
|
||||
>fn : (input: Input) => Result | Thenable<Result>
|
||||
>input : Input
|
||||
|
||||
(input: Input): Thenable<Result> => {
|
||||
>(input: Input): Thenable<Result> => { const result = fn(input) return { then(onFulfilled) { return toThenableInferred(onFulfilled)(result as Result) } }; } : (input: Input) => Thenable<Result>
|
||||
>input : Input
|
||||
|
||||
const result = fn(input)
|
||||
>result : Result | Thenable<Result>
|
||||
>fn(input) : Result | Thenable<Result>
|
||||
>fn : (input: Input) => Result | Thenable<Result>
|
||||
>input : Input
|
||||
|
||||
return {
|
||||
>{ then(onFulfilled) { return toThenableInferred(onFulfilled)(result as Result) } } : { then<V>(onFulfilled: (value: Result) => V | Thenable<V>): Thenable<V>; }
|
||||
|
||||
then(onFulfilled) {
|
||||
>then : <V>(onFulfilled: (value: Result) => V | Thenable<V>) => Thenable<V>
|
||||
>onFulfilled : (value: Result) => V | Thenable<V>
|
||||
|
||||
return toThenableInferred(onFulfilled)(result as Result)
|
||||
>toThenableInferred(onFulfilled)(result as Result) : Thenable<V>
|
||||
>toThenableInferred(onFulfilled) : (input: Result) => Thenable<V>
|
||||
>toThenableInferred : <Result, Input>(fn: (input: Input) => Result | Thenable<Result>) => (input: Input) => Thenable<Result>
|
||||
>onFulfilled : (value: Result) => V | Thenable<V>
|
||||
>result as Result : Result
|
||||
>result : Result | Thenable<Result>
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
14
tests/baselines/reference/nestedGenericSpreadInference.js
Normal file
14
tests/baselines/reference/nestedGenericSpreadInference.js
Normal file
@ -0,0 +1,14 @@
|
||||
//// [tests/cases/compiler/nestedGenericSpreadInference.ts] ////
|
||||
|
||||
//// [nestedGenericSpreadInference.ts]
|
||||
declare function wrap<X>(x: X): { x: X };
|
||||
declare function call<A extends unknown[], T>(x: { x: (...args: A) => T }, ...args: A): T;
|
||||
|
||||
// This should be of type `number` - ideally, it also would not error.
|
||||
const leak = call(wrap(<T>(x: T) => x), 1);
|
||||
|
||||
|
||||
//// [nestedGenericSpreadInference.js]
|
||||
"use strict";
|
||||
// This should be of type `number` - ideally, it also would not error.
|
||||
var leak = call(wrap(function (x) { return x; }), 1);
|
||||
@ -0,0 +1,34 @@
|
||||
//// [tests/cases/compiler/nestedGenericSpreadInference.ts] ////
|
||||
|
||||
=== nestedGenericSpreadInference.ts ===
|
||||
declare function wrap<X>(x: X): { x: X };
|
||||
>wrap : Symbol(wrap, Decl(nestedGenericSpreadInference.ts, 0, 0))
|
||||
>X : Symbol(X, Decl(nestedGenericSpreadInference.ts, 0, 22))
|
||||
>x : Symbol(x, Decl(nestedGenericSpreadInference.ts, 0, 25))
|
||||
>X : Symbol(X, Decl(nestedGenericSpreadInference.ts, 0, 22))
|
||||
>x : Symbol(x, Decl(nestedGenericSpreadInference.ts, 0, 33))
|
||||
>X : Symbol(X, Decl(nestedGenericSpreadInference.ts, 0, 22))
|
||||
|
||||
declare function call<A extends unknown[], T>(x: { x: (...args: A) => T }, ...args: A): T;
|
||||
>call : Symbol(call, Decl(nestedGenericSpreadInference.ts, 0, 41))
|
||||
>A : Symbol(A, Decl(nestedGenericSpreadInference.ts, 1, 22))
|
||||
>T : Symbol(T, Decl(nestedGenericSpreadInference.ts, 1, 42))
|
||||
>x : Symbol(x, Decl(nestedGenericSpreadInference.ts, 1, 46))
|
||||
>x : Symbol(x, Decl(nestedGenericSpreadInference.ts, 1, 50))
|
||||
>args : Symbol(args, Decl(nestedGenericSpreadInference.ts, 1, 55))
|
||||
>A : Symbol(A, Decl(nestedGenericSpreadInference.ts, 1, 22))
|
||||
>T : Symbol(T, Decl(nestedGenericSpreadInference.ts, 1, 42))
|
||||
>args : Symbol(args, Decl(nestedGenericSpreadInference.ts, 1, 74))
|
||||
>A : Symbol(A, Decl(nestedGenericSpreadInference.ts, 1, 22))
|
||||
>T : Symbol(T, Decl(nestedGenericSpreadInference.ts, 1, 42))
|
||||
|
||||
// This should be of type `number` - ideally, it also would not error.
|
||||
const leak = call(wrap(<T>(x: T) => x), 1);
|
||||
>leak : Symbol(leak, Decl(nestedGenericSpreadInference.ts, 4, 5))
|
||||
>call : Symbol(call, Decl(nestedGenericSpreadInference.ts, 0, 41))
|
||||
>wrap : Symbol(wrap, Decl(nestedGenericSpreadInference.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(nestedGenericSpreadInference.ts, 4, 24))
|
||||
>x : Symbol(x, Decl(nestedGenericSpreadInference.ts, 4, 27))
|
||||
>T : Symbol(T, Decl(nestedGenericSpreadInference.ts, 4, 24))
|
||||
>x : Symbol(x, Decl(nestedGenericSpreadInference.ts, 4, 27))
|
||||
|
||||
27
tests/baselines/reference/nestedGenericSpreadInference.types
Normal file
27
tests/baselines/reference/nestedGenericSpreadInference.types
Normal file
@ -0,0 +1,27 @@
|
||||
//// [tests/cases/compiler/nestedGenericSpreadInference.ts] ////
|
||||
|
||||
=== nestedGenericSpreadInference.ts ===
|
||||
declare function wrap<X>(x: X): { x: X };
|
||||
>wrap : <X>(x: X) => { x: X;}
|
||||
>x : X
|
||||
>x : X
|
||||
|
||||
declare function call<A extends unknown[], T>(x: { x: (...args: A) => T }, ...args: A): T;
|
||||
>call : <A extends unknown[], T>(x: { x: (...args: A) => T; }, ...args: A) => T
|
||||
>x : { x: (...args: A) => T; }
|
||||
>x : (...args: A) => T
|
||||
>args : A
|
||||
>args : A
|
||||
|
||||
// This should be of type `number` - ideally, it also would not error.
|
||||
const leak = call(wrap(<T>(x: T) => x), 1);
|
||||
>leak : number
|
||||
>call(wrap(<T>(x: T) => x), 1) : number
|
||||
>call : <A extends unknown[], T>(x: { x: (...args: A) => T; }, ...args: A) => T
|
||||
>wrap(<T>(x: T) => x) : { x: (x: A[0]) => A[0]; }
|
||||
>wrap : <X>(x: X) => { x: X; }
|
||||
><T>(x: T) => x : <T>(x: T) => T
|
||||
>x : T
|
||||
>x : T
|
||||
>1 : 1
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
// @strict: true
|
||||
interface Thenable<Value> {
|
||||
then<V>(
|
||||
onFulfilled: (value: Value) => V | Thenable<V>,
|
||||
): Thenable<V>;
|
||||
}
|
||||
|
||||
const toThenable = <Result, Input>(fn: (input: Input) => Result | Thenable<Result>) =>
|
||||
(input: Input): Thenable<Result> => {
|
||||
const result = fn(input)
|
||||
return {
|
||||
then<V>(onFulfilled: (value: Result) => V | Thenable<V>) {
|
||||
return toThenable<V, Result>(onFulfilled)(result as Result)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const toThenableInferred = <Result, Input>(fn: (input: Input) => Result | Thenable<Result>) =>
|
||||
(input: Input): Thenable<Result> => {
|
||||
const result = fn(input)
|
||||
return {
|
||||
then(onFulfilled) {
|
||||
return toThenableInferred(onFulfilled)(result as Result)
|
||||
}
|
||||
};
|
||||
}
|
||||
6
tests/cases/compiler/nestedGenericSpreadInference.ts
Normal file
6
tests/cases/compiler/nestedGenericSpreadInference.ts
Normal file
@ -0,0 +1,6 @@
|
||||
// @strict: true
|
||||
declare function wrap<X>(x: X): { x: X };
|
||||
declare function call<A extends unknown[], T>(x: { x: (...args: A) => T }, ...args: A): T;
|
||||
|
||||
// This should be of type `number` - ideally, it also would not error.
|
||||
const leak = call(wrap(<T>(x: T) => x), 1);
|
||||
Loading…
x
Reference in New Issue
Block a user