@@ -281,6 +281,7 @@ namespace ts {
281
281
282
282
const noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
283
283
const circularConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
284
+ const resolvingDefaultType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
284
285
285
286
const markerSuperType = <TypeParameter>createType(TypeFlags.TypeParameter);
286
287
const markerSubType = <TypeParameter>createType(TypeFlags.TypeParameter);
@@ -6055,27 +6056,51 @@ namespace ts {
6055
6056
return type.resolvedApparentType || (type.resolvedApparentType = getTypeWithThisArgument(type, type));
6056
6057
}
6057
6058
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 {
6068
6060
if (!typeParameter.default) {
6069
6061
if (typeParameter.target) {
6070
- const targetDefault = getDefaultFromTypeParameter (typeParameter.target);
6062
+ const targetDefault = getResolvedTypeParameterDefault (typeParameter.target);
6071
6063
typeParameter.default = targetDefault ? instantiateType(targetDefault, typeParameter.mapper) : noConstraintType;
6072
6064
}
6073
6065
else {
6066
+ // To block recursion, set the initial value to the resolvingDefaultType.
6067
+ typeParameter.default = resolvingDefaultType;
6074
6068
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
+ }
6076
6074
}
6077
6075
}
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));
6079
6104
}
6080
6105
6081
6106
/**
@@ -6361,7 +6386,7 @@ namespace ts {
6361
6386
let minTypeArgumentCount = 0;
6362
6387
if (typeParameters) {
6363
6388
for (let i = 0; i < typeParameters.length; i++) {
6364
- if (!getDefaultFromTypeParameter (typeParameters[i])) {
6389
+ if (!hasTypeParameterDefault (typeParameters[i])) {
6365
6390
minTypeArgumentCount = i + 1;
6366
6391
}
6367
6392
}
@@ -18478,6 +18503,9 @@ namespace ts {
18478
18503
if (!hasNonCircularBaseConstraint(typeParameter)) {
18479
18504
error(node.constraint, Diagnostics.Type_parameter_0_has_a_circular_constraint, typeToString(typeParameter));
18480
18505
}
18506
+ if (!hasNonCircularTypeParameterDefault(typeParameter)) {
18507
+ error(node.default, Diagnostics.Type_parameter_0_has_a_circular_default, typeToString(typeParameter));
18508
+ }
18481
18509
const constraintType = getConstraintOfTypeParameter(typeParameter);
18482
18510
const defaultType = getDefaultFromTypeParameter(typeParameter);
18483
18511
if (constraintType && defaultType) {
0 commit comments