Skip to content

Commit 319617c

Browse files
committed
Optimize caching of type literals
1 parent 601a21c commit 319617c

File tree

1 file changed

+31
-15
lines changed

1 file changed

+31
-15
lines changed

src/compiler/checker.ts

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8179,40 +8179,54 @@ namespace ts {
81798179
}
81808180

81818181
function getAnonymousTypeInstantiation(type: AnonymousType, mapper: TypeMapper) {
8182-
if (type.objectFlags & ObjectFlags.Instantiated) {
8183-
mapper = combineTypeMappers(type.mapper, mapper);
8184-
type = type.target;
8185-
}
8186-
const symbol = type.symbol;
8182+
const target = type.objectFlags & ObjectFlags.Instantiated ? type.target : type;
8183+
const symbol = target.symbol;
81878184
const links = getSymbolLinks(symbol);
8188-
if (!links.typeParameters) {
8189-
// This first time an anonymous type is instantiated we compute and store a list of the type
8190-
// parameters that are in scope (and therefore potentially referenced).
8191-
const typeParameters = getOuterTypeParameters(symbol.declarations[0], /*includeThisTypes*/ true);
8192-
links.typeParameters = typeParameters || emptyArray;
8193-
if (typeParameters) {
8185+
let typeParameters = links.typeParameters;
8186+
if (!typeParameters) {
8187+
// The first time an anonymous type is instantiated we compute and store a list of the type
8188+
// parameters that are in scope (and therefore potentially referenced). For type literals that
8189+
// aren't the right hand side of a generic type alias declaration we optimize by reducing the
8190+
// set of type parameters to those that are actually referenced somewhere in the literal.
8191+
const declaration = symbol.declarations[0];
8192+
const outerTypeParameters = getOuterTypeParameters(declaration, /*includeThisTypes*/ true) || emptyArray;
8193+
typeParameters = symbol.flags & SymbolFlags.TypeLiteral && !target.aliasTypeArguments ?
8194+
filter(outerTypeParameters, tp => isTypeParameterReferencedWithin(tp, declaration)) :
8195+
outerTypeParameters;
8196+
links.typeParameters = typeParameters;
8197+
if (typeParameters.length) {
81948198
links.instantiations = createMap<Type>();
8195-
links.instantiations.set(getTypeListId(typeParameters), type);
8199+
links.instantiations.set(getTypeListId(typeParameters), target);
81968200
}
81978201
}
8198-
const typeParameters = links.typeParameters;
81998202
if (typeParameters.length) {
82008203
// We are instantiating an anonymous type that has one or more type parameters in scope. Apply the
82018204
// mapper to the type parameters to produce the effective list of type arguments, and compute the
82028205
// instantiation cache key from the type IDs of the type arguments.
8203-
const typeArguments = map(typeParameters, mapper);
8206+
const combinedMapper = type.objectFlags & ObjectFlags.Instantiated ? combineTypeMappers(type.mapper, mapper) : mapper;
8207+
const typeArguments = map(typeParameters, combinedMapper);
82048208
const id = getTypeListId(typeArguments);
82058209
let result = links.instantiations.get(id);
82068210
if (!result) {
82078211
const newMapper = createTypeMapper(typeParameters, typeArguments);
8208-
result = type.objectFlags & ObjectFlags.Mapped ? instantiateMappedType(<MappedType>type, newMapper) : instantiateAnonymousType(type, newMapper);
8212+
result = target.objectFlags & ObjectFlags.Mapped ? instantiateMappedType(<MappedType>target, newMapper) : instantiateAnonymousType(target, newMapper);
82098213
links.instantiations.set(id, result);
82108214
}
82118215
return result;
82128216
}
82138217
return type;
82148218
}
82158219

8220+
function isTypeParameterReferencedWithin(tp: TypeParameter, node: Node) {
8221+
return tp.isThisType ? forEachChild(node, checkThis) : forEachChild(node, checkIdentifier);
8222+
function checkThis(node: Node): boolean {
8223+
return node.kind === SyntaxKind.ThisType || forEachChild(node, checkThis);
8224+
}
8225+
function checkIdentifier(node: Node): boolean {
8226+
return node.kind === SyntaxKind.Identifier && isPartOfTypeNode(node) && getTypeFromTypeNode(<TypeNode>node) === tp || forEachChild(node, checkIdentifier);
8227+
}
8228+
}
8229+
82168230
function instantiateMappedType(type: MappedType, mapper: TypeMapper): Type {
82178231
// Check if we have a homomorphic mapped type, i.e. a type of the form { [P in keyof T]: X } for some
82188232
// type variable T. If so, the mapped type is distributive over a union type and when T is instantiated
@@ -10420,6 +10434,7 @@ namespace ts {
1042010434
function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority: InferencePriority = 0) {
1042110435
let symbolStack: Symbol[];
1042210436
let visited: Map<boolean>;
10437+
//sys.write(typeToString(originalSource) + " ==> " + typeToString(originalTarget) + "\n");
1042310438
inferFromTypes(originalSource, originalTarget);
1042410439

1042510440
function inferFromTypes(source: Type, target: Type) {
@@ -10487,6 +10502,7 @@ namespace ts {
1048710502
const inference = getInferenceInfoForType(target);
1048810503
if (inference) {
1048910504
if (!inference.isFixed) {
10505+
//sys.write(" " + typeToString(source) + "\n");
1049010506
if (!inference.candidates || priority < inference.priority) {
1049110507
inference.candidates = [source];
1049210508
inference.priority = priority;

0 commit comments

Comments
 (0)