mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge pull request #7448 from Microsoft/optimizeInstantiation
Skip unnecessary instatiation of anonymous types
This commit is contained in:
+73
-26
@@ -5045,42 +5045,29 @@ namespace ts {
|
||||
return t => t === source1 ? target1 : t === source2 ? target2 : t;
|
||||
}
|
||||
|
||||
function createTypeMapper(sources: Type[], targets: Type[]): TypeMapper {
|
||||
switch (sources.length) {
|
||||
case 1: return createUnaryTypeMapper(sources[0], targets[0]);
|
||||
case 2: return createBinaryTypeMapper(sources[0], targets[0], sources[1], targets[1]);
|
||||
}
|
||||
function createArrayTypeMapper(sources: Type[], targets: Type[]): TypeMapper {
|
||||
return t => {
|
||||
for (let i = 0; i < sources.length; i++) {
|
||||
if (t === sources[i]) {
|
||||
return targets[i];
|
||||
return targets ? targets[i] : anyType;
|
||||
}
|
||||
}
|
||||
return t;
|
||||
};
|
||||
}
|
||||
|
||||
function createUnaryTypeEraser(source: Type): TypeMapper {
|
||||
return t => t === source ? anyType : t;
|
||||
}
|
||||
|
||||
function createBinaryTypeEraser(source1: Type, source2: Type): TypeMapper {
|
||||
return t => t === source1 || t === source2 ? anyType : t;
|
||||
function createTypeMapper(sources: Type[], targets: Type[]): TypeMapper {
|
||||
const count = sources.length;
|
||||
const mapper: TypeMapper =
|
||||
count == 1 ? createUnaryTypeMapper(sources[0], targets ? targets[0] : anyType) :
|
||||
count == 2 ? createBinaryTypeMapper(sources[0], targets ? targets[0] : anyType, sources[1], targets ? targets[1] : anyType) :
|
||||
createArrayTypeMapper(sources, targets);
|
||||
mapper.mappedTypes = sources;
|
||||
return mapper;
|
||||
}
|
||||
|
||||
function createTypeEraser(sources: Type[]): TypeMapper {
|
||||
switch (sources.length) {
|
||||
case 1: return createUnaryTypeEraser(sources[0]);
|
||||
case 2: return createBinaryTypeEraser(sources[0], sources[1]);
|
||||
}
|
||||
return t => {
|
||||
for (const source of sources) {
|
||||
if (t === source) {
|
||||
return anyType;
|
||||
}
|
||||
}
|
||||
return t;
|
||||
};
|
||||
return createTypeMapper(sources, undefined);
|
||||
}
|
||||
|
||||
function getInferenceMapper(context: InferenceContext): TypeMapper {
|
||||
@@ -5095,6 +5082,7 @@ namespace ts {
|
||||
}
|
||||
return t;
|
||||
};
|
||||
mapper.mappedTypes = context.typeParameters;
|
||||
mapper.context = context;
|
||||
context.mapper = mapper;
|
||||
}
|
||||
@@ -5106,7 +5094,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
function combineTypeMappers(mapper1: TypeMapper, mapper2: TypeMapper): TypeMapper {
|
||||
return t => instantiateType(mapper1(t), mapper2);
|
||||
const mapper: TypeMapper = t => instantiateType(mapper1(t), mapper2);
|
||||
mapper.mappedTypes = mapper1.mappedTypes;
|
||||
return mapper;
|
||||
}
|
||||
|
||||
function cloneTypeParameter(typeParameter: TypeParameter): TypeParameter {
|
||||
@@ -5201,13 +5191,70 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
function isSymbolInScopeOfMappedTypeParameter(symbol: Symbol, mapper: TypeMapper) {
|
||||
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.
|
||||
let node = symbol.declarations[0].parent;
|
||||
while (node) {
|
||||
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 declaration = <DeclarationWithTypeParameters>node;
|
||||
if (declaration.typeParameters) {
|
||||
for (const d of declaration.typeParameters) {
|
||||
if (contains(mappedTypes, getDeclaredTypeOfTypeParameter(d.symbol))) {
|
||||
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.ModuleDeclaration:
|
||||
case SyntaxKind.SourceFile:
|
||||
return false;
|
||||
}
|
||||
node = node.parent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function instantiateType(type: Type, mapper: TypeMapper): Type {
|
||||
if (type && mapper !== identityMapper) {
|
||||
if (type.flags & TypeFlags.TypeParameter) {
|
||||
return mapper(<TypeParameter>type);
|
||||
}
|
||||
if (type.flags & TypeFlags.Anonymous) {
|
||||
return type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) ?
|
||||
// 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) &&
|
||||
(type.flags & TypeFlags.Instantiated || isSymbolInScopeOfMappedTypeParameter(type.symbol, mapper)) ?
|
||||
instantiateAnonymousType(<AnonymousType>type, mapper) : type;
|
||||
}
|
||||
if (type.flags & TypeFlags.Reference) {
|
||||
|
||||
@@ -1208,6 +1208,8 @@ namespace ts {
|
||||
block: Block;
|
||||
}
|
||||
|
||||
export type DeclarationWithTypeParameters = SignatureDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration;
|
||||
|
||||
export interface ClassLikeDeclaration extends Declaration {
|
||||
name?: Identifier;
|
||||
typeParameters?: NodeArray<TypeParameterDeclaration>;
|
||||
@@ -2286,6 +2288,7 @@ namespace ts {
|
||||
/* @internal */
|
||||
export interface TypeMapper {
|
||||
(t: TypeParameter): Type;
|
||||
mappedTypes?: Type[]; // Types mapped by this mapper
|
||||
instantiations?: Type[]; // Cache of instantiations created using this type mapper.
|
||||
context?: InferenceContext; // The inference context this mapper was created from.
|
||||
// Only inference mappers have this set (in createInferenceMapper).
|
||||
|
||||
Reference in New Issue
Block a user