Skip to content

Commit 0bb5cb8

Browse files
andy-hansondcodeIO
authored andcommitted
Support definite assignment assertion x!: i32 (AssemblyScript#260)
1 parent e58582e commit 0bb5cb8

9 files changed

+84
-17
lines changed

src/common.ts

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -36,44 +36,46 @@ export enum CommonFlags {
3636
GET = 1 << 11,
3737
/** Has a `set` modifier. */
3838
SET = 1 << 12,
39+
/** Has a definite assignment assertion `!` as in `x!: i32;`. */
40+
DEFINITE_ASSIGNMENT = 1 << 13,
3941

4042
// Extended modifiers usually derived from basic modifiers
4143

4244
/** Is ambient, that is either declared or nested in a declared element. */
43-
AMBIENT = 1 << 13,
45+
AMBIENT = 1 << 14,
4446
/** Is generic. */
45-
GENERIC = 1 << 14,
47+
GENERIC = 1 << 15,
4648
/** Is part of a generic context. */
47-
GENERIC_CONTEXT = 1 << 15,
49+
GENERIC_CONTEXT = 1 << 16,
4850
/** Is an instance member. */
49-
INSTANCE = 1 << 16,
51+
INSTANCE = 1 << 17,
5052
/** Is a constructor. */
51-
CONSTRUCTOR = 1 << 17,
53+
CONSTRUCTOR = 1 << 18,
5254
/** Is an arrow function. */
53-
ARROW = 1 << 18,
55+
ARROW = 1 << 19,
5456
/** Is a module export. */
55-
MODULE_EXPORT = 1 << 19,
57+
MODULE_EXPORT = 1 << 20,
5658
/** Is a module import. */
57-
MODULE_IMPORT = 1 << 20,
59+
MODULE_IMPORT = 1 << 21,
5860

5961
// Compilation states
6062

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

7476
// Other
7577

76-
QUOTED = 1 << 27
78+
QUOTED = 1 << 28
7779
}
7880

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

src/diagnosticMessages.generated.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export enum DiagnosticCode {
2929
Constructor_of_class_0_must_not_require_any_arguments = 216,
3030
Function_0_cannot_be_inlined_into_itself = 217,
3131
Cannot_access_method_0_without_calling_it_as_it_requires_this_to_be_set = 218,
32+
Optional_properties_are_not_supported = 219,
3233
Unterminated_string_literal = 1002,
3334
Identifier_expected = 1003,
3435
_0_expected = 1005,
@@ -81,6 +82,7 @@ export enum DiagnosticCode {
8182
Decorators_are_not_valid_here = 1206,
8283
_abstract_modifier_can_only_appear_on_a_class_method_or_property_declaration = 1242,
8384
Method_0_cannot_have_an_implementation_because_it_is_marked_abstract = 1245,
85+
A_definite_assignment_assertion_is_not_permitted_in_this_context = 1255,
8486
A_class_may_only_extend_another_class = 1311,
8587
A_parameter_property_cannot_be_declared_using_a_rest_parameter = 1317,
8688
Duplicate_identifier_0 = 2300,
@@ -149,6 +151,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
149151
case 216: return "Constructor of class '{0}' must not require any arguments.";
150152
case 217: return "Function '{0}' cannot be inlined into itself.";
151153
case 218: return "Cannot access method '{0}' without calling it as it requires 'this' to be set.";
154+
case 219: return "Optional properties are not supported.";
152155
case 1002: return "Unterminated string literal.";
153156
case 1003: return "Identifier expected.";
154157
case 1005: return "'{0}' expected.";
@@ -201,6 +204,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
201204
case 1206: return "Decorators are not valid here.";
202205
case 1242: return "'abstract' modifier can only appear on a class, method, or property declaration.";
203206
case 1245: return "Method '{0}' cannot have an implementation because it is marked abstract.";
207+
case 1255: return "A definite assignment assertion '!' is not permitted in this context.";
204208
case 1311: return "A class may only extend another class.";
205209
case 1317: return "A parameter property cannot be declared using a rest parameter.";
206210
case 2300: return "Duplicate identifier '{0}'.";

src/diagnosticMessages.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"Constructor of class '{0}' must not require any arguments.": 216,
2222
"Function '{0}' cannot be inlined into itself.": 217,
2323
"Cannot access method '{0}' without calling it as it requires 'this' to be set.": 218,
24+
"Optional properties are not supported.": 219,
2425

2526
"Unterminated string literal.": 1002,
2627
"Identifier expected.": 1003,
@@ -74,6 +75,7 @@
7475
"Decorators are not valid here.": 1206,
7576
"'abstract' modifier can only appear on a class, method, or property declaration.": 1242,
7677
"Method '{0}' cannot have an implementation because it is marked abstract.": 1245,
78+
"A definite assignment assertion '!' is not permitted in this context.": 1255,
7779
"A class may only extend another class.": 1311,
7880
"A parameter property cannot be declared using a rest parameter.": 1317,
7981

src/extra/ast.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,9 @@ export class ASTBuilder {
990990
this.serializeAccessModifiers(node);
991991
this.visitIdentifierExpression(node.name);
992992
var sb = this.sb;
993+
if (node.flags & CommonFlags.DEFINITE_ASSIGNMENT) {
994+
sb.push("!");
995+
}
993996
var type = node.type;
994997
if (type) {
995998
sb.push(": ");
@@ -1376,6 +1379,9 @@ export class ASTBuilder {
13761379
this.visitIdentifierExpression(node.name);
13771380
var type = node.type;
13781381
var sb = this.sb;
1382+
if (node.flags & CommonFlags.DEFINITE_ASSIGNMENT) {
1383+
sb.push("!");
1384+
}
13791385
if (type) {
13801386
sb.push(": ");
13811387
this.visitTypeNode(type);

src/parser.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,9 @@ export class Parser extends DiagnosticEmitter {
769769
}
770770
var identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
771771
var flags = parentFlags;
772+
if (tn.skip(Token.EXCLAMATION)) {
773+
flags |= CommonFlags.DEFINITE_ASSIGNMENT;
774+
}
772775

773776
var type: CommonTypeNode | null = null;
774777
if (tn.skip(Token.COLON)) {
@@ -800,13 +803,19 @@ export class Parser extends DiagnosticEmitter {
800803
); // recoverable
801804
}
802805
}
806+
var range = Range.join(identifier.range, tn.range());
807+
if ((flags & CommonFlags.DEFINITE_ASSIGNMENT) && initializer) {
808+
this.error(
809+
DiagnosticCode.A_definite_assignment_assertion_is_not_permitted_in_this_context,
810+
range);
811+
}
803812
return Node.createVariableDeclaration(
804813
identifier,
805814
type,
806815
initializer,
807816
parentDecorators,
808817
flags,
809-
Range.join(identifier.range, tn.range())
818+
range
810819
);
811820
}
812821

@@ -1926,6 +1935,15 @@ export class Parser extends DiagnosticEmitter {
19261935
}
19271936

19281937
let type: CommonTypeNode | null = null;
1938+
if (tn.skip(Token.QUESTION)) {
1939+
this.error(
1940+
DiagnosticCode.Optional_properties_are_not_supported,
1941+
tn.range(startPos, tn.pos)
1942+
);
1943+
}
1944+
if (tn.skip(Token.EXCLAMATION)) {
1945+
flags |= CommonFlags.DEFINITE_ASSIGNMENT;
1946+
}
19291947
if (tn.skip(Token.COLON)) {
19301948
type = this.parseType(tn);
19311949
if (!type) return null;
@@ -1940,13 +1958,20 @@ export class Parser extends DiagnosticEmitter {
19401958
initializer = this.parseExpression(tn);
19411959
if (!initializer) return null;
19421960
}
1961+
let range = tn.range(startPos, tn.pos);
1962+
if ((flags & CommonFlags.DEFINITE_ASSIGNMENT) && ((flags & CommonFlags.STATIC) || isInterface || initializer)) {
1963+
this.error(
1964+
DiagnosticCode.A_definite_assignment_assertion_is_not_permitted_in_this_context,
1965+
range
1966+
);
1967+
}
19431968
let retField = Node.createFieldDeclaration(
19441969
name,
19451970
type,
19461971
initializer,
19471972
decorators,
19481973
flags,
1949-
tn.range(startPos, tn.pos)
1974+
range
19501975
);
19511976
tn.skip(Token.SEMICOLON);
19521977
return retField;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class C {
2+
x!: i32;
3+
x!: i32 = 0;
4+
static x!: i32;
5+
}
6+
function f(): void {
7+
let x!: i32;
8+
let x!: i32 = 0;
9+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
class C {
2+
x!: i32;
3+
x!: i32 = 0;
4+
static x!: i32;
5+
}
6+
function f(): void {
7+
let x!: i32;
8+
let x!: i32 = 0;
9+
}
10+
// ERROR 1255: "A definite assignment assertion '!' is not permitted in this context." in definite-assignment-assertion.ts:3:10
11+
// ERROR 1255: "A definite assignment assertion '!' is not permitted in this context." in definite-assignment-assertion.ts:4:14
12+
// ERROR 1255: "A definite assignment assertion '!' is not permitted in this context." in definite-assignment-assertion.ts:8:6

tests/parser/optional-property.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class C {
2+
x?: i32;
3+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
class C {
2+
x: i32;
3+
}
4+
// ERROR 219: "Optional properties are not supported." in optional-property.ts:2:9

0 commit comments

Comments
 (0)