Skip to content

Commit 0e33806

Browse files
committed
Add a way to ensure that lazy globals are resolved, fixes #355
This only affects static fields that currently must have a type annotation, while it wouldn't work if there wasn't an annotated type, like on normal globals, which aren't compiled lazily, though. Must be revisted if requirements on type annotations on fields ever become relaxed.
1 parent a661ff7 commit 0e33806

File tree

4 files changed

+39
-21
lines changed

4 files changed

+39
-21
lines changed

src/common.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,22 +60,24 @@ export enum CommonFlags {
6060

6161
// Compilation states
6262

63+
/** Is resolved. */
64+
RESOLVED = 1 << 22,
6365
/** Is compiled. */
64-
COMPILED = 1 << 22,
66+
COMPILED = 1 << 23,
6567
/** Has a constant value and is therefore inlined. */
66-
INLINED = 1 << 23,
68+
INLINED = 1 << 24,
6769
/** Is scoped. */
68-
SCOPED = 1 << 24,
70+
SCOPED = 1 << 25,
6971
/** Is a trampoline. */
70-
TRAMPOLINE = 1 << 25,
72+
TRAMPOLINE = 1 << 26,
7173
/** Is a virtual method. */
72-
VIRTUAL = 1 << 26,
74+
VIRTUAL = 1 << 27,
7375
/** Is the main function. */
74-
MAIN = 1 << 27,
76+
MAIN = 1 << 28,
7577

7678
// Other
7779

78-
QUOTED = 1 << 28
80+
QUOTED = 1 << 29
7981
}
8082

8183
/** Path delimiter inserted between file system levels. */

src/compiler.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -696,7 +696,7 @@ export class Compiler extends DiagnosticEmitter {
696696
var declaration = global.declaration;
697697
var initExpr: ExpressionRef = 0;
698698

699-
if (global.type == Type.void) { // type is void if not yet resolved or not annotated
699+
if (!global.is(CommonFlags.RESOLVED)) {
700700
if (declaration) {
701701

702702
// resolve now if annotated
@@ -711,6 +711,7 @@ export class Compiler extends DiagnosticEmitter {
711711
return false;
712712
}
713713
global.type = resolvedType;
714+
global.set(CommonFlags.RESOLVED);
714715

715716
// infer from initializer if not annotated
716717
} else if (declaration.initializer) { // infer type using void/NONE for literal inference
@@ -727,6 +728,7 @@ export class Compiler extends DiagnosticEmitter {
727728
return false;
728729
}
729730
global.type = this.currentType;
731+
global.set(CommonFlags.RESOLVED);
730732

731733
// must either be annotated or have an initializer
732734
} else {
@@ -737,7 +739,7 @@ export class Compiler extends DiagnosticEmitter {
737739
return false;
738740
}
739741
} else {
740-
assert(false); // must have a declaration if 'void' (and thus resolved later on)
742+
assert(false); // must have a declaration if resolved lazily
741743
}
742744
}
743745

src/program.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ import {
1616

1717
import {
1818
Options,
19-
Feature
19+
Feature,
20+
Compiler
2021
} from "./compiler";
2122

2223
import {
@@ -730,19 +731,19 @@ export class Program extends DiagnosticEmitter {
730731
/** Sets a constant integer value. */
731732
setConstantInteger(globalName: string, type: Type, value: I64): void {
732733
assert(type.is(TypeFlags.INTEGER));
733-
this.elementsLookup.set(globalName,
734-
new Global(this, globalName, globalName, type, null, DecoratorFlags.NONE)
735-
.withConstantIntegerValue(value)
736-
);
734+
var global = new Global(this, globalName, globalName, type, null, DecoratorFlags.NONE)
735+
.withConstantIntegerValue(value);
736+
global.set(CommonFlags.RESOLVED);
737+
this.elementsLookup.set(globalName, global);
737738
}
738739

739740
/** Sets a constant float value. */
740741
setConstantFloat(globalName: string, type: Type, value: f64): void {
741742
assert(type.is(TypeFlags.FLOAT));
742-
this.elementsLookup.set(globalName,
743-
new Global(this, globalName, globalName, type, null, DecoratorFlags.NONE)
744-
.withConstantFloatValue(value)
745-
);
743+
var global = new Global(this, globalName, globalName, type, null, DecoratorFlags.NONE)
744+
.withConstantFloatValue(value);
745+
global.set(CommonFlags.RESOLVED);
746+
this.elementsLookup.set(globalName, global);
746747
}
747748

748749
/** Tries to locate an import by traversing exports and queued exports. */

src/resolver.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ import {
2424
Property,
2525
DecoratorFlags,
2626
FieldPrototype,
27-
Field
27+
Field,
28+
Global
2829
} from "./program";
2930

3031
import {
@@ -358,6 +359,18 @@ export class Resolver extends DiagnosticEmitter {
358359
return null;
359360
}
360361

362+
/** Resolves a lazily compiled global, i.e. a static class field. */
363+
ensureResolvedLazyGlobal(global: Global, reportMode: ReportMode = ReportMode.REPORT): bool {
364+
if (global.is(CommonFlags.RESOLVED)) return true;
365+
var resolveType = assert(global.declaration).type;
366+
if (!resolveType) return false;
367+
var resolvedType = this.resolveType(resolveType, null, reportMode);
368+
if (!resolvedType) return false;
369+
global.type = resolvedType;
370+
global.set(CommonFlags.RESOLVED);
371+
return true;
372+
}
373+
361374
/** Resolves a property access to the element it refers to. */
362375
resolvePropertyAccess(
363376
propertyAccess: PropertyAccessExpression,
@@ -374,7 +387,7 @@ export class Resolver extends DiagnosticEmitter {
374387

375388
// Resolve variable-likes to the class type they reference first
376389
switch (target.kind) {
377-
case ElementKind.GLOBAL:
390+
case ElementKind.GLOBAL: if (!this.ensureResolvedLazyGlobal(<Global>target, reportMode)) return null;
378391
case ElementKind.LOCAL:
379392
case ElementKind.FIELD: {
380393
let type = (<VariableLikeElement>target).type;
@@ -494,7 +507,7 @@ export class Resolver extends DiagnosticEmitter {
494507
var target = this.resolveExpression(targetExpression, contextualFunction, reportMode);
495508
if (!target) return null;
496509
switch (target.kind) {
497-
case ElementKind.GLOBAL:
510+
case ElementKind.GLOBAL: if (!this.ensureResolvedLazyGlobal(<Global>target, reportMode)) return null;
498511
case ElementKind.LOCAL:
499512
case ElementKind.FIELD: {
500513
let type = (<VariableLikeElement>target).type;

0 commit comments

Comments
 (0)