| Index: runtime/vm/parser.cc
|
| ===================================================================
|
| --- runtime/vm/parser.cc (revision 24964)
|
| +++ 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,41 @@
|
|
|
|
|
| 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() ||
|
| + (type.arguments() != AbstractTypeArguments::null())) {
|
| + // Type parameters are always resolved eagerly by the parser and never
|
| + // resolved later by the class finalizer. Therefore, we know here that if
|
| + // 'type' is not a type parameter (an unresolved type will not get resolved
|
| + // to a type parameter later) and if 'type' has no type arguments, then it
|
| + // will be instantiated at class finalization time. Otherwise, we return
|
| + // false, since the type test would not be possible at finalization time for
|
| + // an uninstantiated type.
|
| + 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 +8007,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 +8055,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 +8539,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 +8859,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 +8962,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 +9159,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 +9316,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 +9382,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 +9493,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 +9501,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);
|
|
|