Skip to content

Commit 4331293

Browse files
committed
Implement optional type parameters
1 parent d7f4874 commit 4331293

27 files changed

+1837
-2226
lines changed

src/ast.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,12 +181,14 @@ export abstract class Node {
181181
static createTypeParameter(
182182
name: IdentifierExpression,
183183
extendsType: TypeNode | null,
184+
defaultType: TypeNode | null,
184185
range: Range
185186
): TypeParameterNode {
186187
var elem = new TypeParameterNode();
187188
elem.range = range;
188189
elem.name = name; name.parent = elem;
189190
elem.extendsType = extendsType; if (extendsType) extendsType.parent = elem;
191+
elem.defaultType = defaultType; if (defaultType) defaultType.parent = elem;
190192
return elem;
191193
}
192194

@@ -1070,6 +1072,8 @@ export class TypeParameterNode extends Node {
10701072
name: IdentifierExpression;
10711073
/** Extended type reference, if any. */
10721074
extendsType: TypeNode | null; // can't be a function
1075+
/** Default type if omitted, if any. */
1076+
defaultType: TypeNode | null; // can't be a function
10731077
}
10741078

10751079
/** Represents the kind of a parameter. */

src/compiler.ts

Lines changed: 59 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,8 @@ import {
162162
writeI32,
163163
writeI64,
164164
writeF32,
165-
writeF64
165+
writeF64,
166+
uniqueMap
166167
} from "./util";
167168

168169
/** Compilation target. */
@@ -619,7 +620,7 @@ export class Compiler extends DiagnosticEmitter {
619620
(noTreeShaking || (isEntry && statement.is(CommonFlags.EXPORT))) &&
620621
!(<ClassDeclaration>statement).isGeneric
621622
) {
622-
this.compileClassDeclaration(<ClassDeclaration>statement, [], null);
623+
this.compileClassDeclaration(<ClassDeclaration>statement, []);
623624
}
624625
break;
625626
}
@@ -958,16 +959,15 @@ export class Compiler extends DiagnosticEmitter {
958959
/** Compiles a top-level function given its declaration. */
959960
compileFunctionDeclaration(
960961
declaration: FunctionDeclaration,
961-
typeArguments: TypeNode[],
962-
contextualTypeArguments: Map<string,Type> | null = null
962+
typeArguments: TypeNode[]
963963
): Function | null {
964964
var element = assert(this.program.elementsLookup.get(declaration.fileLevelInternalName));
965965
assert(element.kind == ElementKind.FUNCTION_PROTOTYPE);
966966
return this.compileFunctionUsingTypeArguments( // reports
967967
<FunctionPrototype>element,
968968
typeArguments,
969-
contextualTypeArguments,
970-
null, // no outer scope (is top level)
969+
uniqueMap<string,Type>(),
970+
null,
971971
(<FunctionPrototype>element).declaration.name
972972
);
973973
}
@@ -976,7 +976,7 @@ export class Compiler extends DiagnosticEmitter {
976976
compileFunctionUsingTypeArguments(
977977
prototype: FunctionPrototype,
978978
typeArguments: TypeNode[],
979-
contextualTypeArguments: Map<string,Type> | null,
979+
contextualTypeArguments: Map<string,Type>,
980980
outerScope: Flow | null,
981981
reportNode: Node
982982
): Function | null {
@@ -1234,7 +1234,11 @@ export class Compiler extends DiagnosticEmitter {
12341234
(<ClassPrototype>element).is(CommonFlags.EXPORT)
12351235
) && !(<ClassPrototype>element).is(CommonFlags.GENERIC)
12361236
) {
1237-
this.compileClassUsingTypeArguments(<ClassPrototype>element, []);
1237+
this.compileClassUsingTypeArguments(
1238+
<ClassPrototype>element,
1239+
[],
1240+
uniqueMap<string,Type>()
1241+
);
12381242
}
12391243
break;
12401244
}
@@ -1252,8 +1256,8 @@ export class Compiler extends DiagnosticEmitter {
12521256
this.compileFunctionUsingTypeArguments(
12531257
<FunctionPrototype>element,
12541258
[],
1255-
null, // no contextual type arguments
1256-
null, // no outer scope
1259+
uniqueMap<string,Type>(),
1260+
null,
12571261
(<FunctionPrototype>element).declaration.name
12581262
);
12591263
}
@@ -1286,7 +1290,11 @@ export class Compiler extends DiagnosticEmitter {
12861290
switch (element.kind) {
12871291
case ElementKind.CLASS_PROTOTYPE: {
12881292
if (!(<ClassPrototype>element).is(CommonFlags.GENERIC)) {
1289-
this.compileClassUsingTypeArguments(<ClassPrototype>element, []);
1293+
this.compileClassUsingTypeArguments(
1294+
<ClassPrototype>element,
1295+
[],
1296+
uniqueMap<string,Type>()
1297+
);
12901298
}
12911299
break;
12921300
}
@@ -1302,8 +1310,8 @@ export class Compiler extends DiagnosticEmitter {
13021310
this.compileFunctionUsingTypeArguments(
13031311
<FunctionPrototype>element,
13041312
[],
1305-
null, // no contextual type arguments
1306-
null, // no outer scope
1313+
uniqueMap<string,Type>(),
1314+
null,
13071315
(<FunctionPrototype>element).declaration.name
13081316
);
13091317
}
@@ -1325,23 +1333,22 @@ export class Compiler extends DiagnosticEmitter {
13251333

13261334
compileClassDeclaration(
13271335
declaration: ClassDeclaration,
1328-
typeArguments: TypeNode[],
1329-
contextualTypeArguments: Map<string,Type> | null = null
1336+
typeArguments: TypeNode[]
13301337
): void {
13311338
var element = assert(this.program.elementsLookup.get(declaration.fileLevelInternalName));
13321339
assert(element.kind == ElementKind.CLASS_PROTOTYPE);
13331340
this.compileClassUsingTypeArguments(
13341341
<ClassPrototype>element,
13351342
typeArguments,
1336-
contextualTypeArguments,
1343+
uniqueMap<string,Type>(),
13371344
declaration
13381345
);
13391346
}
13401347

13411348
compileClassUsingTypeArguments(
13421349
prototype: ClassPrototype,
13431350
typeArguments: TypeNode[],
1344-
contextualTypeArguments: Map<string,Type> | null = null,
1351+
contextualTypeArguments: Map<string,Type>,
13451352
alternativeReportNode: Node | null = null
13461353
): void {
13471354
var instance = this.resolver.resolveClassInclTypeArguments(
@@ -1372,7 +1379,9 @@ export class Compiler extends DiagnosticEmitter {
13721379
) {
13731380
this.compileFunctionUsingTypeArguments(
13741381
<FunctionPrototype>element,
1375-
[], null, null,
1382+
[],
1383+
uniqueMap<string,Type>(),
1384+
null,
13761385
(<FunctionPrototype>element).declaration.name
13771386
);
13781387
}
@@ -1383,15 +1392,19 @@ export class Compiler extends DiagnosticEmitter {
13831392
if (getter) {
13841393
this.compileFunctionUsingTypeArguments(
13851394
getter,
1386-
[], null, null,
1395+
[],
1396+
uniqueMap<string,Type>(),
1397+
null,
13871398
getter.declaration.name
13881399
);
13891400
}
13901401
let setter = (<Property>element).setterPrototype;
13911402
if (setter) {
13921403
this.compileFunctionUsingTypeArguments(
13931404
setter,
1394-
[], null, null,
1405+
[],
1406+
uniqueMap<string,Type>(),
1407+
null,
13951408
setter.declaration.name
13961409
);
13971410
}
@@ -1413,8 +1426,8 @@ export class Compiler extends DiagnosticEmitter {
14131426
this.compileFunctionUsingTypeArguments(
14141427
<FunctionPrototype>element,
14151428
[],
1416-
instance.contextualTypeArguments,
1417-
null, // no outer scope
1429+
uniqueMap<string,Type>(instance.contextualTypeArguments),
1430+
null,
14181431
(<FunctionPrototype>element).declaration.name
14191432
);
14201433
}
@@ -1429,15 +1442,19 @@ export class Compiler extends DiagnosticEmitter {
14291442
if (getter) {
14301443
this.compileFunctionUsingTypeArguments(
14311444
getter,
1432-
[], instance.contextualTypeArguments, null,
1445+
[],
1446+
uniqueMap<string,Type>(instance.contextualTypeArguments),
1447+
null,
14331448
getter.declaration.name
14341449
);
14351450
}
14361451
let setter = (<Property>element).setterPrototype;
14371452
if (setter) {
14381453
this.compileFunctionUsingTypeArguments(
14391454
setter,
1440-
[], instance.contextualTypeArguments, null,
1455+
[],
1456+
uniqueMap<string,Type>(instance.contextualTypeArguments),
1457+
null,
14411458
setter.declaration.name
14421459
);
14431460
}
@@ -5014,7 +5031,7 @@ export class Compiler extends DiagnosticEmitter {
50145031
instance = this.resolver.resolveFunctionInclTypeArguments(
50155032
prototype,
50165033
typeArguments,
5017-
this.currentFunction.flow.contextualTypeArguments,
5034+
uniqueMap<string,Type>(this.currentFunction.flow.contextualTypeArguments),
50185035
expression
50195036
);
50205037

@@ -5088,7 +5105,7 @@ export class Compiler extends DiagnosticEmitter {
50885105
instance = this.resolver.resolveFunction(
50895106
prototype,
50905107
resolvedTypeArguments,
5091-
this.currentFunction.flow.contextualTypeArguments
5108+
uniqueMap<string,Type>(this.currentFunction.flow.contextualTypeArguments)
50925109
);
50935110
if (!instance) return this.module.createUnreachable();
50945111
return this.makeCallDirect(instance, argumentExprs);
@@ -5098,11 +5115,7 @@ export class Compiler extends DiagnosticEmitter {
50985115

50995116
// otherwise resolve the non-generic call as usual
51005117
} else {
5101-
instance = this.resolver.resolveFunction(
5102-
prototype,
5103-
null,
5104-
this.currentFunction.flow.contextualTypeArguments
5105-
);
5118+
instance = this.resolver.resolveFunction(prototype, null);
51065119
}
51075120
if (!instance) return this.module.createUnreachable();
51085121

@@ -5241,7 +5254,7 @@ export class Compiler extends DiagnosticEmitter {
52415254
typeArguments = this.resolver.resolveTypeArguments(
52425255
assert(prototype.declaration.typeParameters),
52435256
typeArgumentNodes,
5244-
this.currentFunction.flow.contextualTypeArguments,
5257+
uniqueMap<string,Type>(this.currentFunction.flow.contextualTypeArguments),
52455258
expression
52465259
);
52475260
}
@@ -5932,7 +5945,7 @@ export class Compiler extends DiagnosticEmitter {
59325945
var instance = this.compileFunctionUsingTypeArguments(
59335946
prototype,
59345947
[],
5935-
flow.contextualTypeArguments,
5948+
uniqueMap<string,Type>(flow.contextualTypeArguments),
59365949
flow,
59375950
declaration
59385951
);
@@ -6093,7 +6106,7 @@ export class Compiler extends DiagnosticEmitter {
60936106
let instance = this.resolver.resolveFunction(
60946107
<FunctionPrototype>target,
60956108
null,
6096-
currentFunction.flow.contextualTypeArguments
6109+
uniqueMap<string,Type>(currentFunction.flow.contextualTypeArguments)
60976110
);
60986111
if (!(instance && this.compileFunction(instance))) return module.createUnreachable();
60996112
let index = this.ensureFunctionTableEntry(instance);
@@ -6438,7 +6451,11 @@ export class Compiler extends DiagnosticEmitter {
64386451

64396452
// create the Array segment and return a pointer to it
64406453
var arrayPrototype = assert(program.arrayPrototype);
6441-
var arrayInstance = assert(this.resolver.resolveClass(arrayPrototype, [ elementType ]));
6454+
var arrayInstance = assert(this.resolver.resolveClass(
6455+
arrayPrototype,
6456+
[ elementType ],
6457+
uniqueMap<string,Type>()
6458+
));
64426459
var arrayHeaderSize = (arrayInstance.currentMemoryOffset + 7) & ~7;
64436460
if (hasGC) {
64446461
buf = new Uint8Array(gcHeaderSize + arrayHeaderSize);
@@ -6506,9 +6523,11 @@ export class Compiler extends DiagnosticEmitter {
65066523

65076524
// otherwise obtain the array type
65086525
var arrayPrototype = assert(this.program.arrayPrototype);
6509-
if (!arrayPrototype || arrayPrototype.kind != ElementKind.CLASS_PROTOTYPE) return module.createUnreachable();
6510-
var arrayInstance = this.resolver.resolveClass(<ClassPrototype>arrayPrototype, [ elementType ]);
6511-
if (!arrayInstance) return module.createUnreachable();
6526+
var arrayInstance = assert(this.resolver.resolveClass(
6527+
<ClassPrototype>arrayPrototype,
6528+
[ elementType ],
6529+
uniqueMap<string,Type>()
6530+
));
65126531
var arrayType = arrayInstance.type;
65136532

65146533
// and compile an explicit instantiation
@@ -6660,13 +6679,13 @@ export class Compiler extends DiagnosticEmitter {
66606679
classInstance = this.resolver.resolveClass(
66616680
classPrototype,
66626681
classReference.typeArguments,
6663-
currentFunction.flow.contextualTypeArguments
6682+
uniqueMap<string,Type>(currentFunction.flow.contextualTypeArguments)
66646683
);
66656684
} else {
66666685
classInstance = this.resolver.resolveClassInclTypeArguments(
66676686
classPrototype,
66686687
typeArguments,
6669-
currentFunction.flow.contextualTypeArguments,
6688+
uniqueMap<string,Type>(currentFunction.flow.contextualTypeArguments),
66706689
expression
66716690
);
66726691
}

src/diagnosticMessages.generated.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ export enum DiagnosticCode {
121121
Constructor_of_class_0_is_private_and_only_accessible_within_the_class_declaration = 2673,
122122
Constructor_of_class_0_is_protected_and_only_accessible_within_the_class_declaration = 2674,
123123
Namespace_0_has_no_exported_member_1 = 2694,
124+
Required_type_parameters_may_not_follow_optional_type_parameters = 2706,
124125
File_0_not_found = 6054,
125126
Numeric_separators_are_not_allowed_here = 6188,
126127
Multiple_consecutive_numeric_separators_are_not_permitted = 6189
@@ -243,6 +244,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
243244
case 2673: return "Constructor of class '{0}' is private and only accessible within the class declaration.";
244245
case 2674: return "Constructor of class '{0}' is protected and only accessible within the class declaration.";
245246
case 2694: return "Namespace '{0}' has no exported member '{1}'.";
247+
case 2706: return "Required type parameters may not follow optional type parameters.";
246248
case 6054: return "File '{0}' not found.";
247249
case 6188: return "Numeric separators are not allowed here.";
248250
case 6189: return "Multiple consecutive numeric separators are not permitted.";

src/diagnosticMessages.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@
115115
"Constructor of class '{0}' is private and only accessible within the class declaration.": 2673,
116116
"Constructor of class '{0}' is protected and only accessible within the class declaration.": 2674,
117117
"Namespace '{0}' has no exported member '{1}'.": 2694,
118+
"Required type parameters may not follow optional type parameters.": 2706,
118119

119120
"File '{0}' not found.": 6054,
120121
"Numeric separators are not allowed here.": 6188,

src/extra/ast.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,11 @@ export class ASTBuilder {
379379
this.sb.push(" extends ");
380380
this.visitTypeNode(extendsType);
381381
}
382+
var defaultType = node.defaultType;
383+
if (defaultType) {
384+
this.sb.push("=");
385+
this.visitTypeNode(defaultType);
386+
}
382387
}
383388

384389
visitSignatureNode(node: SignatureNode): void {

0 commit comments

Comments
 (0)