@@ -8179,40 +8179,54 @@ namespace ts {
8179
8179
}
8180
8180
8181
8181
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;
8187
8184
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) {
8194
8198
links.instantiations = createMap<Type>();
8195
- links.instantiations.set(getTypeListId(typeParameters), type );
8199
+ links.instantiations.set(getTypeListId(typeParameters), target );
8196
8200
}
8197
8201
}
8198
- const typeParameters = links.typeParameters;
8199
8202
if (typeParameters.length) {
8200
8203
// We are instantiating an anonymous type that has one or more type parameters in scope. Apply the
8201
8204
// mapper to the type parameters to produce the effective list of type arguments, and compute the
8202
8205
// 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);
8204
8208
const id = getTypeListId(typeArguments);
8205
8209
let result = links.instantiations.get(id);
8206
8210
if (!result) {
8207
8211
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);
8209
8213
links.instantiations.set(id, result);
8210
8214
}
8211
8215
return result;
8212
8216
}
8213
8217
return type;
8214
8218
}
8215
8219
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
+
8216
8230
function instantiateMappedType(type: MappedType, mapper: TypeMapper): Type {
8217
8231
// Check if we have a homomorphic mapped type, i.e. a type of the form { [P in keyof T]: X } for some
8218
8232
// 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 {
10420
10434
function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority: InferencePriority = 0) {
10421
10435
let symbolStack: Symbol[];
10422
10436
let visited: Map<boolean>;
10437
+ //sys.write(typeToString(originalSource) + " ==> " + typeToString(originalTarget) + "\n");
10423
10438
inferFromTypes(originalSource, originalTarget);
10424
10439
10425
10440
function inferFromTypes(source: Type, target: Type) {
@@ -10487,6 +10502,7 @@ namespace ts {
10487
10502
const inference = getInferenceInfoForType(target);
10488
10503
if (inference) {
10489
10504
if (!inference.isFixed) {
10505
+ //sys.write(" " + typeToString(source) + "\n");
10490
10506
if (!inference.candidates || priority < inference.priority) {
10491
10507
inference.candidates = [source];
10492
10508
inference.priority = priority;
0 commit comments