Skip to content

Commit ca16ba8

Browse files
committed
Added comments and additional circularity tests
1 parent 25cb02e commit ca16ba8

8 files changed

+614
-184
lines changed

src/compiler/checker.ts

+67-19
Original file line numberDiff line numberDiff line change
@@ -4840,15 +4840,60 @@ namespace ts {
48404840
}
48414841
}
48424842

4843-
function getDefaultOfTypeParameter(typeParameter: TypeParameter): Type {
4843+
/**
4844+
* Gets the default type for a type parameter.
4845+
*
4846+
* If the type parameter is the result of an instantiation, this gets the instantiated
4847+
* default type of its target. If the type parameter has no default type, `undefined`
4848+
* is returned.
4849+
*
4850+
* This function *does not* perform a circularity check.
4851+
*/
4852+
function getDefaultFromTypeParameter(typeParameter: TypeParameter): Type | undefined {
4853+
if (!typeParameter.default) {
4854+
if (typeParameter.target) {
4855+
const targetDefault = getDefaultFromTypeParameter(typeParameter.target);
4856+
typeParameter.default = targetDefault ? instantiateType(targetDefault, typeParameter.mapper) : noConstraintOrDefaultType;
4857+
}
4858+
else {
4859+
const defaultDeclaration = typeParameter.symbol && forEach(typeParameter.symbol.declarations, decl => isTypeParameter(decl) && decl.default);
4860+
typeParameter.default = defaultDeclaration ? getTypeFromTypeNode(defaultDeclaration) : noConstraintOrDefaultType;
4861+
}
4862+
}
4863+
return typeParameter.default === noConstraintOrDefaultType ? undefined : typeParameter.default;
4864+
}
4865+
4866+
/**
4867+
* Gets the default type for a type parameter.
4868+
*
4869+
* If the type parameter is the result of an instantiation, this gets the instantiated
4870+
* default type of its target. If the type parameter has no default type, or if the default
4871+
* type circularly references the type parameter, `undefined` is returned.
4872+
*
4873+
* This function *does* perform a circularity check.
4874+
*/
4875+
function getDefaultOfTypeParameter(typeParameter: TypeParameter): Type | undefined {
48444876
return hasNonCircularDefault(typeParameter) ? getDefaultFromTypeParameter(typeParameter) : undefined;
48454877
}
48464878

4847-
function hasNonCircularDefault(type: TypeParameter) {
4848-
return getResolvedDefault(type) !== circularConstraintOrDefaultType;
4879+
/**
4880+
* Determines whether a type parameter has a non-circular default type.
4881+
*
4882+
* Note that this function also returns `true` if a type parameter *does not* have a
4883+
* default type.
4884+
*/
4885+
function hasNonCircularDefault(typeParameter: TypeParameter): boolean {
4886+
return getResolvedDefault(typeParameter) !== circularConstraintOrDefaultType;
48494887
}
48504888

4851-
function getResolvedDefault(typeParameter: TypeParameter) {
4889+
/**
4890+
* Resolves the default type of a type parameter.
4891+
*
4892+
* If the type parameter has no default, the `noConstraintOrDefaultType` singleton is
4893+
* returned. If the type parameter has a circular default, the
4894+
* `circularConstraintOrDefaultType` singleton is returned.
4895+
*/
4896+
function getResolvedDefault(typeParameter: TypeParameter): Type {
48524897
if (!typeParameter.resolvedDefault) {
48534898
if (!pushTypeResolution(typeParameter, TypeSystemPropertyName.ResolvedDefault)) {
48544899
return circularConstraintOrDefaultType;
@@ -4863,6 +4908,12 @@ namespace ts {
48634908
return typeParameter.resolvedDefault;
48644909
}
48654910

4911+
/**
4912+
* Recursively resolves the default type for a type.
4913+
*
4914+
* If the type is a union or intersection type and any of its constituents is a circular
4915+
* reference, the `circularConstraintOrDefaultType` singleton is returned.
4916+
*/
48664917
function getResolvedDefaultWorker(type: Type): Type {
48674918
if (type.flags & TypeFlags.TypeParameter) {
48684919
return getResolvedDefault(<TypeParameter>type);
@@ -5173,6 +5224,14 @@ namespace ts {
51735224
return minTypeArgumentCount;
51745225
}
51755226

5227+
/**
5228+
* Fill in default types for unsupplied type arguments. If `typeArguments` is undefined
5229+
* when a default type is supplied, a new array will be created and returned.
5230+
*
5231+
* @param typeArguments The supplied type arguments.
5232+
* @param typeParameters The requested type parameters.
5233+
* @param minTypeArgumentCount The minimum number of required type arguments.
5234+
*/
51765235
function fillMissingTypeArguments(typeArguments: Type[] | undefined, typeParameters: TypeParameter[] | undefined, minTypeArgumentCount: number) {
51775236
const numTypeParameters = typeParameters ? typeParameters.length : 0;
51785237
if (numTypeParameters) {
@@ -5488,20 +5547,6 @@ namespace ts {
54885547
return typeParameter.constraint === noConstraintOrDefaultType ? undefined : typeParameter.constraint;
54895548
}
54905549

5491-
function getDefaultFromTypeParameter(typeParameter: TypeParameter): Type | undefined {
5492-
if (!typeParameter.default) {
5493-
if (typeParameter.target) {
5494-
const targetDefault = getDefaultFromTypeParameter(typeParameter.target);
5495-
typeParameter.default = targetDefault ? instantiateType(targetDefault, typeParameter.mapper) : noConstraintOrDefaultType;
5496-
}
5497-
else {
5498-
const defaultDeclaration = typeParameter.symbol && forEach(typeParameter.symbol.declarations, decl => isTypeParameter(decl) && decl.default);
5499-
typeParameter.default = defaultDeclaration ? getTypeFromTypeNode(defaultDeclaration) : noConstraintOrDefaultType;
5500-
}
5501-
}
5502-
return typeParameter.default === noConstraintOrDefaultType ? undefined : typeParameter.default;
5503-
}
5504-
55055550
function getParentSymbolOfTypeParameter(typeParameter: TypeParameter): Symbol {
55065551
return getSymbolOfNode(getDeclarationOfKind(typeParameter.symbol, SyntaxKind.TypeParameter).parent);
55075552
}
@@ -13535,6 +13580,7 @@ namespace ts {
1353513580
? createInferenceContext(originalCandidate, /*inferUnionTypes*/ false)
1353613581
: undefined;
1353713582

13583+
// fix each supplied type argument in the inference context
1353813584
if (typeArguments) {
1353913585
for (let i = 0; i < typeArguments.length; i++) {
1354013586
inferenceContext.inferredTypes[i] = getTypeFromTypeNode(typeArguments[i]);
@@ -13545,8 +13591,10 @@ namespace ts {
1354513591
while (true) {
1354613592
candidate = originalCandidate;
1354713593
if (candidate.typeParameters) {
13548-
typeArgumentsAreValid = typeArguments ? checkTypeArguments(candidate, typeArguments, inferenceContext.inferredTypes, /*reportErrors*/ false) : true;
13594+
// Check any supplied type arguments against the candidate.
13595+
typeArgumentsAreValid = !typeArguments || checkTypeArguments(candidate, typeArguments, inferenceContext.inferredTypes, /*reportErrors*/ false);
1354913596
if (typeArgumentsAreValid) {
13597+
// Infer any unsupplied type arguments for the candidate.
1355013598
inferTypeArguments(node, candidate, args, excludeArgument, inferenceContext);
1355113599
typeArgumentsAreValid = inferenceContext.failedTypeParameterIndex === undefined;
1355213600
}

tests/baselines/reference/genericDefaults.js

+80
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,28 @@ const f03c06 = f03<number, number>();
4242
const f03c07 = f03<number, number>(1);
4343
const f03c08 = f03<number, number>(1, 2);
4444

45+
declare function f04<T, U = T | { a: number }>(a?: T, b?: U): [T, U];
46+
const f04c00 = f04();
47+
const f04c01 = f04(1);
48+
const f04c02 = f04(1, 1);
49+
const f04c03 = f04<number>();
50+
const f04c04 = f04<number>(1);
51+
const f04c05 = f04<number>(1, 2);
52+
const f04c06 = f04<number, number>();
53+
const f04c07 = f04<number, number>(1);
54+
const f04c08 = f04<number, number>(1, 2);
55+
56+
declare function f05<T, U = T & { a: number }>(a?: T, b?: U): [T, U];
57+
const f05c00 = f05();
58+
const f05c01 = f05(1);
59+
const f05c02 = f05(1, 1);
60+
const f05c03 = f05<number>();
61+
const f05c04 = f05<number>(1);
62+
const f05c05 = f05<number>(1, 2);
63+
const f05c06 = f05<number, number>();
64+
const f05c07 = f05<number, number>(1);
65+
const f05c08 = f05<number, number>(1, 2);
66+
4567
interface i00<T = number> { a: T; }
4668
const i00c00 = (<i00>x).a;
4769
const i00c01 = (<i00<number>>x).a;
@@ -120,6 +142,24 @@ var f03c05 = f03(1, 2);
120142
var f03c06 = f03();
121143
var f03c07 = f03(1);
122144
var f03c08 = f03(1, 2);
145+
var f04c00 = f04();
146+
var f04c01 = f04(1);
147+
var f04c02 = f04(1, 1);
148+
var f04c03 = f04();
149+
var f04c04 = f04(1);
150+
var f04c05 = f04(1, 2);
151+
var f04c06 = f04();
152+
var f04c07 = f04(1);
153+
var f04c08 = f04(1, 2);
154+
var f05c00 = f05();
155+
var f05c01 = f05(1);
156+
var f05c02 = f05(1, 1);
157+
var f05c03 = f05();
158+
var f05c04 = f05(1);
159+
var f05c05 = f05(1, 2);
160+
var f05c06 = f05();
161+
var f05c07 = f05(1);
162+
var f05c08 = f05(1, 2);
123163
var i00c00 = x.a;
124164
var i00c01 = x.a;
125165
var i01c00 = x.a;
@@ -187,6 +227,46 @@ declare const f03c05: [number, number];
187227
declare const f03c06: [number, number];
188228
declare const f03c07: [number, number];
189229
declare const f03c08: [number, number];
230+
declare function f04<T, U = T | {
231+
a: number;
232+
}>(a?: T, b?: U): [T, U];
233+
declare const f04c00: [{}, {} | {
234+
a: number;
235+
}];
236+
declare const f04c01: [number, number | {
237+
a: number;
238+
}];
239+
declare const f04c02: [number, number];
240+
declare const f04c03: [number, number | {
241+
a: number;
242+
}];
243+
declare const f04c04: [number, number | {
244+
a: number;
245+
}];
246+
declare const f04c05: [number, number];
247+
declare const f04c06: [number, number];
248+
declare const f04c07: [number, number];
249+
declare const f04c08: [number, number];
250+
declare function f05<T, U = T & {
251+
a: number;
252+
}>(a?: T, b?: U): [T, U];
253+
declare const f05c00: [{}, {} & {
254+
a: number;
255+
}];
256+
declare const f05c01: [number, number & {
257+
a: number;
258+
}];
259+
declare const f05c02: [number, number];
260+
declare const f05c03: [number, number & {
261+
a: number;
262+
}];
263+
declare const f05c04: [number, number & {
264+
a: number;
265+
}];
266+
declare const f05c05: [number, number];
267+
declare const f05c06: [number, number];
268+
declare const f05c07: [number, number];
269+
declare const f05c08: [number, number];
190270
interface i00<T = number> {
191271
a: T;
192272
}

0 commit comments

Comments
 (0)