@@ -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