@@ -281,6 +281,7 @@ namespace ts {
281281
282282 const noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
283283 const circularConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
284+ const resolvingDefaultType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
284285
285286 const markerSuperType = <TypeParameter>createType(TypeFlags.TypeParameter);
286287 const markerSubType = <TypeParameter>createType(TypeFlags.TypeParameter);
@@ -6055,27 +6056,51 @@ namespace ts {
60556056 return type.resolvedApparentType || (type.resolvedApparentType = getTypeWithThisArgument(type, type));
60566057 }
60576058
6058- /**
6059- * Gets the default type for a type parameter.
6060- *
6061- * If the type parameter is the result of an instantiation, this gets the instantiated
6062- * default type of its target. If the type parameter has no default type, `undefined`
6063- * is returned.
6064- *
6065- * This function *does not* perform a circularity check.
6066- */
6067- function getDefaultFromTypeParameter(typeParameter: TypeParameter): Type | undefined {
6059+ function getResolvedTypeParameterDefault(typeParameter: TypeParameter): Type | undefined {
60686060 if (!typeParameter.default) {
60696061 if (typeParameter.target) {
6070- const targetDefault = getDefaultFromTypeParameter (typeParameter.target);
6062+ const targetDefault = getResolvedTypeParameterDefault (typeParameter.target);
60716063 typeParameter.default = targetDefault ? instantiateType(targetDefault, typeParameter.mapper) : noConstraintType;
60726064 }
60736065 else {
6066+ // To block recursion, set the initial value to the resolvingDefaultType.
6067+ typeParameter.default = resolvingDefaultType;
60746068 const defaultDeclaration = typeParameter.symbol && forEach(typeParameter.symbol.declarations, decl => isTypeParameterDeclaration(decl) && decl.default);
6075- typeParameter.default = defaultDeclaration ? getTypeFromTypeNode(defaultDeclaration) : noConstraintType;
6069+ const defaultType = defaultDeclaration ? getTypeFromTypeNode(defaultDeclaration) : noConstraintType;
6070+ if (typeParameter.default === resolvingDefaultType) {
6071+ // If we have not been called recursively, set the correct default type.
6072+ typeParameter.default = defaultType;
6073+ }
60766074 }
60776075 }
6078- return typeParameter.default === noConstraintType ? undefined : typeParameter.default;
6076+ else if (typeParameter.default === resolvingDefaultType) {
6077+ // If we are called recursively for this type parameter, mark the default as circular.
6078+ typeParameter.default = circularConstraintType;
6079+ }
6080+ return typeParameter.default;
6081+ }
6082+
6083+ /**
6084+ * Gets the default type for a type parameter.
6085+ *
6086+ * If the type parameter is the result of an instantiation, this gets the instantiated
6087+ * default type of its target. If the type parameter has no default type or the default is
6088+ * circular, `undefined` is returned.
6089+ */
6090+ function getDefaultFromTypeParameter(typeParameter: TypeParameter): Type | undefined {
6091+ const defaultType = getResolvedTypeParameterDefault(typeParameter);
6092+ return defaultType !== noConstraintType && defaultType !== circularConstraintType ? defaultType : undefined;
6093+ }
6094+
6095+ function hasNonCircularTypeParameterDefault(typeParameter: TypeParameter) {
6096+ return getResolvedTypeParameterDefault(typeParameter) !== circularConstraintType;
6097+ }
6098+
6099+ /**
6100+ * Indicates whether the declaration of a typeParameter has a default type.
6101+ */
6102+ function hasTypeParameterDefault(typeParameter: TypeParameter): boolean {
6103+ return !!(typeParameter.symbol && forEach(typeParameter.symbol.declarations, decl => isTypeParameterDeclaration(decl) && decl.default));
60796104 }
60806105
60816106 /**
@@ -6361,7 +6386,7 @@ namespace ts {
63616386 let minTypeArgumentCount = 0;
63626387 if (typeParameters) {
63636388 for (let i = 0; i < typeParameters.length; i++) {
6364- if (!getDefaultFromTypeParameter (typeParameters[i])) {
6389+ if (!hasTypeParameterDefault (typeParameters[i])) {
63656390 minTypeArgumentCount = i + 1;
63666391 }
63676392 }
@@ -18478,6 +18503,9 @@ namespace ts {
1847818503 if (!hasNonCircularBaseConstraint(typeParameter)) {
1847918504 error(node.constraint, Diagnostics.Type_parameter_0_has_a_circular_constraint, typeToString(typeParameter));
1848018505 }
18506+ if (!hasNonCircularTypeParameterDefault(typeParameter)) {
18507+ error(node.default, Diagnostics.Type_parameter_0_has_a_circular_default, typeToString(typeParameter));
18508+ }
1848118509 const constraintType = getConstraintOfTypeParameter(typeParameter);
1848218510 const defaultType = getDefaultFromTypeParameter(typeParameter);
1848318511 if (constraintType && defaultType) {
0 commit comments