Skip to content

Commit 96ce41f

Browse files
committed
Ensure left and right flows, use assert for maps, initialize field flags in constructor only
1 parent 63cb614 commit 96ce41f

File tree

3 files changed

+47
-21
lines changed

3 files changed

+47
-21
lines changed

src/flow.ts

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,8 @@ export enum LocalFlags {
171171

172172
/** Flags indicating the current state of an instance field. */
173173
export enum FieldFlags {
174-
NONE = 0,
175-
INITIALIZED = 1 << 0,
174+
NONE = 1,
175+
INITIALIZED = 1 << 1,
176176
}
177177

178178
/** Condition kinds. */
@@ -207,7 +207,7 @@ export class Flow {
207207
/** Local flags. */
208208
localFlags: LocalFlags[];
209209
/** Field flags. */
210-
fieldFlags: Map<string, FieldFlags>;
210+
fieldFlags: Map<string, FieldFlags> | null = null;
211211
/** Function being inlined, when inlining. */
212212
inlineFunction: Function | null;
213213
/** The label we break to when encountering a return statement, when inlining. */
@@ -224,7 +224,9 @@ export class Flow {
224224
flow.returnType = parentFunction.signature.returnType;
225225
flow.contextualTypeArguments = parentFunction.contextualTypeArguments;
226226
flow.localFlags = [];
227-
flow.fieldFlags = new Map();
227+
if (parentFunction.is(CommonFlags.CONSTRUCTOR)) {
228+
flow.fieldFlags = new Map();
229+
}
228230
flow.inlineFunction = null;
229231
flow.inlineReturnLabel = null;
230232
return flow;
@@ -285,7 +287,9 @@ export class Flow {
285287
branch.localFlags = this.localFlags.slice();
286288
branch.inlineFunction = this.inlineFunction;
287289
branch.inlineReturnLabel = this.inlineReturnLabel;
288-
branch.fieldFlags = new Map(this.fieldFlags);
290+
if (branch.parentFunction.is(CommonFlags.CONSTRUCTOR)) {
291+
branch.fieldFlags = new Map(this.fieldFlags!);
292+
}
289293
return branch;
290294
}
291295

@@ -531,13 +535,17 @@ export class Flow {
531535

532536
setFieldFlag(name: string, flag: FieldFlags): void {
533537
let fieldFlags = this.fieldFlags;
534-
const flags = fieldFlags.get(name) || 0;
535-
fieldFlags.set(name, flags | flag);
538+
if (fieldFlags) {
539+
const flags = fieldFlags.has(name) ? assert(fieldFlags.get(name)) : FieldFlags.NONE;
540+
fieldFlags.set(name, flags | flag);
541+
}
536542
}
537543

538544
isFieldFlag(name: string, flag: FieldFlags): bool {
539-
const flags = this.fieldFlags.get(name);
540-
if (flags) {
545+
const fieldFlags = this.fieldFlags;
546+
547+
if (fieldFlags && fieldFlags.has(name)) {
548+
const flags = assert(fieldFlags.get(name));
541549
return (flags & flag) == flag;
542550
}
543551
return false;
@@ -831,17 +839,22 @@ export class Flow {
831839
}
832840
}
833841

834-
// Only the most right flow will have an effect
835-
// on the resulting flow.
836-
const rightFieldFlags = right.fieldFlags;
837-
const rightKeys = Map_keys(rightFieldFlags);
838842

839-
for (let _values = Map_values(rightFieldFlags), i = 0, k = _values.length; i < k; ++i) {
840-
const rightValue = unchecked(_values[i]);
841-
const currentKey = unchecked(rightKeys[i]);
843+
if (left.fieldFlags && right.fieldFlags && right.fieldFlags.size > 0) {
844+
const rightFieldFlags = right.fieldFlags;
845+
const rightKeys = Map_keys(rightFieldFlags);
846+
const rightValues = Map_values(rightFieldFlags);
847+
848+
const leftFieldFlags = left.fieldFlags;
842849

843-
if (rightValue & FieldFlags.INITIALIZED) {
844-
this.setFieldFlag(currentKey, FieldFlags.INITIALIZED);
850+
for (let i = 0, k = rightValues.length; i < k; ++i) {
851+
const rightValue = unchecked(rightValues[i]);
852+
const rightKey = unchecked(rightKeys[i]);
853+
const leftValue = leftFieldFlags.has(rightKey) ? assert(leftFieldFlags.get(rightKey)) : FieldFlags.NONE;
854+
855+
if ((rightValue & FieldFlags.INITIALIZED) && (leftValue & FieldFlags.INITIALIZED)) {
856+
this.setFieldFlag(rightKey, FieldFlags.INITIALIZED);
857+
}
845858
}
846859
}
847860
}

tests/compiler/strict-init.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
"stderr": [
66
"TS2564: Property inlinedProp has no initializer and is not definitely assigned in constructor",
77
"TS2564: Property b has no initializer and is not definitely assigned in constructor",
8+
"TS2564: Property fieldLeft has no initializer and is not definitely assigned in constructor",
9+
"TS2564: Property fieldRight has no initializer and is not definitely assigned in constructor",
810
"TS2564: Property p has no initializer and is not definitely assigned in constructor"
911
]
1012
}

tests/compiler/strict-init.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,24 @@ export class ExplicitConstructorInit {
2323
}
2424
}
2525

26-
export class EmptyIfBlock {
27-
field: i32;
26+
export class EmptyLeftBlock {
27+
fieldLeft: i32;
2828

2929
constructor(x: i32) {
3030
if ((x + 5) == 6) {
3131
} else {
32-
this.field = 7;
32+
this.fieldLeft = 7;
33+
}
34+
}
35+
}
36+
37+
export class EmptyRightBlock {
38+
fieldRight: i32;
39+
40+
constructor(x: i32) {
41+
if ((x + 5) == 6) {
42+
this.fieldRight = 7;
43+
} else {
3344
}
3445
}
3546
}

0 commit comments

Comments
 (0)