Chromium Code Reviews| Index: runtime/vm/parser.cc |
| =================================================================== |
| --- runtime/vm/parser.cc (revision 24938) |
| +++ runtime/vm/parser.cc (working copy) |
| @@ -1281,7 +1281,7 @@ |
| // mode, because they are part of the function type of closurized |
| // functions appearing in type tests with typedefs. |
| parameter.type = &AbstractType::ZoneHandle( |
| - ParseType(is_top_level_ ? ClassFinalizer::kTryResolve : |
| + ParseType(is_top_level_ ? ClassFinalizer::kResolveTypeParameters : |
| ClassFinalizer::kCanonicalize)); |
| } else { |
| parameter.type = &Type::ZoneHandle(Type::DynamicType()); |
| @@ -2800,20 +2800,17 @@ |
| ConsumeToken(); |
| const intptr_t type_pos = TokenPos(); |
| const AbstractType& type = AbstractType::Handle( |
| - ParseType(ClassFinalizer::kTryResolve)); |
| - if (!type.IsMalformed() && |
| - (type.IsTypeParameter() || type.IsDynamicType())) { |
| + ParseType(ClassFinalizer::kResolveTypeParameters)); |
| + if (!type.IsMalformed() && type.IsTypeParameter()) { |
| // Replace the type with a malformed type and compile a throw when called. |
| redirection_type = ClassFinalizer::NewFinalizedMalformedType( |
| Error::Handle(), // No previous error. |
| current_class(), |
| type_pos, |
| - ClassFinalizer::kTryResolve, // No compile-time error. |
| - "factory '%s' may not redirect to %s'%s'", |
| + ClassFinalizer::kResolveTypeParameters, // No compile-time error. |
| + "factory '%s' may not redirect to type parameter '%s'", |
| method->name->ToCString(), |
| - type.IsTypeParameter() ? "type parameter " : "", |
| - type.IsTypeParameter() ? |
| - String::Handle(type.UserVisibleName()).ToCString() : "dynamic"); |
| + String::Handle(type.UserVisibleName()).ToCString()); |
| } else { |
| redirection_type ^= type.raw(); |
| } |
| @@ -3022,11 +3019,15 @@ |
| // invocation/compilation. |
| // For instance fields, the expression is parsed when a constructor |
| // is compiled. |
| - // For static fields with very simple initializer expressions |
| + // For static const fields with very simple initializer expressions |
| // (e.g. a literal number or string) we optimize away the |
| // kConstImplicitGetter and initialize the field here. |
| + // We also do it for static final non-const fields, but only in production |
| + // mode. |
| - if (field->has_static && (field->has_final || field->has_const) && |
| + if (field->has_static && |
| + (field->has_const || |
| + (!FLAG_enable_type_checks && field->has_final)) && |
| (LookaheadToken(1) == Token::kSEMICOLON)) { |
| has_simple_literal = IsSimpleLiteral(*field->type, &init_value); |
| } |
| @@ -3215,7 +3216,7 @@ |
| // because getters and setters could be closurized at some time (not |
| // supported yet). |
| member.type = &AbstractType::ZoneHandle( |
| - ParseType(ClassFinalizer::kTryResolve)); |
| + ParseType(ClassFinalizer::kResolveTypeParameters)); |
| } |
| } |
| } |
| @@ -3464,18 +3465,13 @@ |
| if (CurrentToken() == Token::kEXTENDS) { |
| ConsumeToken(); |
| const intptr_t type_pos = TokenPos(); |
| - super_type = ParseType(ClassFinalizer::kTryResolve); |
| + super_type = ParseType(ClassFinalizer::kResolveTypeParameters); |
| if (super_type.IsTypeParameter()) { |
| ErrorMsg(type_pos, |
| "class '%s' may not extend type parameter '%s'", |
| class_name.ToCString(), |
| String::Handle(super_type.UserVisibleName()).ToCString()); |
| } |
| - if (super_type.IsDynamicType()) { |
| - ErrorMsg(type_pos, |
| - "class '%s' may not extend 'dynamic'", |
| - class_name.ToCString()); |
| - } |
| if (CurrentToken() == Token::kWITH) { |
| super_type = ParseMixins(super_type); |
| } |
| @@ -3671,7 +3667,7 @@ |
| const intptr_t type_pos = TokenPos(); |
| AbstractType& type = |
| - AbstractType::Handle(ParseType(ClassFinalizer::kTryResolve)); |
| + AbstractType::Handle(ParseType(ClassFinalizer::kResolveTypeParameters)); |
| if (type.IsTypeParameter()) { |
| ErrorMsg(type_pos, |
| "class '%s' may not extend type parameter '%s'", |
| @@ -3787,7 +3783,7 @@ |
| // result type. |
| if (!result_type.IsNull()) { |
| ResolveTypeFromClass(function_type_alias, |
| - ClassFinalizer::kTryResolve, |
| + ClassFinalizer::kResolveTypeParameters, |
| &result_type); |
| } |
| // Parse the formal parameters of the function type. |
| @@ -3984,7 +3980,7 @@ |
| type_parameter ^= type_parameters.TypeAt(i); |
| type_parameter_bound = type_parameter.bound(); |
| ResolveTypeFromClass(cls, |
| - ClassFinalizer::kTryResolve, |
| + ClassFinalizer::kResolveTypeParameters, |
| &type_parameter_bound); |
| type_parameter.set_bound(type_parameter_bound); |
| } |
| @@ -4046,15 +4042,12 @@ |
| do { |
| ConsumeToken(); |
| intptr_t interface_pos = TokenPos(); |
| - interface = ParseType(ClassFinalizer::kTryResolve); |
| + interface = ParseType(ClassFinalizer::kResolveTypeParameters); |
| if (interface.IsTypeParameter()) { |
| ErrorMsg(interface_pos, |
| "type parameter '%s' may not be used in interface list", |
| String::Handle(interface.UserVisibleName()).ToCString()); |
| } |
| - if (interface.IsDynamicType()) { |
| - ErrorMsg(interface_pos, "'dynamic' may not be used in interface list"); |
| - } |
| all_interfaces.Add(interface); |
| } while (CurrentToken() == Token::kCOMMA); |
| cls_interfaces = Array::MakeArray(all_interfaces); |
| @@ -4080,7 +4073,7 @@ |
| do { |
| ConsumeToken(); |
| const intptr_t mixin_pos = TokenPos(); |
| - mixin_type = ParseType(ClassFinalizer::kTryResolve); |
| + mixin_type = ParseType(ClassFinalizer::kResolveTypeParameters); |
| if (mixin_type.IsTypeParameter()) { |
| ErrorMsg(mixin_pos, |
| "mixin type '%s' may not be a type parameter", |
| @@ -4113,7 +4106,7 @@ |
| // to get the copy is to rewind the parser, parse the mixin type |
| // again and steal its type arguments. |
| SetPosition(mixin_pos); |
| - mixin_type = ParseType(ClassFinalizer::kTryResolve); |
| + mixin_type = ParseType(ClassFinalizer::kResolveTypeParameters); |
| mixin_type_arguments = mixin_type.arguments(); |
| mixin_application_type = Type::New(mixin_application, |
| @@ -4136,7 +4129,7 @@ |
| const bool is_static = true; |
| const AbstractType& type = |
| AbstractType::ZoneHandle(ParseConstFinalVarOrType( |
| - FLAG_enable_type_checks ? ClassFinalizer::kTryResolve : |
| + FLAG_enable_type_checks ? ClassFinalizer::kResolveTypeParameters : |
| ClassFinalizer::kIgnore)); |
| Field& field = Field::Handle(); |
| Function& getter = Function::Handle(); |
| @@ -4175,7 +4168,8 @@ |
| ConsumeToken(); |
| Instance& field_value = Instance::Handle(Object::sentinel().raw()); |
| bool has_simple_literal = false; |
| - if (is_final && (LookaheadToken(1) == Token::kSEMICOLON)) { |
| + if ((is_const || (!FLAG_enable_type_checks && is_final)) && |
| + (LookaheadToken(1) == Token::kSEMICOLON)) { |
| has_simple_literal = IsSimpleLiteral(type, &field_value); |
| } |
| SkipExpr(); |
| @@ -4234,7 +4228,7 @@ |
| // Parse optional type. |
| if ((CurrentToken() == Token::kIDENT) && |
| (LookaheadToken(1) != Token::kLPAREN)) { |
| - result_type = ParseType(ClassFinalizer::kTryResolve); |
| + result_type = ParseType(ClassFinalizer::kResolveTypeParameters); |
| } |
| } |
| const intptr_t name_pos = TokenPos(); |
| @@ -4328,7 +4322,7 @@ |
| ConsumeToken(); |
| result_type = Type::VoidType(); |
| } else { |
| - result_type = ParseType(ClassFinalizer::kTryResolve); |
| + result_type = ParseType(ClassFinalizer::kResolveTypeParameters); |
| } |
| is_getter = (CurrentToken() == Token::kGET); |
| if (CurrentToken() == Token::kGET || CurrentToken() == Token::kSET) { |
| @@ -5324,30 +5318,34 @@ |
| bool Parser::IsSimpleLiteral(const AbstractType& type, Instance* value) { |
| - bool no_check = type.IsDynamicType(); |
| - if ((CurrentToken() == Token::kINTEGER) && |
| - (no_check || type.IsIntType() || type.IsNumberType())) { |
| + // Assigning null never causes a type error. |
| + if (CurrentToken() == Token::kNULL) { |
| + *value = Instance::null(); |
| + return true; |
| + } |
| + // If the type of the const field is guaranteed to be instantiated once |
| + // resolved at class finalization time, and if the type of the literal is one |
| + // of int, double, String, or bool, then preset the field with the value and |
| + // perform the type check (in checked mode only) at finalization time. |
| + if (type.IsTypeParameter() || // Always resolved at parse time. |
|
hausner
2013/07/12 05:30:22
At parse time of what? I don't understand the comm
regis
2013/07/12 17:58:55
I clarified the comment.
|
| + (type.arguments() != AbstractTypeArguments::null())) { |
| + return false; |
| + } |
| + if (CurrentToken() == Token::kINTEGER) { |
| *value = CurrentIntegerLiteral(); |
| return true; |
| - } else if ((CurrentToken() == Token::kDOUBLE) && |
| - (no_check || type.IsDoubleType() || type.IsNumberType())) { |
| + } else if (CurrentToken() == Token::kDOUBLE) { |
| *value = CurrentDoubleLiteral(); |
| return true; |
| - } else if ((CurrentToken() == Token::kSTRING) && |
| - (no_check || type.IsStringType())) { |
| + } else if (CurrentToken() == Token::kSTRING) { |
| *value = CurrentLiteral()->raw(); |
| return true; |
| - } else if ((CurrentToken() == Token::kTRUE) && |
| - (no_check || type.IsBoolType())) { |
| + } else if (CurrentToken() == Token::kTRUE) { |
| *value = Bool::True().raw(); |
| return true; |
| - } else if ((CurrentToken() == Token::kFALSE) && |
| - (no_check || type.IsBoolType())) { |
| + } else if (CurrentToken() == Token::kFALSE) { |
| *value = Bool::False().raw(); |
| return true; |
| - } else if (CurrentToken() == Token::kNULL) { |
| - *value = Instance::null(); |
| - return true; |
| } |
| return false; |
| } |
| @@ -8002,7 +8000,7 @@ |
| void Parser::ResolveTypeFromClass(const Class& scope_class, |
| ClassFinalizer::FinalizationKind finalization, |
| AbstractType* type) { |
| - ASSERT(finalization >= ClassFinalizer::kTryResolve); |
| + ASSERT(finalization >= ClassFinalizer::kResolveTypeParameters); |
| ASSERT(type != NULL); |
| if (type->IsResolved()) { |
| return; |
| @@ -8050,25 +8048,29 @@ |
| return; |
| } |
| } |
| - // Resolve classname in the scope of the current library. |
| - Error& error = Error::Handle(); |
| - // If we finalize a type expression, as opposed to a type annotation, we |
| - // tell the resolver (by passing NULL) to immediately report an ambiguous |
| - // type as a compile time error. |
| - resolved_type_class = ResolveClassInCurrentLibraryScope( |
| - unresolved_class.token_pos(), |
| - unresolved_class_name, |
| - finalization >= ClassFinalizer::kCanonicalizeExpression ? |
| - NULL : &error); |
| - if (!error.IsNull()) { |
| - *type = ClassFinalizer::NewFinalizedMalformedType( |
| - error, |
| - scope_class, |
| + // The referenced class may not have been parsed yet. It would be wrong |
| + // to resolve it too early to an imported class of the same name. |
| + if (finalization > ClassFinalizer::kResolveTypeParameters) { |
| + // Resolve classname in the scope of the current library. |
| + Error& error = Error::Handle(); |
| + // If we finalize a type expression, as opposed to a type annotation, |
| + // we tell the resolver (by passing NULL) to immediately report an |
| + // ambiguous type as a compile time error. |
| + resolved_type_class = ResolveClassInCurrentLibraryScope( |
| unresolved_class.token_pos(), |
| - finalization, |
| - "cannot resolve class '%s'", |
| - unresolved_class_name.ToCString()); |
| - return; |
| + unresolved_class_name, |
| + finalization >= ClassFinalizer::kCanonicalizeExpression ? |
| + NULL : &error); |
| + if (!error.IsNull()) { |
| + *type = ClassFinalizer::NewFinalizedMalformedType( |
| + error, |
| + scope_class, |
| + unresolved_class.token_pos(), |
| + finalization, |
| + "cannot resolve class '%s'", |
| + unresolved_class_name.ToCString()); |
| + return; |
| + } |
| } |
| } else { |
| LibraryPrefix& lib_prefix = |
| @@ -8530,8 +8532,8 @@ |
| if (first_lib_url.raw() == lib.url()) { |
| ambiguous_ref_error = FormatErrorMsg( |
| script_, ident_pos, "Error", |
| - "ambiguous reference: " |
| - "'%s' as library '%s' is imported multiple times", |
| + "ambiguous reference to '%s', " |
| + "as library '%s' is imported multiple times", |
| name.ToCString(), |
| first_lib_url.ToCString()); |
| } else { |
| @@ -8850,7 +8852,7 @@ |
| parameterized_type.set_arguments(Object::null_abstract_type_arguments()); |
| parameterized_type.set_malformed_error(malformed_error); |
| } |
| - if (finalization >= ClassFinalizer::kTryResolve) { |
| + if (finalization >= ClassFinalizer::kResolveTypeParameters) { |
| ResolveTypeFromClass(current_class(), finalization, &type); |
| if (finalization >= ClassFinalizer::kCanonicalize) { |
| type ^= ClassFinalizer::FinalizeType(current_class(), type, finalization); |
| @@ -8953,6 +8955,7 @@ |
| AstNode* elem = element_list[i]; |
| // Arguments have been evaluated to a literal value already. |
| ASSERT(elem->IsLiteralNode()); |
| + ASSERT(!is_top_level_); // We cannot check unresolved types. |
| if (FLAG_enable_type_checks && |
| !element_type.IsDynamicType() && |
| (!elem->AsLiteralNode()->literal().IsNull() && |
| @@ -9149,6 +9152,7 @@ |
| AstNode* arg = kv_pairs_list[i]; |
| // Arguments have been evaluated to a literal value already. |
| ASSERT(arg->IsLiteralNode()); |
| + ASSERT(!is_top_level_); // We cannot check unresolved types. |
| if (FLAG_enable_type_checks && |
| ((i % 2) == 1) && // Check values only, not keys. |
| !value_type.IsDynamicType() && |
| @@ -9305,7 +9309,7 @@ |
| Error::Handle(), // No previous error. |
| current_class(), |
| type_pos, |
| - ClassFinalizer::kTryResolve, // No compile-time error. |
| + ClassFinalizer::kResolveTypeParameters, // No compile-time error. |
| "%s'%s' cannot be instantiated", |
| type.IsTypeParameter() ? "type parameter " : "", |
| type.IsTypeParameter() ? |
| @@ -9371,7 +9375,7 @@ |
| Error::Handle(), // No previous error. |
| current_class(), |
| call_pos, |
| - ClassFinalizer::kTryResolve, // No compile-time error. |
| + ClassFinalizer::kResolveTypeParameters, // No compile-time error. |
| "class '%s' has no constructor or factory named '%s'", |
| String::Handle(type_class.Name()).ToCString(), |
| external_constructor_name.ToCString()); |
| @@ -9482,6 +9486,7 @@ |
| if (!type_bound.IsNull()) { |
| ASSERT(!type_bound.IsMalformed()); |
| Error& malformed_error = Error::Handle(); |
| + ASSERT(!is_top_level_); // We cannot check unresolved types. |
| if (!const_instance.IsInstanceOf(type_bound, |
| TypeArguments::Handle(), |
| &malformed_error)) { |
| @@ -9489,7 +9494,7 @@ |
| malformed_error, |
| current_class(), |
| new_pos, |
| - ClassFinalizer::kTryResolve, // No compile-time error. |
| + ClassFinalizer::kResolveTypeParameters, // No compile-time error. |
| "const factory result is not an instance of '%s'", |
| String::Handle(type_bound.UserVisibleName()).ToCString()); |
| new_object = ThrowTypeError(new_pos, type_bound); |