mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-11 20:37:46 -05:00
Port fixes from master into release-2.5 (#18361)
* Test: parsing of two-line @typedef jsdoc * Fix forEachChild's visit of JSDocTypedefTag Also remove JSDocTypeLiteral.jsdocTypeTag, which made no sense since it was only useful when storing information for its parent `@typedef` tag. * Update baselines * Inline variable to aid control flow * Improved caching scheme for anonymous types * Fix signature help * Optimize caching of type literals * Accept new baselines * Fix linting errors * Use canonicalized forms when comparing signatures * Minor changes * Document ThrottledOperations.schedule * Limit the number of unanswered typings installer requests If we send them all at once, we (apparently) hit a buffer limit in the node IPC channel and both TS Server and the typings installer become unresponsive. * Fix lint issues * Add explanatory comment
This commit is contained in:
@@ -4788,22 +4788,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4811,7 +4828,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,
|
||||
@@ -6614,11 +6631,30 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getErasedSignature(signature: Signature): Signature {
|
||||
if (!signature.typeParameters) return signature;
|
||||
if (!signature.erasedSignatureCache) {
|
||||
signature.erasedSignatureCache = instantiateSignature(signature, createTypeEraser(signature.typeParameters), /*eraseTypeParameters*/ true);
|
||||
}
|
||||
return signature.erasedSignatureCache;
|
||||
return signature.typeParameters ?
|
||||
signature.erasedSignatureCache || (signature.erasedSignatureCache = createErasedSignature(signature)) :
|
||||
signature;
|
||||
}
|
||||
|
||||
function createErasedSignature(signature: Signature) {
|
||||
// Create an instantiation of the signature where all type arguments are the any type.
|
||||
return instantiateSignature(signature, createTypeEraser(signature.typeParameters), /*eraseTypeParameters*/ true);
|
||||
}
|
||||
|
||||
function getCanonicalSignature(signature: Signature): Signature {
|
||||
return signature.typeParameters ?
|
||||
signature.canonicalSignatureCache || (signature.canonicalSignatureCache = createCanonicalSignature(signature)) :
|
||||
signature;
|
||||
}
|
||||
|
||||
function createCanonicalSignature(signature: Signature) {
|
||||
// Create an instantiation of the signature where each unconstrained type parameter is replaced with
|
||||
// its original. When a generic class or interface is instantiated, each generic method in the class or
|
||||
// interface is instantiated with a fresh set of cloned type parameters (which we need to handle scenarios
|
||||
// where different generations of the same type parameter are in scope). This leads to a lot of new type
|
||||
// identities, and potentially a lot of work comparing those identities, so here we create an instantiation
|
||||
// that uses the original type identities for all unconstrained type parameters.
|
||||
return getSignatureInstantiation(signature, map(signature.typeParameters, tp => tp.target && !getConstraintOfTypeParameter(tp.target) ? tp.target : tp));
|
||||
}
|
||||
|
||||
function getOrCreateTypeFromSignature(signature: Signature): ObjectType {
|
||||
@@ -6799,7 +6835,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;
|
||||
}
|
||||
@@ -8034,11 +8070,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;
|
||||
}
|
||||
@@ -8060,11 +8091,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 {
|
||||
@@ -8075,10 +8104,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 {
|
||||
@@ -8096,15 +8123,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 {
|
||||
@@ -8181,13 +8204,53 @@ 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) {
|
||||
const target = type.objectFlags & ObjectFlags.Instantiated ? type.target : type;
|
||||
const symbol = target.symbol;
|
||||
const links = getSymbolLinks(symbol);
|
||||
let typeParameters = links.typeParameters;
|
||||
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
|
||||
// aren't the right hand side of a generic type alias declaration we optimize by reducing the
|
||||
// set of type parameters to those that are actually referenced somewhere in the literal.
|
||||
const declaration = symbol.declarations[0];
|
||||
const outerTypeParameters = getOuterTypeParameters(declaration, /*includeThisTypes*/ true) || emptyArray;
|
||||
typeParameters = symbol.flags & SymbolFlags.TypeLiteral && !target.aliasTypeArguments ?
|
||||
filter(outerTypeParameters, tp => isTypeParameterReferencedWithin(tp, declaration)) :
|
||||
outerTypeParameters;
|
||||
links.typeParameters = typeParameters;
|
||||
if (typeParameters.length) {
|
||||
links.instantiations = createMap<Type>();
|
||||
links.instantiations.set(getTypeListId(typeParameters), target);
|
||||
}
|
||||
}
|
||||
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 combinedMapper = type.objectFlags & ObjectFlags.Instantiated ? combineTypeMappers(type.mapper, mapper) : mapper;
|
||||
const typeArguments = map(typeParameters, combinedMapper);
|
||||
const id = getTypeListId(typeArguments);
|
||||
let result = links.instantiations.get(id);
|
||||
if (!result) {
|
||||
const newMapper = createTypeMapper(typeParameters, typeArguments);
|
||||
result = target.objectFlags & ObjectFlags.Mapped ? instantiateMappedType(<MappedType>target, newMapper) : instantiateAnonymousType(target, newMapper);
|
||||
links.instantiations.set(id, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
function isTypeParameterReferencedWithin(tp: TypeParameter, node: Node) {
|
||||
return tp.isThisType ? forEachChild(node, checkThis) : forEachChild(node, checkIdentifier);
|
||||
function checkThis(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.ThisType || forEachChild(node, checkThis);
|
||||
}
|
||||
function checkIdentifier(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.Identifier && isPartOfTypeNode(node) && getTypeFromTypeNode(<TypeNode>node) === tp || forEachChild(node, checkIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
function instantiateMappedType(type: MappedType, mapper: TypeMapper): Type {
|
||||
@@ -8204,164 +8267,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;
|
||||
}
|
||||
@@ -8538,7 +8501,8 @@ namespace ts {
|
||||
return Ternary.False;
|
||||
}
|
||||
|
||||
if (source.typeParameters) {
|
||||
if (source.typeParameters && source.typeParameters !== target.typeParameters) {
|
||||
target = getCanonicalSignature(target);
|
||||
source = instantiateSignatureInContextOf(source, target, /*contextualMapper*/ undefined, compareTypes);
|
||||
}
|
||||
|
||||
@@ -10356,7 +10320,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;
|
||||
|
||||
@@ -438,8 +438,10 @@ namespace ts {
|
||||
visitNode(cbNode, (<JSDocTypedefTag>node).typeExpression);
|
||||
}
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
for (const tag of (node as JSDocTypeLiteral).jsDocPropertyTags) {
|
||||
visitNode(cbNode, tag);
|
||||
if ((node as JSDocTypeLiteral).jsDocPropertyTags) {
|
||||
for (const tag of (node as JSDocTypeLiteral).jsDocPropertyTags) {
|
||||
visitNode(cbNode, tag);
|
||||
}
|
||||
}
|
||||
return;
|
||||
case SyntaxKind.PartiallyEmittedExpression:
|
||||
@@ -6667,19 +6669,18 @@ namespace ts {
|
||||
if (!typeExpression || isObjectOrObjectArrayTypeReference(typeExpression.type)) {
|
||||
let child: JSDocTypeTag | JSDocPropertyTag | false;
|
||||
let jsdocTypeLiteral: JSDocTypeLiteral;
|
||||
let alreadyHasTypeTag = false;
|
||||
let childTypeTag: JSDocTypeTag;
|
||||
const start = scanner.getStartPos();
|
||||
while (child = tryParse(() => parseChildParameterOrPropertyTag(PropertyLikeParse.Property))) {
|
||||
if (!jsdocTypeLiteral) {
|
||||
jsdocTypeLiteral = <JSDocTypeLiteral>createNode(SyntaxKind.JSDocTypeLiteral, start);
|
||||
}
|
||||
if (child.kind === SyntaxKind.JSDocTypeTag) {
|
||||
if (alreadyHasTypeTag) {
|
||||
if (childTypeTag) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
jsdocTypeLiteral.jsDocTypeTag = child;
|
||||
alreadyHasTypeTag = true;
|
||||
childTypeTag = child;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -6693,7 +6694,9 @@ namespace ts {
|
||||
if (typeExpression && typeExpression.type.kind === SyntaxKind.ArrayType) {
|
||||
jsdocTypeLiteral.isArrayType = true;
|
||||
}
|
||||
typedefTag.typeExpression = finishNode(jsdocTypeLiteral);
|
||||
typedefTag.typeExpression = childTypeTag && !isObjectOrObjectArrayTypeReference(childTypeTag.typeExpression.type) ?
|
||||
childTypeTag.typeExpression :
|
||||
finishNode(jsdocTypeLiteral);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2150,7 +2150,6 @@ namespace ts {
|
||||
export interface JSDocTypeLiteral extends JSDocType {
|
||||
kind: SyntaxKind.JSDocTypeLiteral;
|
||||
jsDocPropertyTags?: ReadonlyArray<JSDocPropertyLikeTag>;
|
||||
jsDocTypeTag?: JSDocTypeTag;
|
||||
/** If true, then this type literal represents an *array* of its type. */
|
||||
isArrayType?: boolean;
|
||||
}
|
||||
@@ -3296,13 +3295,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 {
|
||||
@@ -3412,6 +3410,8 @@ namespace ts {
|
||||
/* @internal */
|
||||
erasedSignatureCache?: Signature; // Erased version of signature (deferred)
|
||||
/* @internal */
|
||||
canonicalSignatureCache?: Signature; // Canonical version of signature (deferred)
|
||||
/* @internal */
|
||||
isolatedSignatureType?: ObjectType; // A manufactured type that just contains the signature for purposes of signature comparison
|
||||
/* @internal */
|
||||
typePredicate?: TypePredicate;
|
||||
@@ -3433,8 +3433,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 {
|
||||
|
||||
@@ -235,24 +235,39 @@ namespace ts.server {
|
||||
return `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}.${d.getMilliseconds()}`;
|
||||
}
|
||||
|
||||
interface QueuedOperation {
|
||||
operationId: string;
|
||||
operation: () => void;
|
||||
}
|
||||
|
||||
class NodeTypingsInstaller implements ITypingsInstaller {
|
||||
private installer: NodeChildProcess;
|
||||
private installerPidReported = false;
|
||||
private socket: NodeSocket;
|
||||
private projectService: ProjectService;
|
||||
private throttledOperations: ThrottledOperations;
|
||||
private eventSender: EventSender;
|
||||
private activeRequestCount = 0;
|
||||
private requestQueue: QueuedOperation[] = [];
|
||||
private requestMap = createMap<QueuedOperation>(); // Maps operation ID to newest requestQueue entry with that ID
|
||||
|
||||
// This number is essentially arbitrary. Processing more than one typings request
|
||||
// at a time makes sense, but having too many in the pipe results in a hang
|
||||
// (see https://github.com/nodejs/node/issues/7657).
|
||||
// It would be preferable to base our limit on the amount of space left in the
|
||||
// buffer, but we have yet to find a way to retrieve that value.
|
||||
private static readonly maxActiveRequestCount = 10;
|
||||
private static readonly requestDelayMillis = 100;
|
||||
|
||||
|
||||
constructor(
|
||||
private readonly telemetryEnabled: boolean,
|
||||
private readonly logger: server.Logger,
|
||||
host: ServerHost,
|
||||
private readonly host: ServerHost,
|
||||
eventPort: number,
|
||||
readonly globalTypingsCacheLocation: string,
|
||||
readonly typingSafeListLocation: string,
|
||||
private readonly npmLocation: string | undefined,
|
||||
private newLine: string) {
|
||||
this.throttledOperations = new ThrottledOperations(host);
|
||||
if (eventPort) {
|
||||
const s = net.connect({ port: eventPort }, () => {
|
||||
this.socket = s;
|
||||
@@ -333,12 +348,26 @@ namespace ts.server {
|
||||
this.logger.info(`Scheduling throttled operation: ${JSON.stringify(request)}`);
|
||||
}
|
||||
}
|
||||
this.throttledOperations.schedule(project.getProjectName(), /*ms*/ 250, () => {
|
||||
|
||||
const operationId = project.getProjectName();
|
||||
const operation = () => {
|
||||
if (this.logger.hasLevel(LogLevel.verbose)) {
|
||||
this.logger.info(`Sending request: ${JSON.stringify(request)}`);
|
||||
}
|
||||
this.installer.send(request);
|
||||
});
|
||||
};
|
||||
const queuedRequest: QueuedOperation = { operationId, operation };
|
||||
|
||||
if (this.activeRequestCount < NodeTypingsInstaller.maxActiveRequestCount) {
|
||||
this.scheduleRequest(queuedRequest);
|
||||
}
|
||||
else {
|
||||
if (this.logger.hasLevel(LogLevel.verbose)) {
|
||||
this.logger.info(`Deferring request for: ${operationId}`);
|
||||
}
|
||||
this.requestQueue.push(queuedRequest);
|
||||
this.requestMap.set(operationId, queuedRequest);
|
||||
}
|
||||
}
|
||||
|
||||
private handleMessage(response: SetTypings | InvalidateCachedTypings | BeginInstallTypes | EndInstallTypes | InitializationFailedResponse) {
|
||||
@@ -399,11 +428,39 @@ namespace ts.server {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.activeRequestCount > 0) {
|
||||
this.activeRequestCount--;
|
||||
}
|
||||
else {
|
||||
Debug.fail("Received too many responses");
|
||||
}
|
||||
|
||||
while (this.requestQueue.length > 0) {
|
||||
const queuedRequest = this.requestQueue.shift();
|
||||
if (this.requestMap.get(queuedRequest.operationId) === queuedRequest) {
|
||||
this.requestMap.delete(queuedRequest.operationId);
|
||||
this.scheduleRequest(queuedRequest);
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.logger.hasLevel(LogLevel.verbose)) {
|
||||
this.logger.info(`Skipping defunct request for: ${queuedRequest.operationId}`);
|
||||
}
|
||||
}
|
||||
|
||||
this.projectService.updateTypingsForProject(response);
|
||||
if (response.kind === ActionSet && this.socket) {
|
||||
this.sendEvent(0, "setTypings", response);
|
||||
}
|
||||
}
|
||||
|
||||
private scheduleRequest(request: QueuedOperation) {
|
||||
if (this.logger.hasLevel(LogLevel.verbose)) {
|
||||
this.logger.info(`Scheduling request for: ${request.operationId}`);
|
||||
}
|
||||
this.activeRequestCount++;
|
||||
this.host.setTimeout(request.operation, NodeTypingsInstaller.requestDelayMillis);
|
||||
}
|
||||
}
|
||||
|
||||
class IOSession extends Session {
|
||||
|
||||
@@ -179,6 +179,12 @@ namespace ts.server {
|
||||
constructor(private readonly host: ServerHost) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait `number` milliseconds and then invoke `cb`. If, while waiting, schedule
|
||||
* is called again with the same `operationId`, cancel this operation in favor
|
||||
* of the new one. (Note that the amount of time the canceled operation had been
|
||||
* waiting does not affect the amount of time that the new operation waits.)
|
||||
*/
|
||||
public schedule(operationId: string, delay: number, cb: () => void) {
|
||||
const pendingTimeout = this.pendingTimeouts.get(operationId);
|
||||
if (pendingTimeout) {
|
||||
|
||||
@@ -372,8 +372,7 @@ namespace ts.SignatureHelp {
|
||||
if (isTypeParameterList) {
|
||||
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.target || candidateSignature).typeParameters;
|
||||
signatureHelpParameters = typeParameters && typeParameters.length > 0 ? map(typeParameters, createSignatureHelpParameterForTypeParameter) : emptyArray;
|
||||
suffixDisplayParts.push(punctuationPart(SyntaxKind.GreaterThanToken));
|
||||
const parameterParts = mapToDisplayParts(writer =>
|
||||
|
||||
Reference in New Issue
Block a user