Skip to content

Commit d9ad27f

Browse files
authored
Early couldContainTypeVariables check in instantiateType (microsoft#37844)
* Shared early couldContainTypeVariables check in instantiateType * Defer creation of map object in createUnionOrIntersectionProperty * Types with top-level non-generic type alias reference no type variables
1 parent 3919042 commit d9ad27f

File tree

1 file changed

+43
-38
lines changed

1 file changed

+43
-38
lines changed

src/compiler/checker.ts

+43-38
Original file line numberDiff line numberDiff line change
@@ -10523,7 +10523,8 @@ namespace ts {
1052310523
}
1052410524

1052510525
function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: __String): Symbol | undefined {
10526-
const propSet = createMap<Symbol>();
10526+
let singleProp: Symbol | undefined;
10527+
let propSet: Map<Symbol> | undefined;
1052710528
let indexTypes: Type[] | undefined;
1052810529
const isUnion = containingType.flags & TypeFlags.Union;
1052910530
const excludeModifiers = isUnion ? ModifierFlags.NonPublicAccessibilityModifier : 0;
@@ -10543,9 +10544,18 @@ namespace ts {
1054310544
else {
1054410545
optionalFlag &= prop.flags;
1054510546
}
10546-
const id = "" + getSymbolId(prop);
10547-
if (!propSet.has(id)) {
10548-
propSet.set(id, prop);
10547+
if (!singleProp) {
10548+
singleProp = prop;
10549+
}
10550+
else if (prop !== singleProp) {
10551+
if (!propSet) {
10552+
propSet = createMap<Symbol>();
10553+
propSet.set("" + getSymbolId(singleProp), singleProp);
10554+
}
10555+
const id = "" + getSymbolId(prop);
10556+
if (!propSet.has(id)) {
10557+
propSet.set(id, prop);
10558+
}
1054910559
}
1055010560
checkFlags |= (isReadonlySymbol(prop) ? CheckFlags.Readonly : 0) |
1055110561
(!(modifiers & ModifierFlags.NonPublicAccessibilityModifier) ? CheckFlags.ContainsPublic : 0) |
@@ -10572,13 +10582,13 @@ namespace ts {
1057210582
}
1057310583
}
1057410584
}
10575-
if (!propSet.size) {
10585+
if (!singleProp) {
1057610586
return undefined;
1057710587
}
10578-
const props = arrayFrom(propSet.values());
10579-
if (props.length === 1 && !(checkFlags & CheckFlags.ReadPartial) && !indexTypes) {
10580-
return props[0];
10588+
if (!propSet && !(checkFlags & CheckFlags.ReadPartial) && !indexTypes) {
10589+
return singleProp;
1058110590
}
10591+
const props = propSet ? arrayFrom(propSet.values()) : [singleProp];
1058210592
let declarations: Declaration[] | undefined;
1058310593
let firstType: Type | undefined;
1058410594
let nameType: Type | undefined;
@@ -14275,7 +14285,7 @@ namespace ts {
1427514285
function instantiateType(type: Type, mapper: TypeMapper | undefined): Type;
1427614286
function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined): Type | undefined;
1427714287
function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined): Type | undefined {
14278-
if (!type || !mapper) {
14288+
if (!(type && mapper && couldContainTypeVariables(type))) {
1427914289
return type;
1428014290
}
1428114291
if (instantiationDepth === 50 || instantiationCount >= 5000000) {
@@ -14311,37 +14321,23 @@ namespace ts {
1431114321
}
1431214322
if (flags & TypeFlags.Object) {
1431314323
const objectFlags = (<ObjectType>type).objectFlags;
14314-
if (objectFlags & ObjectFlags.Anonymous) {
14315-
// If the anonymous type originates in a declaration of a function, method, class, or
14316-
// interface, in an object type literal, or in an object literal expression, we may need
14317-
// to instantiate the type because it might reference a type parameter.
14318-
return couldContainTypeVariables(type) ?
14319-
getObjectTypeInstantiation(<AnonymousType>type, mapper) : type;
14320-
}
14321-
if (objectFlags & ObjectFlags.Mapped) {
14322-
return getObjectTypeInstantiation(<AnonymousType>type, mapper);
14323-
}
14324-
if (objectFlags & ObjectFlags.Reference) {
14325-
if ((<TypeReference>type).node) {
14326-
return getObjectTypeInstantiation(<TypeReference>type, mapper);
14324+
if (objectFlags & (ObjectFlags.Reference | ObjectFlags.Anonymous | ObjectFlags.Mapped)) {
14325+
if (objectFlags & ObjectFlags.Reference && !((<TypeReference>type).node)) {
14326+
const resolvedTypeArguments = (<TypeReference>type).resolvedTypeArguments;
14327+
const newTypeArguments = instantiateTypes(resolvedTypeArguments, mapper);
14328+
return newTypeArguments !== resolvedTypeArguments ? createTypeReference((<TypeReference>type).target, newTypeArguments) : type;
1432714329
}
14328-
const resolvedTypeArguments = (<TypeReference>type).resolvedTypeArguments;
14329-
const newTypeArguments = instantiateTypes(resolvedTypeArguments, mapper);
14330-
return newTypeArguments !== resolvedTypeArguments ? createTypeReference((<TypeReference>type).target, newTypeArguments) : type;
14330+
return getObjectTypeInstantiation(<TypeReference | AnonymousType | MappedType>type, mapper);
1433114331
}
1433214332
return type;
1433314333
}
14334-
if ((flags & TypeFlags.Intersection) || (flags & TypeFlags.Union && !(flags & TypeFlags.Primitive))) {
14335-
if (!couldContainTypeVariables(type)) {
14336-
return type;
14337-
}
14334+
if (flags & TypeFlags.UnionOrIntersection) {
1433814335
const types = (<UnionOrIntersectionType>type).types;
1433914336
const newTypes = instantiateTypes(types, mapper);
14340-
return newTypes === types
14341-
? type
14342-
: (flags & TypeFlags.Intersection)
14343-
? getIntersectionType(newTypes, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper))
14344-
: getUnionType(newTypes, UnionReduction.Literal, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper));
14337+
return newTypes === types ? type :
14338+
flags & TypeFlags.Intersection ?
14339+
getIntersectionType(newTypes, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper)) :
14340+
getUnionType(newTypes, UnionReduction.Literal, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper));
1434514341
}
1434614342
if (flags & TypeFlags.Index) {
1434714343
return getIndexType(instantiateType((<IndexType>type).type, mapper));
@@ -18388,16 +18384,25 @@ namespace ts {
1838818384
return !!(objectFlags & ObjectFlags.CouldContainTypeVariables);
1838918385
}
1839018386
const result = !!(type.flags & TypeFlags.Instantiable ||
18391-
objectFlags & ObjectFlags.Reference && ((<TypeReference>type).node || forEach(getTypeArguments(<TypeReference>type), couldContainTypeVariables)) ||
18392-
objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations ||
18393-
objectFlags & (ObjectFlags.Mapped | ObjectFlags.ObjectRestType) ||
18394-
type.flags & TypeFlags.UnionOrIntersection && !(type.flags & TypeFlags.EnumLiteral) && some((<UnionOrIntersectionType>type).types, couldContainTypeVariables));
18387+
type.flags & TypeFlags.Object && !isNonGenericTopLevelType(type) && (
18388+
objectFlags & ObjectFlags.Reference && ((<TypeReference>type).node || forEach(getTypeArguments(<TypeReference>type), couldContainTypeVariables)) ||
18389+
objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations ||
18390+
objectFlags & (ObjectFlags.Mapped | ObjectFlags.ObjectRestType)) ||
18391+
type.flags & TypeFlags.UnionOrIntersection && !(type.flags & TypeFlags.EnumLiteral) && !isNonGenericTopLevelType(type) && some((<UnionOrIntersectionType>type).types, couldContainTypeVariables));
1839518392
if (type.flags & TypeFlags.ObjectFlagsType) {
1839618393
(<ObjectFlagsType>type).objectFlags |= ObjectFlags.CouldContainTypeVariablesComputed | (result ? ObjectFlags.CouldContainTypeVariables : 0);
1839718394
}
1839818395
return result;
1839918396
}
1840018397

18398+
function isNonGenericTopLevelType(type: Type) {
18399+
if (type.aliasSymbol && !type.aliasTypeArguments) {
18400+
const declaration = getDeclarationOfKind(type.aliasSymbol, SyntaxKind.TypeAliasDeclaration);
18401+
return !!(declaration && findAncestor(declaration.parent, n => n.kind === SyntaxKind.SourceFile ? true : n.kind === SyntaxKind.ModuleDeclaration ? false : "quit"));
18402+
}
18403+
return false;
18404+
}
18405+
1840118406
function isTypeParameterAtTopLevel(type: Type, typeParameter: TypeParameter): boolean {
1840218407
return !!(type === typeParameter ||
1840318408
type.flags & TypeFlags.UnionOrIntersection && some((<UnionOrIntersectionType>type).types, t => isTypeParameterAtTopLevel(t, typeParameter)) ||

0 commit comments

Comments
 (0)