Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 1e0466e

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

File tree

9 files changed

+802
-58
lines changed

9 files changed

+802
-58
lines changed

‎src/compiler.ts‎

Lines changed: 34 additions & 18 deletions
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

‎src/flow.ts‎

Lines changed: 36 additions & 1 deletion
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);

‎src/program.ts‎

Lines changed: 3 additions & 3 deletions
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)

AltStyle によって変換されたページ (->オリジナル) /