Skip to content

Commit 52a1a14

Browse files
committed
Instantiate deferred type references like anonymous types
1 parent b24fcd0 commit 52a1a14

File tree

2 files changed

+34
-25
lines changed

2 files changed

+34
-25
lines changed

src/compiler/checker.ts

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9077,10 +9077,10 @@ namespace ts {
90779077
return type;
90789078
}
90799079

9080-
function createDeferredTypeReference(target: GenericType, typeArgumentNodes: ReadonlyArray<TypeNode>, mapper?: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: ReadonlyArray<Type>): TypeReference {
9081-
const type = <TypeReference>createObjectType(ObjectFlags.Reference, target.symbol);
9080+
function createDeferredTypeReference(target: GenericType, node: ArrayTypeNode | TupleTypeNode, mapper?: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: ReadonlyArray<Type>): DeferredTypeReference {
9081+
const type = <DeferredTypeReference>createObjectType(ObjectFlags.Reference, target.symbol);
90829082
type.target = target;
9083-
type.typeArgumentNodes = typeArgumentNodes;
9083+
type.node = node;
90849084
type.mapper = mapper;
90859085
type.aliasSymbol = aliasSymbol;
90869086
type.aliasTypeArguments = aliasTypeArguments;
@@ -9089,7 +9089,7 @@ namespace ts {
90899089

90909090
function getTypeArguments(type: TypeReference): ReadonlyArray<Type> {
90919091
if (!type.resolvedTypeArguments) {
9092-
const typeArguments = type.typeArgumentNodes ? map(type.typeArgumentNodes, getTypeFromTypeNode) : emptyArray;
9092+
const typeArguments = type.node ? map(type.node.kind === SyntaxKind.ArrayType ? [type.node.elementType] : type.node.elementTypes, getTypeFromTypeNode) : emptyArray;
90939093
type.resolvedTypeArguments = type.mapper ? instantiateTypes(typeArguments, type.mapper) : typeArguments;
90949094
}
90959095
return type.resolvedTypeArguments;
@@ -9598,8 +9598,8 @@ namespace ts {
95989598
const target = getArrayOrTupleTargetType(node);
95999599
const aliasSymbol = getAliasSymbolForTypeNode(node);
96009600
const aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol);
9601-
const elementTypes = node.kind === SyntaxKind.ArrayType ? [node.elementType] : node.elementTypes;
9602-
links.resolvedType = elementTypes.length ? createDeferredTypeReference(target, elementTypes, /*mapper*/ undefined, aliasSymbol, aliasTypeArguments) : target;
9601+
links.resolvedType = node.kind === SyntaxKind.TupleType && node.elementTypes.length === 0 ? target :
9602+
createDeferredTypeReference(target, node, /*mapper*/ undefined, aliasSymbol, aliasTypeArguments);
96039603
}
96049604
return links.resolvedType;
96059605
}
@@ -11393,17 +11393,17 @@ namespace ts {
1139311393
return result;
1139411394
}
1139511395

11396-
function getAnonymousTypeInstantiation(type: AnonymousType, mapper: TypeMapper) {
11396+
function getObjectTypeInstantiation(type: AnonymousType | DeferredTypeReference, mapper: TypeMapper) {
1139711397
const target = type.objectFlags & ObjectFlags.Instantiated ? type.target! : type;
11398-
const { symbol } = target;
11399-
const links = getSymbolLinks(symbol);
11398+
const node = type.objectFlags & ObjectFlags.Reference ? (<TypeReference>type).node! : type.symbol.declarations[0];
11399+
const links = getNodeLinks(node);
1140011400
let typeParameters = links.outerTypeParameters;
1140111401
if (!typeParameters) {
1140211402
// The first time an anonymous type is instantiated we compute and store a list of the type
1140311403
// parameters that are in scope (and therefore potentially referenced). For type literals that
1140411404
// aren't the right hand side of a generic type alias declaration we optimize by reducing the
1140511405
// set of type parameters to those that are possibly referenced in the literal.
11406-
let declaration = symbol.declarations[0];
11406+
let declaration = node;
1140711407
if (isInJSFile(declaration)) {
1140811408
const paramTag = findAncestor(declaration, isJSDocParameterTag);
1140911409
if (paramTag) {
@@ -11419,7 +11419,7 @@ namespace ts {
1141911419
outerTypeParameters = addRange(outerTypeParameters, templateTagParameters);
1142011420
}
1142111421
typeParameters = outerTypeParameters || emptyArray;
11422-
typeParameters = symbol.flags & SymbolFlags.TypeLiteral && !target.aliasTypeArguments ?
11422+
typeParameters = (target.objectFlags & ObjectFlags.Reference || target.symbol.flags & SymbolFlags.TypeLiteral) && !target.aliasTypeArguments ?
1142311423
filter(typeParameters, tp => isTypeParameterPossiblyReferenced(tp, declaration)) :
1142411424
typeParameters;
1142511425
links.outerTypeParameters = typeParameters;
@@ -11432,13 +11432,14 @@ namespace ts {
1143211432
// We are instantiating an anonymous type that has one or more type parameters in scope. Apply the
1143311433
// mapper to the type parameters to produce the effective list of type arguments, and compute the
1143411434
// instantiation cache key from the type IDs of the type arguments.
11435-
const combinedMapper = type.objectFlags & ObjectFlags.Instantiated ? combineTypeMappers(type.mapper!, mapper) : mapper;
11436-
const typeArguments: Type[] = map(typeParameters, combinedMapper);
11435+
const typeArguments: Type[] = map(typeParameters, combineTypeMappers(type.mapper, mapper));
1143711436
const id = getTypeListId(typeArguments);
1143811437
let result = links.instantiations!.get(id);
1143911438
if (!result) {
1144011439
const newMapper = createTypeMapper(typeParameters, typeArguments);
11441-
result = target.objectFlags & ObjectFlags.Mapped ? instantiateMappedType(<MappedType>target, newMapper) : instantiateAnonymousType(target, newMapper);
11440+
result = target.objectFlags & ObjectFlags.Reference ? instantiateDeferredTypeReference(<DeferredTypeReference>type, newMapper) :
11441+
target.objectFlags & ObjectFlags.Mapped ? instantiateMappedType(<MappedType>target, newMapper) :
11442+
instantiateAnonymousType(target, newMapper);
1144211443
links.instantiations!.set(id, result);
1144311444
}
1144411445
return result;
@@ -11570,6 +11571,10 @@ namespace ts {
1157011571
return result;
1157111572
}
1157211573

11574+
function instantiateDeferredTypeReference(type: DeferredTypeReference, mapper: TypeMapper): TypeReference {
11575+
return createDeferredTypeReference(type.target, type.node, mapper, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper));
11576+
}
11577+
1157311578
function getConditionalTypeInstantiation(type: ConditionalType, mapper: TypeMapper): Type {
1157411579
const root = type.root;
1157511580
if (root.outerTypeParameters) {
@@ -11635,17 +11640,14 @@ namespace ts {
1163511640
// interface, in an object type literal, or in an object literal expression, we may need
1163611641
// to instantiate the type because it might reference a type parameter.
1163711642
return couldContainTypeVariables(type) ?
11638-
getAnonymousTypeInstantiation(<AnonymousType>type, mapper) : type;
11643+
getObjectTypeInstantiation(<AnonymousType>type, mapper) : type;
1163911644
}
1164011645
if (objectFlags & ObjectFlags.Mapped) {
11641-
return getAnonymousTypeInstantiation(<AnonymousType>type, mapper);
11646+
return getObjectTypeInstantiation(<AnonymousType>type, mapper);
1164211647
}
1164311648
if (objectFlags & ObjectFlags.Reference) {
11644-
const typeArgumentNodes = (<TypeReference>type).typeArgumentNodes;
11645-
if (typeArgumentNodes) {
11646-
const combinedMapper = combineTypeMappers((<TypeReference>type).mapper, mapper);
11647-
return createDeferredTypeReference((<TypeReference>type).target, typeArgumentNodes, combinedMapper,
11648-
(<TypeReference>type).aliasSymbol, instantiateTypes((<TypeReference>type).aliasTypeArguments, combinedMapper));
11649+
if ((<TypeReference>type).node) {
11650+
return getObjectTypeInstantiation(<TypeReference>type, mapper);
1164911651
}
1165011652
const resolvedTypeArguments = (<TypeReference>type).resolvedTypeArguments;
1165111653
const newTypeArguments = instantiateTypes(resolvedTypeArguments, mapper);
@@ -14440,7 +14442,7 @@ namespace ts {
1444014442
}
1444114443

1444214444
function isNonDeferredTypeReference(type: Type): type is TypeReference {
14443-
return !!(getObjectFlags(type) & ObjectFlags.Reference) && !(<TypeReference>type).typeArgumentNodes;
14445+
return !!(getObjectFlags(type) & ObjectFlags.Reference) && !(<TypeReference>type).node;
1444414446
}
1444514447

1444614448
function isTypeReferenceWithGenericArguments(type: Type): boolean {
@@ -22849,7 +22851,7 @@ namespace ts {
2284922851
* Indicates whether a declaration can be treated as a constructor in a JavaScript
2285022852
* file.
2285122853
*/
22852-
function isJSConstructor(node: Declaration | undefined): boolean {
22854+
function isJSConstructor(node: Node | undefined): boolean {
2285322855
if (!node || !isInJSFile(node)) {
2285422856
return false;
2285522857
}

src/compiler/types.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3954,6 +3954,8 @@ namespace ts {
39543954
contextFreeType?: Type; // Cached context-free type used by the first pass of inference; used when a function's return is partially contextually sensitive
39553955
deferredNodes?: Map<Node>; // Set of nodes whose checking has been deferred
39563956
capturedBlockScopeBindings?: Symbol[]; // Block-scoped bindings captured beneath this part of an IterationStatement
3957+
outerTypeParameters?: TypeParameter[]; // Outer type parameters of anonymous object type
3958+
instantiations?: Map<Type>; // Instantiations of generic type alias (undefined if non-generic)
39573959
}
39583960

39593961
export const enum TypeFlags {
@@ -4200,13 +4202,18 @@ namespace ts {
42004202
*/
42014203
export interface TypeReference extends ObjectType {
42024204
target: GenericType; // Type reference target
4203-
resolvedTypeArguments?: ReadonlyArray<Type>; // Type reference type arguments (undefined if none)
4204-
typeArgumentNodes?: ReadonlyArray<TypeNode>;
4205+
node?: ArrayTypeNode | TupleTypeNode;
42054206
mapper?: TypeMapper;
4207+
resolvedTypeArguments?: ReadonlyArray<Type>; // Resolved ype reference type arguments
42064208
/* @internal */
42074209
literalType?: TypeReference; // Clone of type with ObjectFlags.ArrayLiteral set
42084210
}
42094211

4212+
export interface DeferredTypeReference extends TypeReference {
4213+
node: ArrayTypeNode | TupleTypeNode;
4214+
mapper?: TypeMapper;
4215+
}
4216+
42104217
/* @internal */
42114218
export const enum VarianceFlags {
42124219
Invariant = 0, // Neither covariant nor contravariant

0 commit comments

Comments
 (0)