Support definite assignment assertion x!: i32 (#260)

This commit is contained in:
Andy Hanson 2018-10-27 09:29:59 -07:00 committed by Daniel Wirtz
parent e58582e9e9
commit 0bb5cb829e
9 changed files with 84 additions and 17 deletions

View File

@ -36,44 +36,46 @@ export enum CommonFlags {
GET = 1 << 11, GET = 1 << 11,
/** Has a `set` modifier. */ /** Has a `set` modifier. */
SET = 1 << 12, SET = 1 << 12,
/** Has a definite assignment assertion `!` as in `x!: i32;`. */
DEFINITE_ASSIGNMENT = 1 << 13,
// Extended modifiers usually derived from basic modifiers // Extended modifiers usually derived from basic modifiers
/** Is ambient, that is either declared or nested in a declared element. */ /** Is ambient, that is either declared or nested in a declared element. */
AMBIENT = 1 << 13, AMBIENT = 1 << 14,
/** Is generic. */ /** Is generic. */
GENERIC = 1 << 14, GENERIC = 1 << 15,
/** Is part of a generic context. */ /** Is part of a generic context. */
GENERIC_CONTEXT = 1 << 15, GENERIC_CONTEXT = 1 << 16,
/** Is an instance member. */ /** Is an instance member. */
INSTANCE = 1 << 16, INSTANCE = 1 << 17,
/** Is a constructor. */ /** Is a constructor. */
CONSTRUCTOR = 1 << 17, CONSTRUCTOR = 1 << 18,
/** Is an arrow function. */ /** Is an arrow function. */
ARROW = 1 << 18, ARROW = 1 << 19,
/** Is a module export. */ /** Is a module export. */
MODULE_EXPORT = 1 << 19, MODULE_EXPORT = 1 << 20,
/** Is a module import. */ /** Is a module import. */
MODULE_IMPORT = 1 << 20, MODULE_IMPORT = 1 << 21,
// Compilation states // Compilation states
/** Is compiled. */ /** Is compiled. */
COMPILED = 1 << 21, COMPILED = 1 << 22,
/** Has a constant value and is therefore inlined. */ /** Has a constant value and is therefore inlined. */
INLINED = 1 << 22, INLINED = 1 << 23,
/** Is scoped. */ /** Is scoped. */
SCOPED = 1 << 23, SCOPED = 1 << 24,
/** Is a trampoline. */ /** Is a trampoline. */
TRAMPOLINE = 1 << 24, TRAMPOLINE = 1 << 25,
/** Is a virtual method. */ /** Is a virtual method. */
VIRTUAL = 1 << 25, VIRTUAL = 1 << 26,
/** Is the main function. */ /** Is the main function. */
MAIN = 1 << 26, MAIN = 1 << 27,
// Other // Other
QUOTED = 1 << 27 QUOTED = 1 << 28
} }
/** Path delimiter inserted between file system levels. */ /** Path delimiter inserted between file system levels. */

View File

@ -29,6 +29,7 @@ export enum DiagnosticCode {
Constructor_of_class_0_must_not_require_any_arguments = 216, Constructor_of_class_0_must_not_require_any_arguments = 216,
Function_0_cannot_be_inlined_into_itself = 217, Function_0_cannot_be_inlined_into_itself = 217,
Cannot_access_method_0_without_calling_it_as_it_requires_this_to_be_set = 218, Cannot_access_method_0_without_calling_it_as_it_requires_this_to_be_set = 218,
Optional_properties_are_not_supported = 219,
Unterminated_string_literal = 1002, Unterminated_string_literal = 1002,
Identifier_expected = 1003, Identifier_expected = 1003,
_0_expected = 1005, _0_expected = 1005,
@ -81,6 +82,7 @@ export enum DiagnosticCode {
Decorators_are_not_valid_here = 1206, Decorators_are_not_valid_here = 1206,
_abstract_modifier_can_only_appear_on_a_class_method_or_property_declaration = 1242, _abstract_modifier_can_only_appear_on_a_class_method_or_property_declaration = 1242,
Method_0_cannot_have_an_implementation_because_it_is_marked_abstract = 1245, Method_0_cannot_have_an_implementation_because_it_is_marked_abstract = 1245,
A_definite_assignment_assertion_is_not_permitted_in_this_context = 1255,
A_class_may_only_extend_another_class = 1311, A_class_may_only_extend_another_class = 1311,
A_parameter_property_cannot_be_declared_using_a_rest_parameter = 1317, A_parameter_property_cannot_be_declared_using_a_rest_parameter = 1317,
Duplicate_identifier_0 = 2300, Duplicate_identifier_0 = 2300,
@ -149,6 +151,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 216: return "Constructor of class '{0}' must not require any arguments."; case 216: return "Constructor of class '{0}' must not require any arguments.";
case 217: return "Function '{0}' cannot be inlined into itself."; case 217: return "Function '{0}' cannot be inlined into itself.";
case 218: return "Cannot access method '{0}' without calling it as it requires 'this' to be set."; case 218: return "Cannot access method '{0}' without calling it as it requires 'this' to be set.";
case 219: return "Optional properties are not supported.";
case 1002: return "Unterminated string literal."; case 1002: return "Unterminated string literal.";
case 1003: return "Identifier expected."; case 1003: return "Identifier expected.";
case 1005: return "'{0}' expected."; case 1005: return "'{0}' expected.";
@ -201,6 +204,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 1206: return "Decorators are not valid here."; case 1206: return "Decorators are not valid here.";
case 1242: return "'abstract' modifier can only appear on a class, method, or property declaration."; case 1242: return "'abstract' modifier can only appear on a class, method, or property declaration.";
case 1245: return "Method '{0}' cannot have an implementation because it is marked abstract."; case 1245: return "Method '{0}' cannot have an implementation because it is marked abstract.";
case 1255: return "A definite assignment assertion '!' is not permitted in this context.";
case 1311: return "A class may only extend another class."; case 1311: return "A class may only extend another class.";
case 1317: return "A parameter property cannot be declared using a rest parameter."; case 1317: return "A parameter property cannot be declared using a rest parameter.";
case 2300: return "Duplicate identifier '{0}'."; case 2300: return "Duplicate identifier '{0}'.";

View File

@ -21,6 +21,7 @@
"Constructor of class '{0}' must not require any arguments.": 216, "Constructor of class '{0}' must not require any arguments.": 216,
"Function '{0}' cannot be inlined into itself.": 217, "Function '{0}' cannot be inlined into itself.": 217,
"Cannot access method '{0}' without calling it as it requires 'this' to be set.": 218, "Cannot access method '{0}' without calling it as it requires 'this' to be set.": 218,
"Optional properties are not supported.": 219,
"Unterminated string literal.": 1002, "Unterminated string literal.": 1002,
"Identifier expected.": 1003, "Identifier expected.": 1003,
@ -74,6 +75,7 @@
"Decorators are not valid here.": 1206, "Decorators are not valid here.": 1206,
"'abstract' modifier can only appear on a class, method, or property declaration.": 1242, "'abstract' modifier can only appear on a class, method, or property declaration.": 1242,
"Method '{0}' cannot have an implementation because it is marked abstract.": 1245, "Method '{0}' cannot have an implementation because it is marked abstract.": 1245,
"A definite assignment assertion '!' is not permitted in this context.": 1255,
"A class may only extend another class.": 1311, "A class may only extend another class.": 1311,
"A parameter property cannot be declared using a rest parameter.": 1317, "A parameter property cannot be declared using a rest parameter.": 1317,

View File

@ -990,6 +990,9 @@ export class ASTBuilder {
this.serializeAccessModifiers(node); this.serializeAccessModifiers(node);
this.visitIdentifierExpression(node.name); this.visitIdentifierExpression(node.name);
var sb = this.sb; var sb = this.sb;
if (node.flags & CommonFlags.DEFINITE_ASSIGNMENT) {
sb.push("!");
}
var type = node.type; var type = node.type;
if (type) { if (type) {
sb.push(": "); sb.push(": ");
@ -1376,6 +1379,9 @@ export class ASTBuilder {
this.visitIdentifierExpression(node.name); this.visitIdentifierExpression(node.name);
var type = node.type; var type = node.type;
var sb = this.sb; var sb = this.sb;
if (node.flags & CommonFlags.DEFINITE_ASSIGNMENT) {
sb.push("!");
}
if (type) { if (type) {
sb.push(": "); sb.push(": ");
this.visitTypeNode(type); this.visitTypeNode(type);

View File

@ -769,6 +769,9 @@ export class Parser extends DiagnosticEmitter {
} }
var identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); var identifier = Node.createIdentifierExpression(tn.readIdentifier(), tn.range());
var flags = parentFlags; var flags = parentFlags;
if (tn.skip(Token.EXCLAMATION)) {
flags |= CommonFlags.DEFINITE_ASSIGNMENT;
}
var type: CommonTypeNode | null = null; var type: CommonTypeNode | null = null;
if (tn.skip(Token.COLON)) { if (tn.skip(Token.COLON)) {
@ -800,13 +803,19 @@ export class Parser extends DiagnosticEmitter {
); // recoverable ); // recoverable
} }
} }
var range = Range.join(identifier.range, tn.range());
if ((flags & CommonFlags.DEFINITE_ASSIGNMENT) && initializer) {
this.error(
DiagnosticCode.A_definite_assignment_assertion_is_not_permitted_in_this_context,
range);
}
return Node.createVariableDeclaration( return Node.createVariableDeclaration(
identifier, identifier,
type, type,
initializer, initializer,
parentDecorators, parentDecorators,
flags, flags,
Range.join(identifier.range, tn.range()) range
); );
} }
@ -1926,6 +1935,15 @@ export class Parser extends DiagnosticEmitter {
} }
let type: CommonTypeNode | null = null; let type: CommonTypeNode | null = null;
if (tn.skip(Token.QUESTION)) {
this.error(
DiagnosticCode.Optional_properties_are_not_supported,
tn.range(startPos, tn.pos)
);
}
if (tn.skip(Token.EXCLAMATION)) {
flags |= CommonFlags.DEFINITE_ASSIGNMENT;
}
if (tn.skip(Token.COLON)) { if (tn.skip(Token.COLON)) {
type = this.parseType(tn); type = this.parseType(tn);
if (!type) return null; if (!type) return null;
@ -1940,13 +1958,20 @@ export class Parser extends DiagnosticEmitter {
initializer = this.parseExpression(tn); initializer = this.parseExpression(tn);
if (!initializer) return null; if (!initializer) return null;
} }
let range = tn.range(startPos, tn.pos);
if ((flags & CommonFlags.DEFINITE_ASSIGNMENT) && ((flags & CommonFlags.STATIC) || isInterface || initializer)) {
this.error(
DiagnosticCode.A_definite_assignment_assertion_is_not_permitted_in_this_context,
range
);
}
let retField = Node.createFieldDeclaration( let retField = Node.createFieldDeclaration(
name, name,
type, type,
initializer, initializer,
decorators, decorators,
flags, flags,
tn.range(startPos, tn.pos) range
); );
tn.skip(Token.SEMICOLON); tn.skip(Token.SEMICOLON);
return retField; return retField;

View File

@ -0,0 +1,9 @@
class C {
x!: i32;
x!: i32 = 0;
static x!: i32;
}
function f(): void {
let x!: i32;
let x!: i32 = 0;
}

View File

@ -0,0 +1,12 @@
class C {
x!: i32;
x!: i32 = 0;
static x!: i32;
}
function f(): void {
let x!: i32;
let x!: i32 = 0;
}
// ERROR 1255: "A definite assignment assertion '!' is not permitted in this context." in definite-assignment-assertion.ts:3:10
// ERROR 1255: "A definite assignment assertion '!' is not permitted in this context." in definite-assignment-assertion.ts:4:14
// ERROR 1255: "A definite assignment assertion '!' is not permitted in this context." in definite-assignment-assertion.ts:8:6

View File

@ -0,0 +1,3 @@
class C {
x?: i32;
}

View File

@ -0,0 +1,4 @@
class C {
x: i32;
}
// ERROR 219: "Optional properties are not supported." in optional-property.ts:2:9