Skip to content

Commit 63338f9

Browse files
committed
Use objects instead of closures for type mappers
1 parent 8a0b882 commit 63338f9

File tree

2 files changed

+54
-42
lines changed

2 files changed

+54
-42
lines changed

Diff for: src/compiler/checker.ts

+43-41
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,6 @@ namespace ts {
305305
let currentNode: Node | undefined;
306306

307307
const emptySymbols = createSymbolTable();
308-
const identityMapper: (type: Type) => Type = identity;
309308
const arrayVariances = [VarianceFlags.Covariant];
310309

311310
const compilerOptions = host.getCompilerOptions();
@@ -702,6 +701,10 @@ namespace ts {
702701
const keyofConstraintType = keyofStringsOnly ? stringType : stringNumberSymbolType;
703702
const numberOrBigIntType = getUnionType([numberType, bigintType]);
704703

704+
const identityMapper: TypeMapper = { kind: TypeMapKind.Function, func: t => t };
705+
const restrictiveMapper: TypeMapper = { kind: TypeMapKind.Function, func: t => t.flags & TypeFlags.TypeParameter ? getRestrictiveTypeParameter(<TypeParameter>t) : t };
706+
const permissiveMapper: TypeMapper = { kind: TypeMapKind.Function, func: t => t.flags & TypeFlags.TypeParameter ? wildcardType : t };
707+
705708
const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
706709
const emptyJsxObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
707710
emptyJsxObjectType.objectFlags |= ObjectFlags.JsxAttributes;
@@ -4882,7 +4885,7 @@ namespace ts {
48824885
const params = getTypeParametersOfClassOrInterface(
48834886
parentSymbol.flags & SymbolFlags.Alias ? resolveAlias(parentSymbol) : parentSymbol
48844887
);
4885-
typeParameterNodes = mapToTypeNodes(map(params, (nextSymbol as TransientSymbol).mapper!), context);
4888+
typeParameterNodes = mapToTypeNodes(map(params, t => getMappedType(t, (nextSymbol as TransientSymbol).mapper!)), context);
48864889
}
48874890
else {
48884891
typeParameterNodes = typeParametersToTypeParameterDeclarations(symbol, context);
@@ -13298,30 +13301,36 @@ namespace ts {
1329813301
return instantiateList<Signature>(signatures, mapper, instantiateSignature);
1329913302
}
1330013303

13301-
function makeUnaryTypeMapper(source: Type, target: Type) {
13302-
return (t: Type) => t === source ? target : t;
13304+
function createTypeMapper(sources: readonly TypeParameter[], targets: readonly Type[] | undefined): TypeMapper {
13305+
return sources.length === 1 ?
13306+
makeUnaryTypeMapper(sources[0], targets ? targets[0] : anyType) :
13307+
{ kind: TypeMapKind.Multiple, sources, targets };
1330313308
}
1330413309

13305-
function makeBinaryTypeMapper(source1: Type, target1: Type, source2: Type, target2: Type) {
13306-
return (t: Type) => t === source1 ? target1 : t === source2 ? target2 : t;
13310+
function getMappedType(type: Type, map: TypeMapper): Type {
13311+
switch (map.kind) {
13312+
case TypeMapKind.Single:
13313+
return type === map.source ? map.target : type;
13314+
case TypeMapKind.Multiple:
13315+
const sources = map.sources;
13316+
const targets = map.targets;
13317+
for (let i = 0; i < sources.length; i++) {
13318+
if (type === sources[i]) {
13319+
return targets ? targets[i] : anyType;
13320+
}
13321+
}
13322+
return type;
13323+
case TypeMapKind.Function:
13324+
return map.func(type);
13325+
}
1330713326
}
1330813327

13309-
function makeArrayTypeMapper(sources: readonly Type[], targets: readonly Type[] | undefined) {
13310-
return (t: Type) => {
13311-
for (let i = 0; i < sources.length; i++) {
13312-
if (t === sources[i]) {
13313-
return targets ? targets[i] : anyType;
13314-
}
13315-
}
13316-
return t;
13317-
};
13328+
function makeUnaryTypeMapper(source: Type, target: Type): TypeMapper {
13329+
return { kind: TypeMapKind.Single, source, target };
1331813330
}
1331913331

13320-
function createTypeMapper(sources: readonly TypeParameter[], targets: readonly Type[] | undefined): TypeMapper {
13321-
Debug.assert(targets === undefined || sources.length === targets.length);
13322-
return sources.length === 1 ? makeUnaryTypeMapper(sources[0], targets ? targets[0] : anyType) :
13323-
sources.length === 2 ? makeBinaryTypeMapper(sources[0], targets ? targets[0] : anyType, sources[1], targets ? targets[1] : anyType) :
13324-
makeArrayTypeMapper(sources, targets);
13332+
function makeFunctionTypeMapper(func: (t: Type) => Type): TypeMapper {
13333+
return { kind: TypeMapKind.Function, func };
1332513334
}
1332613335

1332713336
function createTypeEraser(sources: readonly TypeParameter[]): TypeMapper {
@@ -13333,23 +13342,19 @@ namespace ts {
1333313342
* This is used during inference when instantiating type parameter defaults.
1333413343
*/
1333513344
function createBackreferenceMapper(context: InferenceContext, index: number): TypeMapper {
13336-
return t => findIndex(context.inferences, info => info.typeParameter === t) >= index ? unknownType : t;
13345+
return { kind: TypeMapKind.Function, func: t => findIndex(context.inferences, info => info.typeParameter === t) >= index ? unknownType : t };
1333713346
}
1333813347

1333913348
function combineTypeMappers(mapper1: TypeMapper | undefined, mapper2: TypeMapper): TypeMapper;
1334013349
function combineTypeMappers(mapper1: TypeMapper, mapper2: TypeMapper | undefined): TypeMapper;
1334113350
function combineTypeMappers(mapper1: TypeMapper, mapper2: TypeMapper): TypeMapper {
1334213351
if (!mapper1) return mapper2;
1334313352
if (!mapper2) return mapper1;
13344-
return t => instantiateType(mapper1(t), mapper2);
13353+
return makeFunctionTypeMapper(t => instantiateType(getMappedType(t, mapper1), mapper2));
1334513354
}
1334613355

1334713356
function createReplacementMapper(source: Type, target: Type, baseMapper: TypeMapper): TypeMapper {
13348-
return t => t === source ? target : baseMapper(t);
13349-
}
13350-
13351-
function permissiveMapper(type: Type) {
13352-
return type.flags & TypeFlags.TypeParameter ? wildcardType : type;
13357+
return makeFunctionTypeMapper(t => t === source ? target : getMappedType(t, baseMapper));
1335313358
}
1335413359

1335513360
function getRestrictiveTypeParameter(tp: TypeParameter) {
@@ -13360,10 +13365,6 @@ namespace ts {
1336013365
);
1336113366
}
1336213367

13363-
function restrictiveMapper(type: Type) {
13364-
return type.flags & TypeFlags.TypeParameter ? getRestrictiveTypeParameter(<TypeParameter>type) : type;
13365-
}
13366-
1336713368
function cloneTypeParameter(typeParameter: TypeParameter): TypeParameter {
1336813369
const result = createTypeParameter(typeParameter.symbol);
1336913370
result.target = typeParameter;
@@ -13470,7 +13471,8 @@ namespace ts {
1347013471
// We are instantiating an anonymous type that has one or more type parameters in scope. Apply the
1347113472
// mapper to the type parameters to produce the effective list of type arguments, and compute the
1347213473
// instantiation cache key from the type IDs of the type arguments.
13473-
const typeArguments = map(typeParameters, combineTypeMappers(type.mapper, mapper));
13474+
const combinedMapper = combineTypeMappers(type.mapper, mapper);
13475+
const typeArguments = map(typeParameters, t => getMappedType(t, combinedMapper));
1347413476
const id = getTypeListId(typeArguments);
1347513477
let result = links.instantiations!.get(id);
1347613478
if (!result) {
@@ -13615,7 +13617,7 @@ namespace ts {
1361513617
// We are instantiating a conditional type that has one or more type parameters in scope. Apply the
1361613618
// mapper to the type parameters to produce the effective list of type arguments, and compute the
1361713619
// instantiation cache key from the type IDs of the type arguments.
13618-
const typeArguments = map(root.outerTypeParameters, mapper);
13620+
const typeArguments = map(root.outerTypeParameters, t => getMappedType(t, mapper));
1361913621
const id = getTypeListId(typeArguments);
1362013622
let result = root.instantiations!.get(id);
1362113623
if (!result) {
@@ -13634,7 +13636,7 @@ namespace ts {
1363413636
// type A | B, we produce (A extends U ? X : Y) | (B extends U ? X : Y).
1363513637
if (root.isDistributive) {
1363613638
const checkType = <TypeParameter>root.checkType;
13637-
const instantiatedType = mapper(checkType);
13639+
const instantiatedType = getMappedType(checkType, mapper);
1363813640
if (checkType !== instantiatedType && instantiatedType.flags & (TypeFlags.Union | TypeFlags.Never)) {
1363913641
return mapType(instantiatedType, t => getConditionalType(root, createReplacementMapper(checkType, t, mapper)));
1364013642
}
@@ -13665,7 +13667,7 @@ namespace ts {
1366513667
function instantiateTypeWorker(type: Type, mapper: TypeMapper): Type {
1366613668
const flags = type.flags;
1366713669
if (flags & TypeFlags.TypeParameter) {
13668-
return mapper(type);
13670+
return getMappedType(type, mapper);
1366913671
}
1367013672
if (flags & TypeFlags.Object) {
1367113673
const objectFlags = (<ObjectType>type).objectFlags;
@@ -15430,10 +15432,10 @@ namespace ts {
1543015432
// We're in the middle of variance checking - integrate any unmeasurable/unreliable flags from this cached component
1543115433
const saved = entry & RelationComparisonResult.ReportsMask;
1543215434
if (saved & RelationComparisonResult.ReportsUnmeasurable) {
15433-
instantiateType(source, reportUnmeasurableMarkers);
15435+
instantiateType(source, makeFunctionTypeMapper(reportUnmeasurableMarkers));
1543415436
}
1543515437
if (saved & RelationComparisonResult.ReportsUnreliable) {
15436-
instantiateType(source, reportUnreliableMarkers);
15438+
instantiateType(source, makeFunctionTypeMapper(reportUnreliableMarkers));
1543715439
}
1543815440
}
1543915441
return entry & RelationComparisonResult.Succeeded ? Ternary.True : Ternary.False;
@@ -15878,7 +15880,7 @@ namespace ts {
1587815880
if (modifiersRelated) {
1587915881
let result: Ternary;
1588015882
const targetConstraint = getConstraintTypeFromMappedType(target);
15881-
const sourceConstraint = instantiateType(getConstraintTypeFromMappedType(source), getCombinedMappedTypeOptionality(source) < 0 ? reportUnmeasurableMarkers : reportUnreliableMarkers);
15883+
const sourceConstraint = instantiateType(getConstraintTypeFromMappedType(source), makeFunctionTypeMapper(getCombinedMappedTypeOptionality(source) < 0 ? reportUnmeasurableMarkers : reportUnreliableMarkers));
1588215884
if (result = isRelatedTo(targetConstraint, sourceConstraint, reportErrors)) {
1588315885
const mapper = createTypeMapper([getTypeParameterFromMappedType(source)], [getTypeParameterFromMappedType(target)]);
1588415886
return result & isRelatedTo(instantiateType(getTemplateTypeFromMappedType(source), mapper), getTemplateTypeFromMappedType(target), reportErrors);
@@ -16359,7 +16361,7 @@ namespace ts {
1635916361
*/
1636016362
function signatureRelatedTo(source: Signature, target: Signature, erase: boolean, reportErrors: boolean, incompatibleReporter: (source: Type, target: Type) => void): Ternary {
1636116363
return compareSignaturesRelated(erase ? getErasedSignature(source) : source, erase ? getErasedSignature(target) : target,
16362-
relation === strictSubtypeRelation ? SignatureCheckMode.StrictArity : 0, reportErrors, reportError, incompatibleReporter, isRelatedTo, reportUnreliableMarkers);
16364+
relation === strictSubtypeRelation ? SignatureCheckMode.StrictArity : 0, reportErrors, reportError, incompatibleReporter, isRelatedTo, makeFunctionTypeMapper(reportUnreliableMarkers));
1636316365
}
1636416366

1636516367
function signaturesIdenticalTo(source: Type, target: Type, kind: SignatureKind): Ternary {
@@ -17556,8 +17558,8 @@ namespace ts {
1755617558
signature,
1755717559
flags,
1755817560
compareTypes,
17559-
mapper: t => mapToInferredType(context, t, /*fix*/ true),
17560-
nonFixingMapper: t => mapToInferredType(context, t, /*fix*/ false),
17561+
mapper: makeFunctionTypeMapper(t => mapToInferredType(context, t, /*fix*/ true)),
17562+
nonFixingMapper: makeFunctionTypeMapper(t => mapToInferredType(context, t, /*fix*/ false)),
1756117563
};
1756217564
return context;
1756317565
}

Diff for: src/compiler/types.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -4812,7 +4812,17 @@ namespace ts {
48124812
}
48134813

48144814
/* @internal */
4815-
export type TypeMapper = (t: TypeParameter) => Type;
4815+
export const enum TypeMapKind {
4816+
Single,
4817+
Multiple,
4818+
Function,
4819+
}
4820+
4821+
/* @internal */
4822+
export type TypeMapper =
4823+
{ kind: TypeMapKind.Single, source: Type, target: Type } |
4824+
{ kind: TypeMapKind.Multiple, sources: readonly Type[], targets: readonly Type[] | undefined } |
4825+
{ kind: TypeMapKind.Function, func: (t: Type) => Type };
48164826

48174827
export const enum InferencePriority {
48184828
NakedTypeVariable = 1 << 0, // Naked type variable in union or intersection type

0 commit comments

Comments
 (0)