Skip to content

Commit 1e0466e

Browse files
authored
feat: implement scoped type alias (AssemblyScript#2806)
1 parent 153def6 commit 1e0466e

9 files changed

+802
-58
lines changed

Diff for: src/compiler.ts

+34-18
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ import {
9393
PropertyPrototype,
9494
IndexSignature,
9595
File,
96-
mangleInternalName
96+
mangleInternalName,
97+
TypeDefinition
9798
} from "./program";
9899

99100
import {
@@ -180,7 +181,8 @@ import {
180181

181182
findDecorator,
182183
isTypeOmitted,
183-
Source
184+
Source,
185+
TypeDeclaration
184186
} from "./ast";
185187

186188
import {
@@ -1156,7 +1158,7 @@ export class Compiler extends DiagnosticEmitter {
11561158

11571159
// Resolve type if annotated
11581160
if (typeNode) {
1159-
let resolvedType = this.resolver.resolveType(typeNode, global.parent); // reports
1161+
let resolvedType = this.resolver.resolveType(typeNode, null, global.parent); // reports
11601162
if (!resolvedType) {
11611163
global.set(CommonFlags.Errored);
11621164
pendingElements.delete(global);
@@ -2238,13 +2240,7 @@ export class Compiler extends DiagnosticEmitter {
22382240
break;
22392241
}
22402242
case NodeKind.TypeDeclaration: {
2241-
// TODO: integrate inner type declaration into flow
2242-
this.error(
2243-
DiagnosticCode.Not_implemented_0,
2244-
statement.range,
2245-
"Inner type alias"
2246-
);
2247-
stmt = module.unreachable();
2243+
stmt = this.compileTypeDeclaration(<TypeDeclaration>statement);
22482244
break;
22492245
}
22502246
case NodeKind.Module: {
@@ -2305,6 +2301,24 @@ export class Compiler extends DiagnosticEmitter {
23052301
return this.module.flatten(stmts);
23062302
}
23072303

2304+
private compileTypeDeclaration(statement: TypeDeclaration): ExpressionRef {
2305+
let flow = this.currentFlow;
2306+
let name = statement.name.text;
2307+
let existedTypeAlias = flow.lookupScopedTypeAlias(name);
2308+
if (existedTypeAlias) {
2309+
this.errorRelated(
2310+
DiagnosticCode.Duplicate_identifier_0,
2311+
statement.range,
2312+
existedTypeAlias.declaration.range,
2313+
name
2314+
);
2315+
return this.module.unreachable();
2316+
}
2317+
let element = new TypeDefinition(name, flow.sourceFunction, statement, DecoratorFlags.None);
2318+
flow.addScopedTypeAlias(name, element);
2319+
return this.module.nop();
2320+
}
2321+
23082322
private compileBreakStatement(
23092323
statement: BreakStatement
23102324
): ExpressionRef {
@@ -2962,7 +2976,7 @@ export class Compiler extends DiagnosticEmitter {
29622976
let initializerNode = declaration.initializer;
29632977
if (typeNode) {
29642978
type = resolver.resolveType( // reports
2965-
typeNode,
2979+
typeNode, flow,
29662980
flow.sourceFunction,
29672981
cloneMap(flow.contextualTypeArguments)
29682982
);
@@ -3729,7 +3743,7 @@ export class Compiler extends DiagnosticEmitter {
37293743
case AssertionKind.As: {
37303744
let flow = this.currentFlow;
37313745
let toType = this.resolver.resolveType( // reports
3732-
assert(expression.toType),
3746+
assert(expression.toType), flow,
37333747
flow.sourceFunction,
37343748
cloneMap(flow.contextualTypeArguments)
37353749
);
@@ -6162,6 +6176,7 @@ export class Compiler extends DiagnosticEmitter {
61626176
typeArguments = this.resolver.resolveTypeArguments(
61636177
assert(typeParameterNodes),
61646178
typeArgumentNodes,
6179+
this.currentFlow,
61656180
this.currentFlow.sourceFunction.parent,
61666181
cloneMap(this.currentFlow.contextualTypeArguments), // don't update
61676182
expression
@@ -7085,7 +7100,7 @@ export class Compiler extends DiagnosticEmitter {
70857100
let parameterNode = parameterNodes[i];
70867101
if (!isTypeOmitted(parameterNode.type)) {
70877102
let resolvedType = this.resolver.resolveType(
7088-
parameterNode.type,
7103+
parameterNode.type, flow,
70897104
sourceFunction.parent,
70907105
contextualTypeArguments
70917106
);
@@ -7105,7 +7120,7 @@ export class Compiler extends DiagnosticEmitter {
71057120
let returnType = contextualSignature.returnType;
71067121
if (!isTypeOmitted(signatureNode.returnType)) {
71077122
let resolvedType = this.resolver.resolveType(
7108-
signatureNode.returnType,
7123+
signatureNode.returnType, flow,
71097124
sourceFunction.parent,
71107125
contextualTypeArguments
71117126
);
@@ -7135,7 +7150,7 @@ export class Compiler extends DiagnosticEmitter {
71357150
return module.unreachable();
71367151
}
71377152
let resolvedType = this.resolver.resolveType(
7138-
thisTypeNode,
7153+
thisTypeNode, flow,
71397154
sourceFunction.parent,
71407155
contextualTypeArguments
71417156
);
@@ -7522,7 +7537,7 @@ export class Compiler extends DiagnosticEmitter {
75227537
if (isType.kind == NodeKind.NamedType) {
75237538
let namedType = <NamedTypeNode>isType;
75247539
if (!(namedType.isNullable || namedType.hasTypeArguments)) {
7525-
let element = this.resolver.resolveTypeName(namedType.name, flow.sourceFunction, ReportMode.Swallow);
7540+
let element = this.resolver.resolveTypeName(namedType.name, flow, flow.sourceFunction, ReportMode.Swallow);
75267541
if (element && element.kind == ElementKind.ClassPrototype) {
75277542
let prototype = <ClassPrototype>element;
75287543
if (prototype.is(CommonFlags.Generic)) {
@@ -7534,7 +7549,7 @@ export class Compiler extends DiagnosticEmitter {
75347549

75357550
// Fall back to `instanceof TYPE`
75367551
let expectedType = this.resolver.resolveType(
7537-
expression.isType,
7552+
expression.isType, flow,
75387553
flow.sourceFunction,
75397554
cloneMap(flow.contextualTypeArguments)
75407555
);
@@ -8686,7 +8701,7 @@ export class Compiler extends DiagnosticEmitter {
86868701
let flow = this.currentFlow;
86878702

86888703
// obtain the class being instantiated
8689-
let target = this.resolver.resolveTypeName(expression.typeName, flow.sourceFunction);
8704+
let target = this.resolver.resolveTypeName(expression.typeName, flow, flow.sourceFunction);
86908705
if (!target) return module.unreachable();
86918706
if (target.kind != ElementKind.ClassPrototype) {
86928707
this.error(
@@ -8722,6 +8737,7 @@ export class Compiler extends DiagnosticEmitter {
87228737
classInstance = this.resolver.resolveClassInclTypeArguments(
87238738
classPrototype,
87248739
typeArguments,
8740+
flow,
87258741
flow.sourceFunction.parent, // relative to caller
87268742
cloneMap(flow.contextualTypeArguments),
87278743
expression

Diff for: src/flow.ts

+36-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ import {
3131
TypedElement,
3232
mangleInternalName,
3333
Property,
34-
PropertyPrototype
34+
PropertyPrototype,
35+
TypeDefinition
3536
} from "./program";
3637

3738
import {
@@ -250,6 +251,8 @@ export class Flow {
250251
breakLabel: string | null = null;
251252
/** Scoped local variables. */
252253
scopedLocals: Map<string,Local> | null = null;
254+
/** Scoped type alias. */
255+
scopedTypeAlias: Map<string,TypeDefinition> | null = null;
253256
/** Local flags. */
254257
localFlags: LocalFlags[] = [];
255258
/** Field flags on `this`. Constructors only. */
@@ -405,6 +408,38 @@ export class Flow {
405408
falseFlows.set(condExpr, falseFlow);
406409
}
407410

411+
addScopedTypeAlias(name: string, definition: TypeDefinition): void {
412+
let scopedTypeAlias = this.scopedTypeAlias;
413+
if (!scopedTypeAlias) this.scopedTypeAlias = scopedTypeAlias = new Map();
414+
scopedTypeAlias.set(name, definition);
415+
}
416+
417+
lookupScopedTypeAlias(name: string): TypeDefinition | null {
418+
let current: Flow | null = this;
419+
do {
420+
let scopedTypeAlias = current.scopedTypeAlias;
421+
if (scopedTypeAlias && scopedTypeAlias.has(name)) {
422+
return assert(scopedTypeAlias.get(name));
423+
}
424+
current = current.parent;
425+
} while (current);
426+
return null;
427+
}
428+
429+
lookupTypeAlias(name: string): TypeDefinition | null {
430+
let definition: TypeDefinition | null = null;
431+
if (definition = this.lookupScopedTypeAlias(name)) return definition;
432+
433+
let sourceParent = this.sourceFunction.parent;
434+
if (sourceParent.kind == ElementKind.Function) {
435+
// lookup parent function.
436+
let parentFunction = <Function>sourceParent;
437+
return parentFunction.flow.lookupTypeAlias(name);
438+
}
439+
440+
return null;
441+
}
442+
408443
/** Gets a free temporary local of the specified type. */
409444
getTempLocal(type: Type): Local {
410445
let local = this.targetFunction.addLocal(type);

Diff for: src/program.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1308,7 +1308,7 @@ export class Program extends DiagnosticEmitter {
13081308
for (let i = 0, k = queuedExtends.length; i < k; ++i) {
13091309
let thisPrototype = queuedExtends[i];
13101310
let extendsNode = assert(thisPrototype.extendsNode); // must be present if in queuedExtends
1311-
let baseElement = resolver.resolveTypeName(extendsNode.name, thisPrototype.parent);
1311+
let baseElement = resolver.resolveTypeName(extendsNode.name, null, thisPrototype.parent);
13121312
if (!baseElement) continue;
13131313
if (thisPrototype.kind == ElementKind.ClassPrototype) {
13141314
if (baseElement.kind == ElementKind.ClassPrototype) {
@@ -1405,7 +1405,7 @@ export class Program extends DiagnosticEmitter {
14051405
let implementsNodes = assert(thisPrototype.implementsNodes); // must be present if in queuedImplements
14061406
for (let j = 0, l = implementsNodes.length; j < l; ++j) {
14071407
let implementsNode = implementsNodes[j];
1408-
let interfaceElement = resolver.resolveTypeName(implementsNode.name, thisPrototype.parent);
1408+
let interfaceElement = resolver.resolveTypeName(implementsNode.name, null, thisPrototype.parent);
14091409
if (!interfaceElement) continue;
14101410
if (interfaceElement.kind == ElementKind.InterfacePrototype) {
14111411
let interfacePrototype = <InterfacePrototype>interfaceElement;
@@ -3383,7 +3383,7 @@ export class TypeDefinition extends TypedElement {
33833383
constructor(
33843384
/** Simple name. */
33853385
name: string,
3386-
/** Parent element, usually a file or namespace. */
3386+
/** Parent element. */
33873387
parent: Element,
33883388
/** Declaration reference. */
33893389
declaration: TypeDeclaration,

0 commit comments

Comments
 (0)