@@ -12889,65 +12889,82 @@ namespace ts {
1288912889 }
1289012890
1289112891 function getConditionalType(root: ConditionalRoot, mapper: TypeMapper | undefined): Type {
12892- const checkType = instantiateType(root.checkType, mapper);
12893- const extendsType = instantiateType(root.extendsType, mapper);
12894- if (checkType === wildcardType || extendsType === wildcardType) {
12895- return wildcardType;
12892+ let result;
12893+ let extraTypes: Type[] | undefined;
12894+ // We loop here for an immediately nested conditional type in the false position, effectively treating
12895+ // types of the form 'A extends B ? X : C extends D ? Y : E extends F ? Z : ...' as a single construct for
12896+ // purposes of resolution. This means such types aren't subject to the instatiation depth limiter.
12897+ while (true) {
12898+ const checkType = instantiateType(root.checkType, mapper);
12899+ const checkTypeInstantiable = isGenericObjectType(checkType) || isGenericIndexType(checkType);
12900+ const extendsType = instantiateType(root.extendsType, mapper);
12901+ if (checkType === wildcardType || extendsType === wildcardType) {
12902+ return wildcardType;
12903+ }
12904+ let combinedMapper: TypeMapper | undefined;
12905+ if (root.inferTypeParameters) {
12906+ const context = createInferenceContext(root.inferTypeParameters, /*signature*/ undefined, InferenceFlags.None);
12907+ // We skip inference of the possible `infer` types unles the `extendsType` _is_ an infer type
12908+ // if it was, it's trivial to say that extendsType = checkType, however such a pattern is used to
12909+ // "reset" the type being build up during constraint calculation and avoid making an apparently "infinite" constraint
12910+ // so in those cases we refain from performing inference and retain the uninfered type parameter
12911+ if (!checkTypeInstantiable || !some(root.inferTypeParameters, t => t === extendsType)) {
12912+ // We don't want inferences from constraints as they may cause us to eagerly resolve the
12913+ // conditional type instead of deferring resolution. Also, we always want strict function
12914+ // types rules (i.e. proper contravariance) for inferences.
12915+ inferTypes(context.inferences, checkType, extendsType, InferencePriority.NoConstraints | InferencePriority.AlwaysStrict);
12916+ }
12917+ combinedMapper = mergeTypeMappers(mapper, context.mapper);
12918+ }
12919+ // Instantiate the extends type including inferences for 'infer T' type parameters
12920+ const inferredExtendsType = combinedMapper ? instantiateType(root.extendsType, combinedMapper) : extendsType;
12921+ // We attempt to resolve the conditional type only when the check and extends types are non-generic
12922+ if (!checkTypeInstantiable && !isGenericObjectType(inferredExtendsType) && !isGenericIndexType(inferredExtendsType)) {
12923+ // Return falseType for a definitely false extends check. We check an instantiations of the two
12924+ // types with type parameters mapped to the wildcard type, the most permissive instantiations
12925+ // possible (the wildcard type is assignable to and from all types). If those are not related,
12926+ // then no instantiations will be and we can just return the false branch type.
12927+ if (!(inferredExtendsType.flags & TypeFlags.AnyOrUnknown) && (checkType.flags & TypeFlags.Any || !isTypeAssignableTo(getPermissiveInstantiation(checkType), getPermissiveInstantiation(inferredExtendsType)))) {
12928+ // Return union of trueType and falseType for 'any' since it matches anything
12929+ if (checkType.flags & TypeFlags.Any) {
12930+ (extraTypes || (extraTypes = [])).push(instantiateTypeWithoutDepthIncrease(root.trueType, combinedMapper || mapper));
12931+ }
12932+ // If falseType is an immediately nested conditional type that isn't distributive or has an
12933+ // identical checkType, switch to that type and loop.
12934+ const falseType = root.falseType;
12935+ if (falseType.flags & TypeFlags.Conditional) {
12936+ const newRoot = (<ConditionalType>falseType).root;
12937+ if (newRoot.node.parent === root.node && (!newRoot.isDistributive || newRoot.checkType === root.checkType)) {
12938+ root = newRoot;
12939+ continue;
12940+ }
12941+ }
12942+ result = instantiateTypeWithoutDepthIncrease(falseType, mapper);
12943+ break;
12944+ }
12945+ // Return trueType for a definitely true extends check. We check instantiations of the two
12946+ // types with type parameters mapped to their restrictive form, i.e. a form of the type parameter
12947+ // that has no constraint. This ensures that, for example, the type
12948+ // type Foo<T extends { x: any }> = T extends { x: string } ? string : number
12949+ // doesn't immediately resolve to 'string' instead of being deferred.
12950+ if (inferredExtendsType.flags & TypeFlags.AnyOrUnknown || isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(inferredExtendsType))) {
12951+ result = instantiateTypeWithoutDepthIncrease(root.trueType, combinedMapper || mapper);
12952+ break;
12953+ }
12954+ }
12955+ // Return a deferred type for a check that is neither definitely true nor definitely false
12956+ const erasedCheckType = getActualTypeVariable(checkType);
12957+ result = <ConditionalType>createType(TypeFlags.Conditional);
12958+ result.root = root;
12959+ result.checkType = erasedCheckType;
12960+ result.extendsType = extendsType;
12961+ result.mapper = mapper;
12962+ result.combinedMapper = combinedMapper;
12963+ result.aliasSymbol = root.aliasSymbol;
12964+ result.aliasTypeArguments = instantiateTypes(root.aliasTypeArguments, mapper!); // TODO: GH#18217
12965+ break;
1289612966 }
12897- const checkTypeInstantiable = isGenericObjectType(checkType) || isGenericIndexType(checkType);
12898- let combinedMapper: TypeMapper | undefined;
12899- if (root.inferTypeParameters) {
12900- const context = createInferenceContext(root.inferTypeParameters, /*signature*/ undefined, InferenceFlags.None);
12901- // We skip inference of the possible `infer` types unles the `extendsType` _is_ an infer type
12902- // if it was, it's trivial to say that extendsType = checkType, however such a pattern is used to
12903- // "reset" the type being build up during constraint calculation and avoid making an apparently "infinite" constraint
12904- // so in those cases we refain from performing inference and retain the uninfered type parameter
12905- if (!checkTypeInstantiable || !some(root.inferTypeParameters, t => t === extendsType)) {
12906- // We don't want inferences from constraints as they may cause us to eagerly resolve the
12907- // conditional type instead of deferring resolution. Also, we always want strict function
12908- // types rules (i.e. proper contravariance) for inferences.
12909- inferTypes(context.inferences, checkType, extendsType, InferencePriority.NoConstraints | InferencePriority.AlwaysStrict);
12910- }
12911- combinedMapper = mergeTypeMappers(mapper, context.mapper);
12912- }
12913- // Instantiate the extends type including inferences for 'infer T' type parameters
12914- const inferredExtendsType = combinedMapper ? instantiateType(root.extendsType, combinedMapper) : extendsType;
12915- // We attempt to resolve the conditional type only when the check and extends types are non-generic
12916- if (!checkTypeInstantiable && !isGenericObjectType(inferredExtendsType) && !isGenericIndexType(inferredExtendsType)) {
12917- if (inferredExtendsType.flags & TypeFlags.AnyOrUnknown) {
12918- return instantiateType(root.trueType, combinedMapper || mapper);
12919- }
12920- // Return union of trueType and falseType for 'any' since it matches anything
12921- if (checkType.flags & TypeFlags.Any) {
12922- return getUnionType([instantiateType(root.trueType, combinedMapper || mapper), instantiateType(root.falseType, mapper)]);
12923- }
12924- // Return falseType for a definitely false extends check. We check an instantiations of the two
12925- // types with type parameters mapped to the wildcard type, the most permissive instantiations
12926- // possible (the wildcard type is assignable to and from all types). If those are not related,
12927- // then no instantiations will be and we can just return the false branch type.
12928- if (!isTypeAssignableTo(getPermissiveInstantiation(checkType), getPermissiveInstantiation(inferredExtendsType))) {
12929- return instantiateType(root.falseType, mapper);
12930- }
12931- // Return trueType for a definitely true extends check. We check instantiations of the two
12932- // types with type parameters mapped to their restrictive form, i.e. a form of the type parameter
12933- // that has no constraint. This ensures that, for example, the type
12934- // type Foo<T extends { x: any }> = T extends { x: string } ? string : number
12935- // doesn't immediately resolve to 'string' instead of being deferred.
12936- if (isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(inferredExtendsType))) {
12937- return instantiateType(root.trueType, combinedMapper || mapper);
12938- }
12939- }
12940- // Return a deferred type for a check that is neither definitely true nor definitely false
12941- const erasedCheckType = getActualTypeVariable(checkType);
12942- const result = <ConditionalType>createType(TypeFlags.Conditional);
12943- result.root = root;
12944- result.checkType = erasedCheckType;
12945- result.extendsType = extendsType;
12946- result.mapper = mapper;
12947- result.combinedMapper = combinedMapper;
12948- result.aliasSymbol = root.aliasSymbol;
12949- result.aliasTypeArguments = instantiateTypes(root.aliasTypeArguments, mapper!); // TODO: GH#18217
12950- return result;
12967+ return extraTypes ? getUnionType(append(extraTypes, result)) : result;
1295112968 }
1295212969
1295312970 function getTrueTypeFromConditionalType(type: ConditionalType) {
@@ -13929,6 +13946,17 @@ namespace ts {
1392913946 return result;
1393013947 }
1393113948
13949+ /**
13950+ * This can be used to avoid the penalty on instantiation depth for types which result from immediate
13951+ * simplification. It essentially removes the depth increase done in `instantiateType`.
13952+ */
13953+ function instantiateTypeWithoutDepthIncrease(type: Type, mapper: TypeMapper | undefined) {
13954+ instantiationDepth--;
13955+ const result = instantiateType(type, mapper);
13956+ instantiationDepth++;
13957+ return result;
13958+ }
13959+
1393213960 function instantiateTypeWorker(type: Type, mapper: TypeMapper): Type {
1393313961 const flags = type.flags;
1393413962 if (flags & TypeFlags.TypeParameter) {
0 commit comments