@@ -340,6 +340,23 @@ namespace ts {
340
340
const Symbol = objectAllocator.getSymbolConstructor();
341
341
const Type = objectAllocator.getTypeConstructor();
342
342
const Signature = objectAllocator.getSignatureConstructor();
343
+ type DebugType = Type & { __debugTypeToString(): string }; // eslint-disable-line @typescript-eslint/naming-convention
344
+ class DebugTypeMapper {
345
+ declare kind: TypeMapKind;
346
+ __debugToString(): string { // eslint-disable-line @typescript-eslint/naming-convention
347
+ Debug.type<TypeMapper>(this);
348
+ switch (this.kind) {
349
+ case TypeMapKind.Function: return this.debugInfo?.() || "(function mapper)";
350
+ case TypeMapKind.Simple: return `${(this.source as DebugType).__debugTypeToString()} -> ${(this.target as DebugType).__debugTypeToString()}`;
351
+ case TypeMapKind.Array: return zipWith(this.sources, this.targets || map(this.sources, () => anyType), (s, t) => `${(s as DebugType).__debugTypeToString()} -> ${(t as DebugType).__debugTypeToString()}`).join(", ");
352
+ case TypeMapKind.Deferred: return zipWith(this.sources, this.targets, (s, t) => `${(s as DebugType).__debugTypeToString()} -> ${(t() as DebugType).__debugTypeToString()}`).join(", ");
353
+ case TypeMapKind.Merged:
354
+ case TypeMapKind.Composite: return `m1: ${(this.mapper1 as unknown as DebugTypeMapper).__debugToString().split("\n").join("\n ")}
355
+ m2: ${(this.mapper2 as unknown as DebugTypeMapper).__debugToString().split("\n").join("\n ")}`;
356
+ default: return Debug.assertNever(this);
357
+ }
358
+ }
359
+ }
343
360
344
361
let typeCount = 0;
345
362
let symbolCount = 0;
@@ -829,10 +846,23 @@ namespace ts {
829
846
const templateConstraintType = getUnionType([stringType, numberType, booleanType, bigintType, nullType, undefinedType]) as UnionType;
830
847
const numericStringType = getTemplateLiteralType(["", ""], [numberType]); // The `${number}` type
831
848
832
- const restrictiveMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? getRestrictiveTypeParameter(t as TypeParameter) : t);
833
- const permissiveMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? wildcardType : t);
849
+ const restrictiveMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? getRestrictiveTypeParameter(t as TypeParameter) : t, () => "(restrictive mapper)" );
850
+ const permissiveMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? wildcardType : t, () => "(permissive mapper)" );
834
851
const uniqueLiteralType = createIntrinsicType(TypeFlags.Never, "never"); // `uniqueLiteralType` is a special `never` flagged by union reduction to behave as a literal
835
- const uniqueLiteralMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? uniqueLiteralType : t); // replace all type parameters with the unique literal type (disregarding constraints)
852
+ const uniqueLiteralMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? uniqueLiteralType : t, () => "(unique literal mapper)"); // replace all type parameters with the unique literal type (disregarding constraints)
853
+ let outofbandVarianceMarkerHandler: ((onlyUnreliable: boolean) => void) | undefined;
854
+ const reportUnreliableMapper = makeFunctionTypeMapper(t => {
855
+ if (outofbandVarianceMarkerHandler && (t === markerSuperType || t === markerSubType || t === markerOtherType)) {
856
+ outofbandVarianceMarkerHandler(/*onlyUnreliable*/ true);
857
+ }
858
+ return t;
859
+ }, () => "(unmeasurable reporter)");
860
+ const reportUnmeasurableMapper = makeFunctionTypeMapper(t => {
861
+ if (outofbandVarianceMarkerHandler && (t === markerSuperType || t === markerSubType || t === markerOtherType)) {
862
+ outofbandVarianceMarkerHandler(/*onlyUnreliable*/ false);
863
+ }
864
+ return t;
865
+ }, () => "(unreliable reporter)");
836
866
837
867
const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, emptyArray);
838
868
const emptyJsxObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, emptyArray);
@@ -1029,7 +1059,6 @@ namespace ts {
1029
1059
1030
1060
let _jsxNamespace: __String;
1031
1061
let _jsxFactoryEntity: EntityName | undefined;
1032
- let outofbandVarianceMarkerHandler: ((onlyUnreliable: boolean) => void) | undefined;
1033
1062
1034
1063
const subtypeRelation = new Map<string, RelationComparisonResult>();
1035
1064
const strictSubtypeRelation = new Map<string, RelationComparisonResult>();
@@ -5124,7 +5153,7 @@ namespace ts {
5124
5153
const name = typeParameterToName(newParam, context);
5125
5154
const newTypeVariable = factory.createTypeReferenceNode(name);
5126
5155
context.approximateLength += 37; // 15 each for two added conditionals, 7 for an added infer type
5127
- const newMapper = prependTypeMapping(type.root.checkType, newParam, type.combinedMapper || type. mapper);
5156
+ const newMapper = prependTypeMapping(type.root.checkType, newParam, type.mapper);
5128
5157
const saveInferTypeParameters = context.inferTypeParameters;
5129
5158
context.inferTypeParameters = type.root.inferTypeParameters;
5130
5159
const extendsTypeNode = typeToTypeNodeHelper(instantiateType(type.root.extendsType, newMapper), context);
@@ -16774,7 +16803,7 @@ namespace ts {
16774
16803
switch (mapper.kind) {
16775
16804
case TypeMapKind.Simple:
16776
16805
return type === mapper.source ? mapper.target : type;
16777
- case TypeMapKind.Array:
16806
+ case TypeMapKind.Array: {
16778
16807
const sources = mapper.sources;
16779
16808
const targets = mapper.targets;
16780
16809
for (let i = 0; i < sources.length; i++) {
@@ -16783,6 +16812,17 @@ namespace ts {
16783
16812
}
16784
16813
}
16785
16814
return type;
16815
+ }
16816
+ case TypeMapKind.Deferred: {
16817
+ const sources = mapper.sources;
16818
+ const targets = mapper.targets;
16819
+ for (let i = 0; i < sources.length; i++) {
16820
+ if (type === sources[i]) {
16821
+ return targets[i]();
16822
+ }
16823
+ }
16824
+ return type;
16825
+ }
16786
16826
case TypeMapKind.Function:
16787
16827
return mapper.func(type);
16788
16828
case TypeMapKind.Composite:
@@ -16792,20 +16832,31 @@ namespace ts {
16792
16832
}
16793
16833
}
16794
16834
16835
+ function attachDebugPrototypeIfDebug(mapper: TypeMapper): TypeMapper {
16836
+ if (Debug.isDebugging) {
16837
+ return Object.setPrototypeOf(mapper, DebugTypeMapper.prototype);
16838
+ }
16839
+ return mapper;
16840
+ }
16841
+
16795
16842
function makeUnaryTypeMapper(source: Type, target: Type): TypeMapper {
16796
- return { kind: TypeMapKind.Simple, source, target };
16843
+ return attachDebugPrototypeIfDebug( { kind: TypeMapKind.Simple, source, target }) ;
16797
16844
}
16798
16845
16799
16846
function makeArrayTypeMapper(sources: readonly TypeParameter[], targets: readonly Type[] | undefined): TypeMapper {
16800
- return { kind: TypeMapKind.Array, sources, targets };
16847
+ return attachDebugPrototypeIfDebug({ kind: TypeMapKind.Array, sources, targets });
16848
+ }
16849
+
16850
+ function makeFunctionTypeMapper(func: (t: Type) => Type, debugInfo: () => string): TypeMapper {
16851
+ return attachDebugPrototypeIfDebug({ kind: TypeMapKind.Function, func, debugInfo: Debug.isDebugging ? debugInfo : undefined });
16801
16852
}
16802
16853
16803
- function makeFunctionTypeMapper(func: (t: Type ) => Type): TypeMapper {
16804
- return { kind: TypeMapKind.Function, func } ;
16854
+ function makeDeferredTypeMapper(sources: readonly TypeParameter[], targets: (( ) => Type)[]) {
16855
+ return attachDebugPrototypeIfDebug( { kind: TypeMapKind.Deferred, sources, targets }) ;
16805
16856
}
16806
16857
16807
16858
function makeCompositeTypeMapper(kind: TypeMapKind.Composite | TypeMapKind.Merged, mapper1: TypeMapper, mapper2: TypeMapper): TypeMapper {
16808
- return { kind, mapper1, mapper2 };
16859
+ return attachDebugPrototypeIfDebug( { kind, mapper1, mapper2 }) ;
16809
16860
}
16810
16861
16811
16862
function createTypeEraser(sources: readonly TypeParameter[]): TypeMapper {
@@ -16817,7 +16868,8 @@ namespace ts {
16817
16868
* This is used during inference when instantiating type parameter defaults.
16818
16869
*/
16819
16870
function createBackreferenceMapper(context: InferenceContext, index: number): TypeMapper {
16820
- return makeFunctionTypeMapper(t => findIndex(context.inferences, info => info.typeParameter === t) >= index ? unknownType : t);
16871
+ const forwardInferences = context.inferences.slice(index);
16872
+ return createTypeMapper(map(forwardInferences, i => i.typeParameter), map(forwardInferences, () => unknownType));
16821
16873
}
16822
16874
16823
16875
function combineTypeMappers(mapper1: TypeMapper | undefined, mapper2: TypeMapper): TypeMapper {
@@ -19183,10 +19235,10 @@ namespace ts {
19183
19235
// We're in the middle of variance checking - integrate any unmeasurable/unreliable flags from this cached component
19184
19236
const saved = entry & RelationComparisonResult.ReportsMask;
19185
19237
if (saved & RelationComparisonResult.ReportsUnmeasurable) {
19186
- instantiateType(source, makeFunctionTypeMapper(reportUnmeasurableMarkers) );
19238
+ instantiateType(source, reportUnmeasurableMapper );
19187
19239
}
19188
19240
if (saved & RelationComparisonResult.ReportsUnreliable) {
19189
- instantiateType(source, makeFunctionTypeMapper(reportUnreliableMarkers) );
19241
+ instantiateType(source, reportUnreliableMapper );
19190
19242
}
19191
19243
}
19192
19244
return entry & RelationComparisonResult.Succeeded ? Ternary.True : Ternary.False;
@@ -19624,7 +19676,7 @@ namespace ts {
19624
19676
}
19625
19677
// Report unreliable variance for type variables referenced in template literal type placeholders.
19626
19678
// For example, `foo-${number}` is related to `foo-${string}` even though number isn't related to string.
19627
- instantiateType(source, makeFunctionTypeMapper(reportUnreliableMarkers) );
19679
+ instantiateType(source, reportUnreliableMapper );
19628
19680
}
19629
19681
if (isTypeMatchedByTemplateLiteralType(source, target as TemplateLiteralType)) {
19630
19682
return Ternary.True;
@@ -19900,20 +19952,6 @@ namespace ts {
19900
19952
}
19901
19953
}
19902
19954
19903
- function reportUnmeasurableMarkers(p: TypeParameter) {
19904
- if (outofbandVarianceMarkerHandler && (p === markerSuperType || p === markerSubType || p === markerOtherType)) {
19905
- outofbandVarianceMarkerHandler(/*onlyUnreliable*/ false);
19906
- }
19907
- return p;
19908
- }
19909
-
19910
- function reportUnreliableMarkers(p: TypeParameter) {
19911
- if (outofbandVarianceMarkerHandler && (p === markerSuperType || p === markerSubType || p === markerOtherType)) {
19912
- outofbandVarianceMarkerHandler(/*onlyUnreliable*/ true);
19913
- }
19914
- return p;
19915
- }
19916
-
19917
19955
// A type [P in S]: X is related to a type [Q in T]: Y if T is related to S and X' is
19918
19956
// related to Y, where X' is an instantiation of X in which P is replaced with Q. Notice
19919
19957
// that S and T are contra-variant whereas X and Y are co-variant.
@@ -19923,7 +19961,7 @@ namespace ts {
19923
19961
if (modifiersRelated) {
19924
19962
let result: Ternary;
19925
19963
const targetConstraint = getConstraintTypeFromMappedType(target);
19926
- const sourceConstraint = instantiateType(getConstraintTypeFromMappedType(source), makeFunctionTypeMapper( getCombinedMappedTypeOptionality(source) < 0 ? reportUnmeasurableMarkers : reportUnreliableMarkers) );
19964
+ const sourceConstraint = instantiateType(getConstraintTypeFromMappedType(source), getCombinedMappedTypeOptionality(source) < 0 ? reportUnmeasurableMapper : reportUnreliableMapper );
19927
19965
if (result = isRelatedTo(targetConstraint, sourceConstraint, RecursionFlags.Both, reportErrors)) {
19928
19966
const mapper = createTypeMapper([getTypeParameterFromMappedType(source)], [getTypeParameterFromMappedType(target)]);
19929
19967
if (instantiateType(getNameTypeFromMappedType(source), mapper) === instantiateType(getNameTypeFromMappedType(target), mapper)) {
@@ -20470,7 +20508,7 @@ namespace ts {
20470
20508
*/
20471
20509
function signatureRelatedTo(source: Signature, target: Signature, erase: boolean, reportErrors: boolean, incompatibleReporter: (source: Type, target: Type) => void): Ternary {
20472
20510
return compareSignaturesRelated(erase ? getErasedSignature(source) : source, erase ? getErasedSignature(target) : target,
20473
- relation === strictSubtypeRelation ? SignatureCheckMode.StrictArity : 0, reportErrors, reportError, incompatibleReporter, isRelatedToWorker, makeFunctionTypeMapper(reportUnreliableMarkers) );
20511
+ relation === strictSubtypeRelation ? SignatureCheckMode.StrictArity : 0, reportErrors, reportError, incompatibleReporter, isRelatedToWorker, reportUnreliableMapper );
20474
20512
}
20475
20513
20476
20514
function signaturesIdenticalTo(source: Type, target: Type, kind: SignatureKind): Ternary {
@@ -21855,28 +21893,31 @@ namespace ts {
21855
21893
signature,
21856
21894
flags,
21857
21895
compareTypes,
21858
- mapper: makeFunctionTypeMapper(t => mapToInferredType( context, t, /*fix*/ true)),
21859
- nonFixingMapper: makeFunctionTypeMapper(t => mapToInferredType(context, t, /*fix*/ false)) ,
21896
+ mapper: reportUnmeasurableMapper, // initialize to a noop mapper so the context object is available, but the underlying object shape is right upon construction
21897
+ nonFixingMapper: reportUnmeasurableMapper ,
21860
21898
};
21899
+ context.mapper = makeFixingMapperForContext(context);
21900
+ context.nonFixingMapper = makeNonFixingMapperForContext(context);
21861
21901
return context;
21862
21902
}
21863
21903
21864
- function mapToInferredType(context: InferenceContext, t: Type, fix: boolean): Type {
21865
- const inferences = context.inferences;
21866
- for (let i = 0; i < inferences.length; i++) {
21867
- const inference = inferences[i];
21868
- if (t === inference.typeParameter) {
21869
- if (fix && !inference.isFixed) {
21870
- // Before we commit to a particular inference (and thus lock out any further inferences),
21871
- // we infer from any intra-expression inference sites we have collected.
21872
- inferFromIntraExpressionSites(context);
21873
- clearCachedInferences(inferences);
21874
- inference.isFixed = true;
21875
- }
21876
- return getInferredType(context, i);
21904
+ function makeFixingMapperForContext(context: InferenceContext) {
21905
+ return makeDeferredTypeMapper(map(context.inferences, i => i.typeParameter), map(context.inferences, (inference, i) => () => {
21906
+ if (!inference.isFixed) {
21907
+ // Before we commit to a particular inference (and thus lock out any further inferences),
21908
+ // we infer from any intra-expression inference sites we have collected.
21909
+ inferFromIntraExpressionSites(context);
21910
+ clearCachedInferences(context.inferences);
21911
+ inference.isFixed = true;
21877
21912
}
21878
- }
21879
- return t;
21913
+ return getInferredType(context, i);
21914
+ }));
21915
+ }
21916
+
21917
+ function makeNonFixingMapperForContext(context: InferenceContext) {
21918
+ return makeDeferredTypeMapper(map(context.inferences, i => i.typeParameter), map(context.inferences, (_, i) => () => {
21919
+ return getInferredType(context, i);
21920
+ }));
21880
21921
}
21881
21922
21882
21923
function clearCachedInferences(inferences: InferenceInfo[]) {
0 commit comments