Skip to content

Commit 57a55d3

Browse files
authored
Enforce strict field initialization (#1349)
BREAKING CHANGE: Instance fields not definitely assigned within the constructor now yield an error, unless the field's name is annotated with a trailing `!` (checked at runtime), is of a nullable or is of a value type (initialized to zero). Fields of non-nullable reference types must be assigned before `this` is either implicitly or explicitly returned from the constructor, passed to another function or another instance method is called on `this`. Overall the behavior is similar to, but not exactly the same as `--strictPropertyInitialization` in TypeScript.
1 parent 2f525c0 commit 57a55d3

36 files changed

+4132
-1039
lines changed

src/ast.ts

+21-9
Original file line numberDiff line numberDiff line change
@@ -748,15 +748,27 @@ export abstract class Node {
748748
return false;
749749
}
750750

751-
/** Checks if this is a call calling a method on super. */
752-
get isCallOnSuper(): bool {
753-
if (this.kind != NodeKind.CALL) return false;
754-
var expression = changetype<CallExpression>(this).expression;
755-
if (expression.kind != NodeKind.PROPERTYACCESS) return false;
756-
var target = (<PropertyAccessExpression>expression).expression;
757-
if (target.kind == NodeKind.SUPER) return true;
751+
private isAccessOn(kind: NodeKind): bool {
752+
let node = changetype<Node>(this);
753+
if (node.kind == NodeKind.CALL) {
754+
node = (<CallExpression>node).expression;
755+
}
756+
if (node.kind == NodeKind.PROPERTYACCESS) {
757+
let target = (<PropertyAccessExpression>node).expression;
758+
if (target.kind == kind) return true;
759+
}
758760
return false;
759761
}
762+
763+
/** Checks if this node accesses a method or property on `this`. */
764+
get isAccessOnThis(): bool {
765+
return this.isAccessOn(NodeKind.THIS);
766+
}
767+
768+
/** Checks if this node accesses a method or property on `super`. */
769+
get isAccessOnSuper(): bool {
770+
return this.isAccessOn(NodeKind.SUPER);
771+
}
760772
}
761773

762774
// types
@@ -1518,12 +1530,12 @@ export class Source extends Node {
15181530
/** Full source text. */
15191531
public text: string
15201532
) {
1521-
super(NodeKind.SOURCE, changetype<Range>(0)); // ¯\(ツ)/¯
1522-
this.range = new Range(this, 0, text.length);
1533+
super(NodeKind.SOURCE, new Range(0, text.length));
15231534
var internalPath = mangleInternalPath(normalizedPath);
15241535
this.internalPath = internalPath;
15251536
var pos = internalPath.lastIndexOf(PATH_DELIMITER);
15261537
this.simplePath = pos >= 0 ? internalPath.substring(pos + 1) : internalPath;
1538+
this.range.source = this;
15271539
}
15281540

15291541
/** Path used internally. */

src/builtins.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -2894,7 +2894,9 @@ function builtin_instantiate(ctx: BuiltinContext): ExpressionRef {
28942894
return module.unreachable();
28952895
}
28962896
compiler.currentType = classInstance.type;
2897-
return compiler.compileInstantiate(classInstance, operands, Constraints.NONE, ctx.reportNode);
2897+
var ctor = compiler.ensureConstructor(classInstance, ctx.reportNode);
2898+
compiler.checkFieldInitialization(classInstance, ctx.reportNode);
2899+
return compiler.compileInstantiate(ctor, operands, Constraints.NONE, ctx.reportNode);
28982900
}
28992901
builtins.set(BuiltinNames.instantiate, builtin_instantiate);
29002902

src/common.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export enum CommonFlags {
3737
/** Has a `set` modifier. */
3838
SET = 1 << 12,
3939
/** Has a definite assignment assertion `!` as in `x!: i32;`. */
40-
DEFINITE_ASSIGNMENT = 1 << 13,
40+
DEFINITELY_ASSIGNED = 1 << 13,
4141

4242
// Extended modifiers usually derived from basic modifiers
4343

0 commit comments

Comments
 (0)