| Index: runtime/vm/parser.cc
|
| diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
|
| index 82dd39defcfc2b6626ca1a30ef3193164ea8f605..cb8a59b65b92d2704c2b592d7753731a682a4d8e 100644
|
| --- a/runtime/vm/parser.cc
|
| +++ b/runtime/vm/parser.cc
|
| @@ -766,8 +766,6 @@ void Parser::ParseFunction(ParsedFunction* parsed_function) {
|
| }
|
|
|
|
|
| -// TODO(regis): Implement support for non-const final static fields (currently
|
| -// supported "final" fields are actually const fields).
|
| // TODO(regis): Since a const variable is implicitly final,
|
| // rename ParseStaticConstGetter to ParseStaticFinalGetter and
|
| // rename kConstImplicitGetter to kImplicitFinalGetter.
|
| @@ -797,12 +795,11 @@ SequenceNode* Parser::ParseStaticConstGetter(const Function& func) {
|
| // leave the evaluation to the getter function.
|
| const intptr_t expr_pos = TokenPos();
|
| AstNode* expr = ParseExpr(kAllowConst, kConsumeCascades);
|
| - // TODO(hausner): Remove is_final check below once we support
|
| - // non-const finals.
|
| - if (field.is_const() || field.is_final()) {
|
| +
|
| + if (field.is_const()) {
|
| // This getter will only be called once at compile time.
|
| if (expr->EvalConstExpr() == NULL) {
|
| - ErrorMsg(expr_pos, "initializer must be a compile time constant");
|
| + ErrorMsg(expr_pos, "initializer must be a compile-time constant");
|
| }
|
| ReturnNode* return_node = new ReturnNode(TokenPos(), expr);
|
| current_block_->statements->Add(return_node);
|
| @@ -819,11 +816,6 @@ SequenceNode* Parser::ParseStaticConstGetter(const Function& func) {
|
| // }
|
| // return field.value; // Type check is executed here in checked mode.
|
|
|
| - // TODO(regis): Remove this check once we support proper const fields.
|
| - if (expr->EvalConstExpr() == NULL) {
|
| - ErrorMsg(expr_pos, "initializer must be a compile time constant");
|
| - }
|
| -
|
| // Generate code checking for circular dependency in field initialization.
|
| AstNode* compare_circular = new ComparisonNode(
|
| TokenPos(),
|
| @@ -866,6 +858,10 @@ SequenceNode* Parser::ParseStaticConstGetter(const Function& func) {
|
| new LiteralNode(
|
| TokenPos(),
|
| Instance::ZoneHandle(Object::transition_sentinel()))));
|
| + // TODO(hausner): If evaluation of the field value throws an exception,
|
| + // we leave the field value as 'transition_sentinel', which is wrong.
|
| + // A second reference to the field later throws a circular dependency
|
| + // exception. The field should instead be set to null after an exception.
|
| initialize_field->Add(new StoreStaticFieldNode(TokenPos(), field, expr));
|
| AstNode* uninitialized_check =
|
| new IfNode(TokenPos(), compare_uninitialized, initialize_field, NULL);
|
| @@ -2672,12 +2668,10 @@ void Parser::ParseFieldDefinition(ClassDesc* members, MemberDesc* field) {
|
| }
|
|
|
| // Create the field object.
|
| - // TODO(hausner): For now, all static final fields are constant. Remove
|
| - // this when lazy init of static variables is implemented.
|
| class_field = Field::New(*field->name,
|
| field->has_static,
|
| field->has_final,
|
| - field->has_const || field->has_final,
|
| + field->has_const,
|
| current_class(),
|
| field->name_pos);
|
| class_field.set_type(*field->type);
|
| @@ -2693,7 +2687,7 @@ void Parser::ParseFieldDefinition(ClassDesc* members, MemberDesc* field) {
|
| getter = Function::New(getter_name,
|
| RawFunction::kConstImplicitGetter,
|
| field->has_static,
|
| - field->has_final,
|
| + field->has_const,
|
| /* is_abstract = */ false,
|
| /* is_external = */ false,
|
| current_class(),
|
| @@ -3735,8 +3729,9 @@ void Parser::AddInterfaces(intptr_t interfaces_pos,
|
|
|
| void Parser::ParseTopLevelVariable(TopLevel* top_level) {
|
| TRACE_PARSER("ParseTopLevelVariable");
|
| - const bool is_final = (CurrentToken() == Token::kFINAL);
|
| const bool is_const = (CurrentToken() == Token::kCONST);
|
| + // Const fields are implicitly final.
|
| + const bool is_final = is_const || (CurrentToken() == Token::kFINAL);
|
| const bool is_static = true;
|
| const AbstractType& type =
|
| AbstractType::ZoneHandle(ParseConstFinalVarOrType(
|
| @@ -3762,13 +3757,8 @@ void Parser::ParseTopLevelVariable(TopLevel* top_level) {
|
| var_name.ToCString());
|
| }
|
|
|
| - // TODO(hausner): const and final are equivalent at the moment.
|
| - field = Field::New(var_name,
|
| - is_static,
|
| - is_final || is_const, // Const fields are also final.
|
| - is_const || is_final,
|
| - current_class(),
|
| - name_pos);
|
| + field = Field::New(var_name, is_static, is_final, is_const,
|
| + current_class(), name_pos);
|
| field.set_type(type);
|
| field.set_value(Instance::Handle(Instance::null()));
|
| top_level->fields.Add(field);
|
| @@ -3777,7 +3767,7 @@ void Parser::ParseTopLevelVariable(TopLevel* top_level) {
|
| ConsumeToken();
|
| Instance& field_value = Instance::Handle(Object::sentinel());
|
| bool has_simple_literal = false;
|
| - if ((is_final || is_const) && (LookaheadToken(1) == Token::kSEMICOLON)) {
|
| + if (is_final && (LookaheadToken(1) == Token::kSEMICOLON)) {
|
| has_simple_literal = IsSimpleLiteral(type, &field_value);
|
| }
|
| SkipExpr();
|
| @@ -3788,7 +3778,7 @@ void Parser::ParseTopLevelVariable(TopLevel* top_level) {
|
| getter = Function::New(getter_name,
|
| RawFunction::kConstImplicitGetter,
|
| is_static,
|
| - is_final,
|
| + is_const,
|
| /* is_abstract = */ false,
|
| /* is_external = */ false,
|
| current_class(),
|
| @@ -3796,8 +3786,7 @@ void Parser::ParseTopLevelVariable(TopLevel* top_level) {
|
| getter.set_result_type(type);
|
| top_level->functions.Add(getter);
|
| }
|
| -
|
| - } else if (is_final || is_const) {
|
| + } else if (is_final) {
|
| ErrorMsg(name_pos, "missing initializer for final or const variable");
|
| }
|
|
|
| @@ -6787,7 +6776,7 @@ AstNode* Parser::FoldConstExpr(intptr_t expr_pos, AstNode* expr) {
|
| return expr;
|
| }
|
| if (expr->EvalConstExpr() == NULL) {
|
| - ErrorMsg(expr_pos, "expression must be a compile time constant");
|
| + ErrorMsg(expr_pos, "expression must be a compile-time constant");
|
| }
|
| return new LiteralNode(expr_pos, EvaluateConstExpr(expr));
|
| }
|
| @@ -6942,7 +6931,7 @@ AstNode* Parser::ParseExpr(bool require_compiletime_const,
|
| ConsumeToken();
|
| const intptr_t right_expr_pos = TokenPos();
|
| if (require_compiletime_const && (assignment_op != Token::kASSIGN)) {
|
| - ErrorMsg(right_expr_pos, "expression must be a compile time constant");
|
| + ErrorMsg(right_expr_pos, "expression must be a compile-time constant");
|
| }
|
| AstNode* right_expr = ParseExpr(require_compiletime_const, consume_cascades);
|
| AstNode* left_expr = expr;
|
| @@ -7181,9 +7170,7 @@ AstNode* Parser::GenerateStaticFieldLookup(const Field& field,
|
| return initializing_getter;
|
| }
|
| // The field is initialized.
|
| - // TODO(hausner): Remove the is_final check when we support non-const
|
| - // final static variables.
|
| - if (field.is_const() || field.is_final()) {
|
| + if (field.is_const()) {
|
| ASSERT(field.value() != Object::sentinel());
|
| ASSERT(field.value() != Object::transition_sentinel());
|
| return new LiteralNode(ident_pos, Instance::ZoneHandle(field.value()));
|
| @@ -7752,9 +7739,7 @@ AstNode* Parser::RunStaticFieldInitializer(const Field& field) {
|
| ASSERT(field.is_static());
|
| const Instance& value = Instance::Handle(field.value());
|
| if (value.raw() == Object::transition_sentinel()) {
|
| - // TODO(hausner): Remove the check for is_final() once we support
|
| - // non-const final fields.
|
| - if (field.is_const() || field.is_final()) {
|
| + if (field.is_const()) {
|
| ErrorMsg("circular dependency while initializing static field '%s'",
|
| String::Handle(field.name()).ToCString());
|
| } else {
|
| @@ -7769,9 +7754,7 @@ AstNode* Parser::RunStaticFieldInitializer(const Field& field) {
|
| // This field has not been referenced yet and thus the value has
|
| // not been evaluated. If the field is const, call the static getter method
|
| // to evaluate the expression and canonicalize the value.
|
| - // TODO(hausner): Remove the check for is_final() once we support
|
| - // non-const final fields.
|
| - if (field.is_const() || field.is_final()) {
|
| + if (field.is_const()) {
|
| field.set_value(Instance::Handle(Object::transition_sentinel()));
|
| const String& field_name = String::Handle(field.name());
|
| const String& getter_name =
|
| @@ -7797,7 +7780,7 @@ AstNode* Parser::RunStaticFieldInitializer(const Field& field) {
|
| // It is a compile-time error if evaluation of a compile-time constant
|
| // would raise an exception.
|
| AppendErrorMsg(error, TokenPos(),
|
| - "error initializing final field '%s'",
|
| + "error initializing const field '%s'",
|
| String::Handle(field.name()).ToCString());
|
| } else {
|
| Isolate::Current()->long_jump_base()->Jump(1, error);
|
| @@ -8567,7 +8550,7 @@ AstNode* Parser::ParseMapLiteral(intptr_t type_pos,
|
| if (key == NULL) {
|
| ErrorMsg("map entry key must be string literal");
|
| } else if (is_const && !key->IsLiteralNode()) {
|
| - ErrorMsg("map entry key must be compile time constant string");
|
| + ErrorMsg("map entry key must be compile-time constant string");
|
| }
|
| ExpectToken(Token::kCOLON);
|
| const bool saved_mode = SetAllowFunctionLiterals(true);
|
|
|