Fix recursive reference in type parameter default
This commit is contained in:
parent
1db762356e
commit
aaa06122b9
|
@ -281,6 +281,7 @@ namespace ts {
|
|||
|
||||
const noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
|
||||
const circularConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
|
||||
const resolvingDefaultType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
|
||||
|
||||
const markerSuperType = <TypeParameter>createType(TypeFlags.TypeParameter);
|
||||
const markerSubType = <TypeParameter>createType(TypeFlags.TypeParameter);
|
||||
|
@ -6055,27 +6056,51 @@ namespace ts {
|
|||
return type.resolvedApparentType || (type.resolvedApparentType = getTypeWithThisArgument(type, type));
|
||||
}
|
||||
|
||||
function getResolvedTypeParameterDefault(typeParameter: TypeParameter): Type | undefined {
|
||||
if (!typeParameter.default) {
|
||||
if (typeParameter.target) {
|
||||
const targetDefault = getResolvedTypeParameterDefault(typeParameter.target);
|
||||
typeParameter.default = targetDefault ? instantiateType(targetDefault, typeParameter.mapper) : noConstraintType;
|
||||
}
|
||||
else {
|
||||
// To block recursion, set the initial value to the resolvingDefaultType.
|
||||
typeParameter.default = resolvingDefaultType;
|
||||
const defaultDeclaration = typeParameter.symbol && forEach(typeParameter.symbol.declarations, decl => isTypeParameterDeclaration(decl) && decl.default);
|
||||
const defaultType = defaultDeclaration ? getTypeFromTypeNode(defaultDeclaration) : noConstraintType;
|
||||
if (typeParameter.default === resolvingDefaultType) {
|
||||
// If we have not been called recursively, set the correct default type.
|
||||
typeParameter.default = defaultType;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (typeParameter.default === resolvingDefaultType) {
|
||||
// If we are called recursively for this type parameter, mark the default as circular.
|
||||
typeParameter.default = circularConstraintType;
|
||||
}
|
||||
return typeParameter.default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default type for a type parameter.
|
||||
*
|
||||
* If the type parameter is the result of an instantiation, this gets the instantiated
|
||||
* default type of its target. If the type parameter has no default type, `undefined`
|
||||
* is returned.
|
||||
*
|
||||
* This function *does not* perform a circularity check.
|
||||
* default type of its target. If the type parameter has no default type or the default is
|
||||
* circular, `undefined` is returned.
|
||||
*/
|
||||
function getDefaultFromTypeParameter(typeParameter: TypeParameter): Type | undefined {
|
||||
if (!typeParameter.default) {
|
||||
if (typeParameter.target) {
|
||||
const targetDefault = getDefaultFromTypeParameter(typeParameter.target);
|
||||
typeParameter.default = targetDefault ? instantiateType(targetDefault, typeParameter.mapper) : noConstraintType;
|
||||
}
|
||||
else {
|
||||
const defaultDeclaration = typeParameter.symbol && forEach(typeParameter.symbol.declarations, decl => isTypeParameterDeclaration(decl) && decl.default);
|
||||
typeParameter.default = defaultDeclaration ? getTypeFromTypeNode(defaultDeclaration) : noConstraintType;
|
||||
}
|
||||
}
|
||||
return typeParameter.default === noConstraintType ? undefined : typeParameter.default;
|
||||
const defaultType = getResolvedTypeParameterDefault(typeParameter);
|
||||
return defaultType !== noConstraintType && defaultType !== circularConstraintType ? defaultType : undefined;
|
||||
}
|
||||
|
||||
function hasNonCircularTypeParameterDefault(typeParameter: TypeParameter) {
|
||||
return getResolvedTypeParameterDefault(typeParameter) !== circularConstraintType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the declaration of a typeParameter has a default type.
|
||||
*/
|
||||
function hasTypeParameterDefault(typeParameter: TypeParameter): boolean {
|
||||
return !!(typeParameter.symbol && forEach(typeParameter.symbol.declarations, decl => isTypeParameterDeclaration(decl) && decl.default));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -6361,7 +6386,7 @@ namespace ts {
|
|||
let minTypeArgumentCount = 0;
|
||||
if (typeParameters) {
|
||||
for (let i = 0; i < typeParameters.length; i++) {
|
||||
if (!getDefaultFromTypeParameter(typeParameters[i])) {
|
||||
if (!hasTypeParameterDefault(typeParameters[i])) {
|
||||
minTypeArgumentCount = i + 1;
|
||||
}
|
||||
}
|
||||
|
@ -18478,6 +18503,9 @@ namespace ts {
|
|||
if (!hasNonCircularBaseConstraint(typeParameter)) {
|
||||
error(node.constraint, Diagnostics.Type_parameter_0_has_a_circular_constraint, typeToString(typeParameter));
|
||||
}
|
||||
if (!hasNonCircularTypeParameterDefault(typeParameter)) {
|
||||
error(node.default, Diagnostics.Type_parameter_0_has_a_circular_default, typeToString(typeParameter));
|
||||
}
|
||||
const constraintType = getConstraintOfTypeParameter(typeParameter);
|
||||
const defaultType = getDefaultFromTypeParameter(typeParameter);
|
||||
if (constraintType && defaultType) {
|
||||
|
|
|
@ -2224,6 +2224,10 @@
|
|||
"category": "Error",
|
||||
"code": 2715
|
||||
},
|
||||
"Type parameter '{0}' has a circular default.": {
|
||||
"category": "Error",
|
||||
"code": 2716
|
||||
},
|
||||
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
|
|
|
@ -487,7 +487,10 @@ const t03c00 = (<t03<number>>x).a;
|
|||
const t03c01 = (<t03<1>>x).a;
|
||||
const t03c02 = (<t03<number, number>>x).a;
|
||||
const t03c03 = (<t03<1, 1>>x).a;
|
||||
const t03c04 = (<t03<number, 1>>x).a;
|
||||
const t03c04 = (<t03<number, 1>>x).a;
|
||||
|
||||
// https://github.com/Microsoft/TypeScript/issues/16221
|
||||
interface SelfReference<T = SelfReference<string>> {}
|
||||
|
||||
//// [genericDefaults.js]
|
||||
// no inference
|
||||
|
@ -1024,3 +1027,5 @@ declare const t03c01: [1, 1];
|
|||
declare const t03c02: [number, number];
|
||||
declare const t03c03: [1, 1];
|
||||
declare const t03c04: [number, 1];
|
||||
interface SelfReference<T = SelfReference<string>> {
|
||||
}
|
||||
|
|
|
@ -2291,3 +2291,9 @@ const t03c04 = (<t03<number, 1>>x).a;
|
|||
>x : Symbol(x, Decl(genericDefaults.ts, 13, 13))
|
||||
>a : Symbol(a, Decl(genericDefaults.ts, 483, 47))
|
||||
|
||||
// https://github.com/Microsoft/TypeScript/issues/16221
|
||||
interface SelfReference<T = SelfReference<string>> {}
|
||||
>SelfReference : Symbol(SelfReference, Decl(genericDefaults.ts, 488, 37))
|
||||
>T : Symbol(T, Decl(genericDefaults.ts, 491, 24))
|
||||
>SelfReference : Symbol(SelfReference, Decl(genericDefaults.ts, 488, 37))
|
||||
|
||||
|
|
|
@ -2643,3 +2643,9 @@ const t03c04 = (<t03<number, 1>>x).a;
|
|||
>x : any
|
||||
>a : [number, 1]
|
||||
|
||||
// https://github.com/Microsoft/TypeScript/issues/16221
|
||||
interface SelfReference<T = SelfReference<string>> {}
|
||||
>SelfReference : SelfReference<T>
|
||||
>T : T
|
||||
>SelfReference : SelfReference<T>
|
||||
|
||||
|
|
|
@ -21,9 +21,10 @@ tests/cases/compiler/genericDefaultsErrors.ts(33,15): error TS2707: Generic type
|
|||
tests/cases/compiler/genericDefaultsErrors.ts(36,15): error TS2707: Generic type 'i09<T, U, V>' requires between 2 and 3 type arguments.
|
||||
tests/cases/compiler/genericDefaultsErrors.ts(38,20): error TS2304: Cannot find name 'T'.
|
||||
tests/cases/compiler/genericDefaultsErrors.ts(38,20): error TS4033: Property 'x' of exported interface has or is using private name 'T'.
|
||||
tests/cases/compiler/genericDefaultsErrors.ts(42,29): error TS2715: Type parameter 'T' has a circular default.
|
||||
|
||||
|
||||
==== tests/cases/compiler/genericDefaultsErrors.ts (21 errors) ====
|
||||
==== tests/cases/compiler/genericDefaultsErrors.ts (22 errors) ====
|
||||
declare const x: any;
|
||||
|
||||
declare function f03<T extends string = number>(): void; // error
|
||||
|
@ -106,4 +107,9 @@ tests/cases/compiler/genericDefaultsErrors.ts(38,20): error TS4033: Property 'x'
|
|||
!!! error TS2304: Cannot find name 'T'.
|
||||
~
|
||||
!!! error TS4033: Property 'x' of exported interface has or is using private name 'T'.
|
||||
interface i10<T = number> {}
|
||||
interface i10<T = number> {}
|
||||
|
||||
// https://github.com/Microsoft/TypeScript/issues/16221
|
||||
interface SelfReference<T = SelfReference> {}
|
||||
~~~~~~~~~~~~~
|
||||
!!! error TS2715: Type parameter 'T' has a circular default.
|
|
@ -37,7 +37,10 @@ type i09t03 = i09<1, 2, 3>; // ok
|
|||
type i09t04 = i09<1, 2, 3, 4>; // error
|
||||
|
||||
interface i10 { x: T; } // error
|
||||
interface i10<T = number> {}
|
||||
interface i10<T = number> {}
|
||||
|
||||
// https://github.com/Microsoft/TypeScript/issues/16221
|
||||
interface SelfReference<T = SelfReference> {}
|
||||
|
||||
//// [genericDefaultsErrors.js]
|
||||
f11(); // ok
|
||||
|
|
|
@ -136,3 +136,9 @@ interface i10<T = number> {}
|
|||
>i10 : Symbol(i10, Decl(genericDefaultsErrors.ts, 35, 30), Decl(genericDefaultsErrors.ts, 37, 23))
|
||||
>T : Symbol(T, Decl(genericDefaultsErrors.ts, 38, 14))
|
||||
|
||||
// https://github.com/Microsoft/TypeScript/issues/16221
|
||||
interface SelfReference<T = SelfReference> {}
|
||||
>SelfReference : Symbol(SelfReference, Decl(genericDefaultsErrors.ts, 38, 28))
|
||||
>T : Symbol(T, Decl(genericDefaultsErrors.ts, 41, 24))
|
||||
>SelfReference : Symbol(SelfReference, Decl(genericDefaultsErrors.ts, 38, 28))
|
||||
|
||||
|
|
|
@ -145,3 +145,9 @@ interface i10<T = number> {}
|
|||
>i10 : i10<T>
|
||||
>T : T
|
||||
|
||||
// https://github.com/Microsoft/TypeScript/issues/16221
|
||||
interface SelfReference<T = SelfReference> {}
|
||||
>SelfReference : SelfReference<T>
|
||||
>T : T
|
||||
>SelfReference : SelfReference<T>
|
||||
|
||||
|
|
|
@ -487,4 +487,7 @@ const t03c00 = (<t03<number>>x).a;
|
|||
const t03c01 = (<t03<1>>x).a;
|
||||
const t03c02 = (<t03<number, number>>x).a;
|
||||
const t03c03 = (<t03<1, 1>>x).a;
|
||||
const t03c04 = (<t03<number, 1>>x).a;
|
||||
const t03c04 = (<t03<number, 1>>x).a;
|
||||
|
||||
// https://github.com/Microsoft/TypeScript/issues/16221
|
||||
interface SelfReference<T = SelfReference<string>> {}
|
|
@ -38,4 +38,7 @@ type i09t03 = i09<1, 2, 3>; // ok
|
|||
type i09t04 = i09<1, 2, 3, 4>; // error
|
||||
|
||||
interface i10 { x: T; } // error
|
||||
interface i10<T = number> {}
|
||||
interface i10<T = number> {}
|
||||
|
||||
// https://github.com/Microsoft/TypeScript/issues/16221
|
||||
interface SelfReference<T = SelfReference> {}
|
Loading…
Reference in a new issue