@@ -2159,7 +2159,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2159
2159
/** Key is "/path/to/a.ts|/path/to/b.ts". */
2160
2160
var amalgamatedDuplicates: Map<string, DuplicateInfoForFiles> | undefined;
2161
2161
var reverseMappedCache = new Map<string, Type | undefined>();
2162
- var homomorphicMappedTypeInferenceStack: string[] = [];
2163
2162
var ambientModulesCache: Symbol[] | undefined;
2164
2163
/**
2165
2164
* List of every ambient module with a "*" wildcard.
@@ -2277,6 +2276,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2277
2276
var potentialReflectCollisions: Node[] = [];
2278
2277
var potentialUnusedRenamedBindingElementsInTypes: BindingElement[] = [];
2279
2278
var awaitedTypeStack: number[] = [];
2279
+ var reverseMappedSourceStack: Type[] = [];
2280
+ var reverseMappedTargetStack: Type[] = [];
2281
+ var reverseExpandingFlags = ExpandingFlags.None;
2280
2282
2281
2283
var diagnostics = createDiagnosticCollection();
2282
2284
var suggestionDiagnostics = createDiagnosticCollection();
@@ -13583,7 +13585,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
13583
13585
const modifiers = getMappedTypeModifiers(type.mappedType);
13584
13586
const readonlyMask = modifiers & MappedTypeModifiers.IncludeReadonly ? false : true;
13585
13587
const optionalMask = modifiers & MappedTypeModifiers.IncludeOptional ? 0 : SymbolFlags.Optional;
13586
- const indexInfos = indexInfo ? [createIndexInfo(stringType, inferReverseMappedType(indexInfo.type, type.mappedType, type.constraintType), readonlyMask && indexInfo.isReadonly)] : emptyArray;
13588
+ const indexInfos = indexInfo ? [createIndexInfo(stringType, inferReverseMappedType(indexInfo.type, type.mappedType, type.constraintType) || unknownType , readonlyMask && indexInfo.isReadonly)] : emptyArray;
13587
13589
const members = createSymbolTable();
13588
13590
const limitedConstraint = getLimitedConstraint(type);
13589
13591
for (const prop of getPropertiesOfType(type.source)) {
@@ -25102,13 +25104,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
25102
25104
if (reverseMappedCache.has(cacheKey)) {
25103
25105
return reverseMappedCache.get(cacheKey);
25104
25106
}
25105
- const recursionKey = source.id + "," + (target.target || target).id;
25106
- if (contains(homomorphicMappedTypeInferenceStack, recursionKey)) {
25107
- return undefined;
25108
- }
25109
- homomorphicMappedTypeInferenceStack.push(recursionKey);
25110
25107
const type = createReverseMappedType(source, target, constraint);
25111
- homomorphicMappedTypeInferenceStack.pop();
25112
25108
reverseMappedCache.set(cacheKey, type);
25113
25109
return type;
25114
25110
}
@@ -25132,10 +25128,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
25132
25128
// For arrays and tuples we infer new arrays and tuples where the reverse mapping has been
25133
25129
// applied to the element type(s).
25134
25130
if (isArrayType(source)) {
25135
- return createArrayType(inferReverseMappedType(getTypeArguments(source)[0], target, constraint), isReadonlyArrayType(source));
25131
+ const elementType = inferReverseMappedType(getTypeArguments(source)[0], target, constraint);
25132
+ if (!elementType) {
25133
+ return undefined;
25134
+ }
25135
+ return createArrayType(elementType, isReadonlyArrayType(source));
25136
25136
}
25137
25137
if (isTupleType(source)) {
25138
25138
const elementTypes = map(getElementTypes(source), t => inferReverseMappedType(t, target, constraint));
25139
+ if (!every(elementTypes, (t): t is Type => !!t)) {
25140
+ return undefined;
25141
+ }
25139
25142
const elementFlags = getMappedTypeModifiers(target) & MappedTypeModifiers.IncludeOptional ?
25140
25143
sameMap(source.target.elementFlags, f => f & ElementFlags.Optional ? ElementFlags.Required : f) :
25141
25144
source.target.elementFlags;
@@ -25150,22 +25153,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
25150
25153
return reversed;
25151
25154
}
25152
25155
25153
- function getTypeOfReverseMappedSymbol(symbol: ReverseMappedSymbol) {
25156
+ function getTypeOfReverseMappedSymbol(symbol: ReverseMappedSymbol): Type {
25154
25157
const links = getSymbolLinks(symbol);
25155
25158
if (!links.type) {
25156
- links.type = inferReverseMappedType(symbol.links.propertyType, symbol.links.mappedType, symbol.links.constraintType);
25159
+ links.type = inferReverseMappedType(symbol.links.propertyType, symbol.links.mappedType, symbol.links.constraintType) || unknownType ;
25157
25160
}
25158
25161
return links.type;
25159
25162
}
25160
25163
25161
- function inferReverseMappedType (sourceType: Type, target: MappedType, constraint: IndexType): Type {
25164
+ function inferReverseMappedTypeWorker (sourceType: Type, target: MappedType, constraint: IndexType): Type {
25162
25165
const typeParameter = getIndexedAccessType(constraint.type, getTypeParameterFromMappedType(target)) as TypeParameter;
25163
25166
const templateType = getTemplateTypeFromMappedType(target);
25164
25167
const inference = createInferenceInfo(typeParameter);
25165
25168
inferTypes([inference], sourceType, templateType);
25166
25169
return getTypeFromInference(inference) || unknownType;
25167
25170
}
25168
25171
25172
+ function inferReverseMappedType(source: Type, target: MappedType, constraint: IndexType): Type | undefined {
25173
+ const cacheKey = source.id + "," + target.id + "," + constraint.id;
25174
+ if (reverseMappedCache.has(cacheKey)) {
25175
+ return reverseMappedCache.get(cacheKey) || unknownType;
25176
+ }
25177
+ reverseMappedSourceStack.push(source);
25178
+ reverseMappedTargetStack.push(target);
25179
+ const saveExpandingFlags = reverseExpandingFlags;
25180
+ if (isDeeplyNestedType(source, reverseMappedSourceStack, reverseMappedSourceStack.length, 2)) reverseExpandingFlags |= ExpandingFlags.Source;
25181
+ if (isDeeplyNestedType(target, reverseMappedTargetStack, reverseMappedTargetStack.length, 2)) reverseExpandingFlags |= ExpandingFlags.Target;
25182
+ let type;
25183
+ if (reverseExpandingFlags !== ExpandingFlags.Both) {
25184
+ type = inferReverseMappedTypeWorker(source, target, constraint);
25185
+ }
25186
+ reverseMappedSourceStack.pop();
25187
+ reverseMappedTargetStack.pop();
25188
+ reverseExpandingFlags = saveExpandingFlags;
25189
+ reverseMappedCache.set(cacheKey, type);
25190
+ return type;
25191
+ }
25192
+
25169
25193
function* getUnmatchedProperties(source: Type, target: Type, requireOptionalProperties: boolean, matchDiscriminantProperties: boolean): IterableIterator<Symbol> {
25170
25194
const properties = getPropertiesOfType(target);
25171
25195
for (const targetProp of properties) {
0 commit comments