mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-06 20:14:01 -06:00
Improved caching scheme for anonymous types
This commit is contained in:
parent
c7b4ed3a91
commit
b65ff647c1
@ -4794,22 +4794,39 @@ namespace ts {
|
||||
return typeParameters;
|
||||
}
|
||||
|
||||
// Appends the outer type parameters of a node to a set of type parameters and returns the resulting set. The function
|
||||
// allocates a new array if the input type parameter set is undefined, but otherwise it modifies the set in-place and
|
||||
// returns the same array.
|
||||
function appendOuterTypeParameters(typeParameters: TypeParameter[], node: Node): TypeParameter[] {
|
||||
// Return the outer type parameters of a node or undefined if the node has no outer type parameters.
|
||||
function getOuterTypeParameters(node: Node, includeThisTypes?: boolean): TypeParameter[] {
|
||||
while (true) {
|
||||
node = node.parent;
|
||||
if (!node) {
|
||||
return typeParameters;
|
||||
return undefined;
|
||||
}
|
||||
if (node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression ||
|
||||
node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression ||
|
||||
node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.ArrowFunction) {
|
||||
const declarations = (<ClassLikeDeclaration | FunctionLikeDeclaration>node).typeParameters;
|
||||
if (declarations) {
|
||||
return appendTypeParameters(appendOuterTypeParameters(typeParameters, node), declarations);
|
||||
}
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.ClassExpression:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.JSDocFunctionType:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.JSDocTemplateTag:
|
||||
case SyntaxKind.MappedType:
|
||||
const outerTypeParameters = getOuterTypeParameters(node, includeThisTypes);
|
||||
if (node.kind === SyntaxKind.MappedType) {
|
||||
return append(outerTypeParameters, getDeclaredTypeOfTypeParameter(getSymbolOfNode((<MappedTypeNode>node).typeParameter)));
|
||||
}
|
||||
const outerAndOwnTypeParameters = appendTypeParameters(outerTypeParameters, getEffectiveTypeParameterDeclarations(<DeclarationWithTypeParameters>node) || emptyArray);
|
||||
const thisType = includeThisTypes &&
|
||||
(node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression || node.kind === SyntaxKind.InterfaceDeclaration) &&
|
||||
getDeclaredTypeOfClassOrInterface(getSymbolOfNode(node)).thisType;
|
||||
return thisType ? append(outerAndOwnTypeParameters, thisType) : outerAndOwnTypeParameters;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4817,7 +4834,7 @@ namespace ts {
|
||||
// The outer type parameters are those defined by enclosing generic classes, methods, or functions.
|
||||
function getOuterTypeParametersOfClassOrInterface(symbol: Symbol): TypeParameter[] {
|
||||
const declaration = symbol.flags & SymbolFlags.Class ? symbol.valueDeclaration : getDeclarationOfKind(symbol, SyntaxKind.InterfaceDeclaration);
|
||||
return appendOuterTypeParameters(/*typeParameters*/ undefined, declaration);
|
||||
return getOuterTypeParameters(declaration);
|
||||
}
|
||||
|
||||
// The local type parameters are the combined set of type parameters from all declarations of the class,
|
||||
@ -6800,7 +6817,7 @@ namespace ts {
|
||||
const id = getTypeListId(typeArguments);
|
||||
let instantiation = links.instantiations.get(id);
|
||||
if (!instantiation) {
|
||||
links.instantiations.set(id, instantiation = instantiateTypeNoAlias(type, createTypeMapper(typeParameters, fillMissingTypeArguments(typeArguments, typeParameters, getMinTypeArgumentCount(typeParameters)))));
|
||||
links.instantiations.set(id, instantiation = instantiateType(type, createTypeMapper(typeParameters, fillMissingTypeArguments(typeArguments, typeParameters, getMinTypeArgumentCount(typeParameters)))));
|
||||
}
|
||||
return instantiation;
|
||||
}
|
||||
@ -8024,11 +8041,6 @@ namespace ts {
|
||||
return instantiateList(signatures, mapper, instantiateSignature);
|
||||
}
|
||||
|
||||
function instantiateCached<T extends Type>(type: T, mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): T {
|
||||
const instantiations = mapper.instantiations || (mapper.instantiations = []);
|
||||
return <T>instantiations[type.id] || (instantiations[type.id] = instantiator(type, mapper));
|
||||
}
|
||||
|
||||
function makeUnaryTypeMapper(source: Type, target: Type) {
|
||||
return (t: Type) => t === source ? target : t;
|
||||
}
|
||||
@ -8050,11 +8062,9 @@ namespace ts {
|
||||
|
||||
function createTypeMapper(sources: TypeParameter[], targets: Type[]): TypeMapper {
|
||||
Debug.assert(targets === undefined || sources.length === targets.length);
|
||||
const mapper: TypeMapper = sources.length === 1 ? makeUnaryTypeMapper(sources[0], targets ? targets[0] : anyType) :
|
||||
return sources.length === 1 ? makeUnaryTypeMapper(sources[0], targets ? targets[0] : anyType) :
|
||||
sources.length === 2 ? makeBinaryTypeMapper(sources[0], targets ? targets[0] : anyType, sources[1], targets ? targets[1] : anyType) :
|
||||
makeArrayTypeMapper(sources, targets);
|
||||
mapper.mappedTypes = sources;
|
||||
return mapper;
|
||||
makeArrayTypeMapper(sources, targets);
|
||||
}
|
||||
|
||||
function createTypeEraser(sources: TypeParameter[]): TypeMapper {
|
||||
@ -8065,10 +8075,8 @@ namespace ts {
|
||||
* Maps forward-references to later types parameters to the empty object type.
|
||||
* This is used during inference when instantiating type parameter defaults.
|
||||
*/
|
||||
function createBackreferenceMapper(typeParameters: TypeParameter[], index: number) {
|
||||
const mapper: TypeMapper = t => indexOf(typeParameters, t) >= index ? emptyObjectType : t;
|
||||
mapper.mappedTypes = typeParameters;
|
||||
return mapper;
|
||||
function createBackreferenceMapper(typeParameters: TypeParameter[], index: number): TypeMapper {
|
||||
return t => indexOf(typeParameters, t) >= index ? emptyObjectType : t;
|
||||
}
|
||||
|
||||
function isInferenceContext(mapper: TypeMapper): mapper is InferenceContext {
|
||||
@ -8086,15 +8094,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
function combineTypeMappers(mapper1: TypeMapper, mapper2: TypeMapper): TypeMapper {
|
||||
const mapper: TypeMapper = t => instantiateType(mapper1(t), mapper2);
|
||||
mapper.mappedTypes = concatenate(mapper1.mappedTypes, mapper2.mappedTypes);
|
||||
return mapper;
|
||||
return t => instantiateType(mapper1(t), mapper2);
|
||||
}
|
||||
|
||||
function createReplacementMapper(source: Type, target: Type, baseMapper: TypeMapper) {
|
||||
const mapper: TypeMapper = t => t === source ? target : baseMapper(t);
|
||||
mapper.mappedTypes = baseMapper.mappedTypes;
|
||||
return mapper;
|
||||
function createReplacementMapper(source: Type, target: Type, baseMapper: TypeMapper): TypeMapper {
|
||||
return t => t === source ? target : baseMapper(t);
|
||||
}
|
||||
|
||||
function cloneTypeParameter(typeParameter: TypeParameter): TypeParameter {
|
||||
@ -8174,13 +8178,39 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
function instantiateAnonymousType(type: AnonymousType, mapper: TypeMapper): AnonymousType {
|
||||
const result = <AnonymousType>createObjectType(ObjectFlags.Anonymous | ObjectFlags.Instantiated, type.symbol);
|
||||
result.target = type.objectFlags & ObjectFlags.Instantiated ? type.target : type;
|
||||
result.mapper = type.objectFlags & ObjectFlags.Instantiated ? combineTypeMappers(type.mapper, mapper) : mapper;
|
||||
result.aliasSymbol = type.aliasSymbol;
|
||||
result.aliasTypeArguments = instantiateTypes(type.aliasTypeArguments, mapper);
|
||||
return result;
|
||||
function getAnonymousTypeInstantiation(type: AnonymousType, mapper: TypeMapper) {
|
||||
if (type.objectFlags & ObjectFlags.Instantiated) {
|
||||
mapper = combineTypeMappers(type.mapper, mapper);
|
||||
type = type.target;
|
||||
}
|
||||
const symbol = type.symbol;
|
||||
const links = getSymbolLinks(symbol);
|
||||
if (!links.typeParameters) {
|
||||
// This 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).
|
||||
const typeParameters = getOuterTypeParameters(symbol.declarations[0], /*includeThisTypes*/ true);
|
||||
links.typeParameters = typeParameters || emptyArray;
|
||||
if (typeParameters) {
|
||||
links.instantiations = createMap<Type>();
|
||||
links.instantiations.set(getTypeListId(typeParameters), type);
|
||||
}
|
||||
}
|
||||
const typeParameters = links.typeParameters;
|
||||
if (typeParameters.length) {
|
||||
// We are instantiating an anonymous type that has one or more type parameters in scope. Apply the
|
||||
// mapper to the type parameters to produce the effective list of type arguments, and compute the
|
||||
// instantiation cache key from the type IDs of the type arguments.
|
||||
const typeArguments = map(typeParameters, mapper);
|
||||
const id = getTypeListId(typeArguments);
|
||||
let result = links.instantiations.get(id);
|
||||
if (!result) {
|
||||
const newMapper = createTypeMapper(typeParameters, typeArguments);
|
||||
result = type.objectFlags & ObjectFlags.Mapped ? instantiateMappedType(<MappedType>type, newMapper) : instantiateAnonymousType(type, newMapper);
|
||||
links.instantiations.set(id, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
function instantiateMappedType(type: MappedType, mapper: TypeMapper): Type {
|
||||
@ -8197,164 +8227,64 @@ namespace ts {
|
||||
if (typeVariable !== mappedTypeVariable) {
|
||||
return mapType(mappedTypeVariable, t => {
|
||||
if (isMappableType(t)) {
|
||||
return instantiateMappedObjectType(type, createReplacementMapper(typeVariable, t, mapper));
|
||||
return instantiateAnonymousType(type, createReplacementMapper(typeVariable, t, mapper));
|
||||
}
|
||||
return t;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return instantiateMappedObjectType(type, mapper);
|
||||
return instantiateAnonymousType(type, mapper);
|
||||
}
|
||||
|
||||
function isMappableType(type: Type) {
|
||||
return type.flags & (TypeFlags.TypeParameter | TypeFlags.Object | TypeFlags.Intersection | TypeFlags.IndexedAccess);
|
||||
}
|
||||
|
||||
function instantiateMappedObjectType(type: MappedType, mapper: TypeMapper): Type {
|
||||
const result = <MappedType>createObjectType(ObjectFlags.Mapped | ObjectFlags.Instantiated, type.symbol);
|
||||
result.declaration = type.declaration;
|
||||
result.mapper = type.mapper ? combineTypeMappers(type.mapper, mapper) : mapper;
|
||||
function instantiateAnonymousType(type: AnonymousType, mapper: TypeMapper): AnonymousType {
|
||||
const result = <AnonymousType>createObjectType(type.objectFlags | ObjectFlags.Instantiated, type.symbol);
|
||||
if (type.objectFlags & ObjectFlags.Mapped) {
|
||||
(<MappedType>result).declaration = (<MappedType>type).declaration;
|
||||
}
|
||||
result.target = type;
|
||||
result.mapper = mapper;
|
||||
result.aliasSymbol = type.aliasSymbol;
|
||||
result.aliasTypeArguments = instantiateTypes(type.aliasTypeArguments, mapper);
|
||||
return result;
|
||||
}
|
||||
|
||||
function isSymbolInScopeOfMappedTypeParameter(symbol: Symbol, mapper: TypeMapper) {
|
||||
if (!(symbol.declarations && symbol.declarations.length)) {
|
||||
return false;
|
||||
}
|
||||
const mappedTypes = mapper.mappedTypes;
|
||||
// Starting with the parent of the symbol's declaration, check if the mapper maps any of
|
||||
// the type parameters introduced by enclosing declarations. We just pick the first
|
||||
// declaration since multiple declarations will all have the same parent anyway.
|
||||
return !!findAncestor(symbol.declarations[0], node => {
|
||||
if (node.kind === SyntaxKind.ModuleDeclaration || node.kind === SyntaxKind.SourceFile) {
|
||||
return "quit";
|
||||
}
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
case SyntaxKind.IndexSignature:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.ClassExpression:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
const typeParameters = getEffectiveTypeParameterDeclarations(node as DeclarationWithTypeParameters);
|
||||
if (typeParameters) {
|
||||
for (const d of typeParameters) {
|
||||
if (contains(mappedTypes, getDeclaredTypeOfTypeParameter(getSymbolOfNode(d)))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isClassLike(node) || node.kind === SyntaxKind.InterfaceDeclaration) {
|
||||
const thisType = getDeclaredTypeOfClassOrInterface(getSymbolOfNode(node)).thisType;
|
||||
if (thisType && contains(mappedTypes, thisType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.MappedType:
|
||||
if (contains(mappedTypes, getDeclaredTypeOfTypeParameter(getSymbolOfNode((<MappedTypeNode>node).typeParameter)))) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.JSDocFunctionType:
|
||||
const func = node as JSDocFunctionType;
|
||||
for (const p of func.parameters) {
|
||||
if (contains(mappedTypes, getTypeOfNode(p))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function isTopLevelTypeAlias(symbol: Symbol) {
|
||||
if (symbol.declarations && symbol.declarations.length) {
|
||||
const parentKind = symbol.declarations[0].parent.kind;
|
||||
return parentKind === SyntaxKind.SourceFile || parentKind === SyntaxKind.ModuleBlock;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function instantiateType(type: Type, mapper: TypeMapper): Type {
|
||||
if (type && mapper !== identityMapper) {
|
||||
// If we are instantiating a type that has a top-level type alias, obtain the instantiation through
|
||||
// the type alias instead in order to share instantiations for the same type arguments. This can
|
||||
// dramatically reduce the number of structurally identical types we generate. Note that we can only
|
||||
// perform this optimization for top-level type aliases. Consider:
|
||||
//
|
||||
// function f1<T>(x: T) {
|
||||
// type Foo<X> = { x: X, t: T };
|
||||
// let obj: Foo<T> = { x: x };
|
||||
// return obj;
|
||||
// }
|
||||
// function f2<U>(x: U) { return f1(x); }
|
||||
// let z = f2(42);
|
||||
//
|
||||
// Above, the declaration of f2 has an inferred return type that is an instantiation of f1's Foo<X>
|
||||
// equivalent to { x: U, t: U }. When instantiating this return type, we can't go back to Foo<X>'s
|
||||
// cache because all cached instantiations are of the form { x: ???, t: T }, i.e. they have not been
|
||||
// instantiated for T. Instead, we need to further instantiate the { x: U, t: U } form.
|
||||
if (type.aliasSymbol && isTopLevelTypeAlias(type.aliasSymbol)) {
|
||||
if (type.aliasTypeArguments) {
|
||||
return getTypeAliasInstantiation(type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper));
|
||||
if (type.flags & TypeFlags.TypeParameter) {
|
||||
return mapper(<TypeParameter>type);
|
||||
}
|
||||
if (type.flags & TypeFlags.Object) {
|
||||
if ((<ObjectType>type).objectFlags & ObjectFlags.Anonymous) {
|
||||
// If the anonymous type originates in a declaration of a function, method, class, or
|
||||
// interface, in an object type literal, or in an object literal expression, we may need
|
||||
// to instantiate the type because it might reference a type parameter.
|
||||
return type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations ?
|
||||
getAnonymousTypeInstantiation(<AnonymousType>type, mapper) : type;
|
||||
}
|
||||
if ((<ObjectType>type).objectFlags & ObjectFlags.Mapped) {
|
||||
return getAnonymousTypeInstantiation(<MappedType>type, mapper);
|
||||
}
|
||||
if ((<ObjectType>type).objectFlags & ObjectFlags.Reference) {
|
||||
return createTypeReference((<TypeReference>type).target, instantiateTypes((<TypeReference>type).typeArguments, mapper));
|
||||
}
|
||||
return type;
|
||||
}
|
||||
return instantiateTypeNoAlias(type, mapper);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
function instantiateTypeNoAlias(type: Type, mapper: TypeMapper): Type {
|
||||
if (type.flags & TypeFlags.TypeParameter) {
|
||||
return mapper(<TypeParameter>type);
|
||||
}
|
||||
if (type.flags & TypeFlags.Object) {
|
||||
if ((<ObjectType>type).objectFlags & ObjectFlags.Anonymous) {
|
||||
// If the anonymous type originates in a declaration of a function, method, class, or
|
||||
// interface, in an object type literal, or in an object literal expression, we may need
|
||||
// to instantiate the type because it might reference a type parameter. We skip instantiation
|
||||
// if none of the type parameters that are in scope in the type's declaration are mapped by
|
||||
// the given mapper, however we can only do that analysis if the type isn't itself an
|
||||
// instantiation.
|
||||
return type.symbol &&
|
||||
type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) &&
|
||||
((<ObjectType>type).objectFlags & ObjectFlags.Instantiated || isSymbolInScopeOfMappedTypeParameter(type.symbol, mapper)) ?
|
||||
instantiateCached(type, mapper, instantiateAnonymousType) : type;
|
||||
if (type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Primitive)) {
|
||||
return getUnionType(instantiateTypes((<UnionType>type).types, mapper), /*subtypeReduction*/ false, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper));
|
||||
}
|
||||
if ((<ObjectType>type).objectFlags & ObjectFlags.Mapped) {
|
||||
return instantiateCached(type, mapper, instantiateMappedType);
|
||||
if (type.flags & TypeFlags.Intersection) {
|
||||
return getIntersectionType(instantiateTypes((<IntersectionType>type).types, mapper), type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper));
|
||||
}
|
||||
if ((<ObjectType>type).objectFlags & ObjectFlags.Reference) {
|
||||
return createTypeReference((<TypeReference>type).target, instantiateTypes((<TypeReference>type).typeArguments, mapper));
|
||||
if (type.flags & TypeFlags.Index) {
|
||||
return getIndexType(instantiateType((<IndexType>type).type, mapper));
|
||||
}
|
||||
if (type.flags & TypeFlags.IndexedAccess) {
|
||||
return getIndexedAccessType(instantiateType((<IndexedAccessType>type).objectType, mapper), instantiateType((<IndexedAccessType>type).indexType, mapper));
|
||||
}
|
||||
}
|
||||
if (type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Primitive)) {
|
||||
return getUnionType(instantiateTypes((<UnionType>type).types, mapper), /*subtypeReduction*/ false, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper));
|
||||
}
|
||||
if (type.flags & TypeFlags.Intersection) {
|
||||
return getIntersectionType(instantiateTypes((<IntersectionType>type).types, mapper), type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper));
|
||||
}
|
||||
if (type.flags & TypeFlags.Index) {
|
||||
return getIndexType(instantiateType((<IndexType>type).type, mapper));
|
||||
}
|
||||
if (type.flags & TypeFlags.IndexedAccess) {
|
||||
return getIndexedAccessType(instantiateType((<IndexedAccessType>type).objectType, mapper), instantiateType((<IndexedAccessType>type).indexType, mapper));
|
||||
}
|
||||
return type;
|
||||
}
|
||||
@ -10368,7 +10298,6 @@ namespace ts {
|
||||
function createInferenceContext(signature: Signature, flags: InferenceFlags, compareTypes?: TypeComparer, baseInferences?: InferenceInfo[]): InferenceContext {
|
||||
const inferences = baseInferences ? map(baseInferences, cloneInferenceInfo) : map(signature.typeParameters, createInferenceInfo);
|
||||
const context = mapper as InferenceContext;
|
||||
context.mappedTypes = signature.typeParameters;
|
||||
context.signature = signature;
|
||||
context.inferences = inferences;
|
||||
context.flags = flags;
|
||||
|
||||
@ -3331,13 +3331,12 @@ namespace ts {
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface MappedType extends ObjectType {
|
||||
export interface MappedType extends AnonymousType {
|
||||
declaration: MappedTypeNode;
|
||||
typeParameter?: TypeParameter;
|
||||
constraintType?: Type;
|
||||
templateType?: Type;
|
||||
modifiersType?: Type;
|
||||
mapper?: TypeMapper; // Instantiation mapper
|
||||
}
|
||||
|
||||
export interface EvolvingArrayType extends ObjectType {
|
||||
@ -3469,8 +3468,6 @@ namespace ts {
|
||||
/* @internal */
|
||||
export interface TypeMapper {
|
||||
(t: TypeParameter): Type;
|
||||
mappedTypes?: TypeParameter[]; // Types mapped by this mapper
|
||||
instantiations?: Type[]; // Cache of instantiations created using this type mapper.
|
||||
}
|
||||
|
||||
export const enum InferencePriority {
|
||||
|
||||
@ -373,7 +373,7 @@ namespace ts.SignatureHelp {
|
||||
isVariadic = false; // type parameter lists are not variadic
|
||||
prefixDisplayParts.push(punctuationPart(SyntaxKind.LessThanToken));
|
||||
// Use `.mapper` to ensure we get the generic type arguments even if this is an instantiated version of the signature.
|
||||
const typeParameters = candidateSignature.mapper ? candidateSignature.mapper.mappedTypes : candidateSignature.typeParameters;
|
||||
const typeParameters = candidateSignature.typeParameters; // !!! candidateSignature.mapper ? candidateSignature.mapper.mappedTypes : candidateSignature.typeParameters;
|
||||
signatureHelpParameters = typeParameters && typeParameters.length > 0 ? map(typeParameters, createSignatureHelpParameterForTypeParameter) : emptyArray;
|
||||
suffixDisplayParts.push(punctuationPart(SyntaxKind.GreaterThanToken));
|
||||
const parameterParts = mapToDisplayParts(writer =>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user