Chromium Code Reviews| Index: runtime/vm/parser.cc |
| =================================================================== |
| --- runtime/vm/parser.cc (revision 13198) |
| +++ runtime/vm/parser.cc (working copy) |
| @@ -1513,7 +1513,7 @@ |
| } |
| return new StaticGetterNode( |
| - field_pos, implicit_argument, true, super_class, field_name); |
| + field_pos, implicit_argument, true, super_class, field_name); |
| } |
| @@ -3646,6 +3646,10 @@ |
| // Map a malformed type argument to Dynamic, so that malformed types with |
| // a resolved type class are handled properly in production mode. |
| if (type.IsMalformed()) { |
| + ASSERT(finalization != ClassFinalizer::kCanonicalizeWellFormed); |
| + if (finalization == ClassFinalizer::kCanonicalizeForCreation) { |
| + ErrorMsg(*malformed_error); |
| + } |
| type = Type::DynamicType(); |
| } |
| types.Add(type); |
| @@ -6676,6 +6680,20 @@ |
| } |
| +AstNode* Parser::ThrowNoSuchMethodError(intptr_t call_pos, const String& name) { |
| + ArgumentListNode* arguments = new ArgumentListNode(call_pos); |
| + // Location argument. |
| + arguments->Add(new LiteralNode( |
| + call_pos, Integer::ZoneHandle(Integer::New(call_pos)))); |
| + // Function name argument. |
| + arguments->Add(new LiteralNode( |
| + call_pos, String::ZoneHandle(Symbols::New(name)))); |
| + const String& cls_name = String::Handle(Symbols::NoSuchMethodError()); |
| + const String& func_name = String::Handle(Symbols::ThrowNew()); |
| + return MakeStaticCall(cls_name, func_name, arguments); |
| +} |
| + |
| + |
| AstNode* Parser::ParseBinaryExpr(int min_preced) { |
| TRACE_PARSER("ParseBinaryExpr"); |
| ASSERT(min_preced >= 4); |
| @@ -6944,6 +6962,11 @@ |
| // Ensure that the expression temp is allocated for nodes that may need it. |
| AstNode* Parser::CreateAssignmentNode(AstNode* original, AstNode* rhs) { |
| AstNode* result = original->MakeAssignmentNode(rhs); |
| + if ((result == NULL) && original->IsStaticGetterNode()) { |
| + const String& setter_name = String::ZoneHandle( |
| + Field::SetterSymbol(original->AsStaticGetterNode()->field_name())); |
| + result = ThrowNoSuchMethodError(original->token_pos(), setter_name); |
| + } |
| if ((result != NULL) && |
| (result->IsStoreIndexedNode() || |
| result->IsInstanceSetterNode() || |
| @@ -7219,22 +7242,8 @@ |
| closure = GenerateStaticFieldLookup(field, call_pos); |
| return new ClosureCallNode(call_pos, closure, arguments); |
| } |
| - // Could not resolve static method: throw an exception if the arguments |
| - // do not match or compile time error otherwise. |
| - const Function& test_func = Function::Handle( |
| - Resolver::ResolveStaticByName(cls, func_name, Resolver::kIsQualified)); |
| - if (test_func.IsNull()) { |
| - ErrorMsg(ident_pos, "unresolved static method '%s'", |
| - func_name.ToCString()); |
| - } else { |
| - ArgumentListNode* arguments = new ArgumentListNode(ident_pos); |
| - arguments->Add(new LiteralNode( |
| - TokenPos(), Integer::ZoneHandle(Integer::New(ident_pos)))); |
| - const String& cls_name = |
| - String::Handle(Symbols::StaticResolutionException()); |
| - const String& func_name = String::Handle(Symbols::ThrowNew()); |
| - return MakeStaticCall(cls_name, func_name, arguments); |
| - } |
| + // Could not resolve static method: throw a NoSuchMethodError. |
| + return ThrowNoSuchMethodError(ident_pos, func_name); |
| } |
| CheckFunctionIsCallable(call_pos, func); |
| return new StaticCallNode(call_pos, func, arguments); |
| @@ -7306,9 +7315,8 @@ |
| kNoArgumentNames, |
| Resolver::kIsQualified); |
| if (func.IsNull()) { |
| - // No field or explicit setter function, this is an error. |
| - ErrorMsg(ident_pos, "unknown static field '%s'", |
| - field_name.ToCString()); |
| + // No field or explicit setter function, throw a NoSuchMethodError. |
| + return ThrowNoSuchMethodError(ident_pos, field_name); |
| } |
| // Explicit setter function for the field found, field does not exist. |
| @@ -7348,9 +7356,8 @@ |
| // there is a function of the same name. |
| func = cls.LookupStaticFunction(field_name); |
| if (func.IsNull()) { |
| - // No field or explicit getter function, this is an error. |
| - ErrorMsg(ident_pos, |
| - "unknown static field '%s'", field_name.ToCString()); |
| + // No field or explicit getter function, hrow a NoSuchMethodError. |
|
srdjan
2012/10/03 23:28:03
s/hrow/throw/
regis
2012/10/04 00:12:23
Done.
|
| + return ThrowNoSuchMethodError(ident_pos, field_name); |
| } |
| access = CreateImplicitClosureNode(func, call_pos, NULL); |
| } else { |
| @@ -7375,15 +7382,14 @@ |
| } |
| PrimaryNode* primary = node->AsPrimaryNode(); |
| if (primary->primary().IsString()) { |
| - // In a static method, an unresolved identifier is an error. |
| + // In a static method, evaluation of an unresolved identifier causes a |
| + // NoSuchMethodError to be thrown. |
| // In an instance method, we convert this into a getter call |
| // for a field (which may be defined in a subclass.) |
| String& name = String::CheckedZoneHandle(primary->primary().raw()); |
| if (current_function().is_static() || |
| current_function().IsInFactoryScope()) { |
| - ErrorMsg(primary->token_pos(), |
| - "identifier '%s' is not declared in this scope", |
| - name.ToCString()); |
| + return ThrowNoSuchMethodError(primary->token_pos(), name); |
| } else { |
| AstNode* receiver = LoadReceiver(primary->token_pos()); |
| return CallGetter(node->token_pos(), receiver, name); |
| @@ -7508,9 +7514,7 @@ |
| // Primary is an unresolved name. |
| String& name = String::CheckedZoneHandle(primary->primary().raw()); |
| if (current_function().is_static()) { |
| - ErrorMsg(primary->token_pos(), |
| - "identifier '%s' is not declared in this scope", |
| - name.ToCString()); |
| + selector = ThrowNoSuchMethodError(primary->token_pos(), name); |
| } else { |
| // Treat as call to unresolved (instance) method. |
| AstNode* receiver = LoadReceiver(primary->token_pos()); |
| @@ -8350,12 +8354,12 @@ |
| PrimaryNode* primary = resolved->AsPrimaryNode(); |
| if (primary->primary().IsString()) { |
| // We got an unresolved name. If we are compiling a static |
| - // method, this is an error. In an instance method, we convert |
| + // method, evaluation of an unresolved identifier causes a |
| + // NoSuchMethodError to be thrown. In an instance method, we convert |
| // the unresolved name to an instance field access, since a |
| // subclass might define a field with this name. |
| if (current_function().is_static()) { |
| - ErrorMsg(ident_pos, "identifier '%s' is not declared in this scope", |
| - ident.ToCString()); |
| + resolved = ThrowNoSuchMethodError(ident_pos, ident); |
| } else { |
| // Treat as call to unresolved instance field. |
| resolved = CallGetter(ident_pos, LoadReceiver(ident_pos), ident); |
| @@ -8864,7 +8868,7 @@ |
| } |
| intptr_t type_pos = TokenPos(); |
| AbstractType& type = AbstractType::Handle( |
| - ParseType(ClassFinalizer::kCanonicalizeWellFormed)); |
| + ParseType(ClassFinalizer::kCanonicalizeForCreation)); |
| // In case the type is malformed, throw a dynamic type error after finishing |
| // parsing the instance creation expression. |
| if (type.IsTypeParameter() || type.IsDynamicType()) { |
| @@ -8895,8 +8899,13 @@ |
| intptr_t call_pos = TokenPos(); |
| ArgumentListNode* arguments = ParseActualParameters(NULL, is_const); |
| - // Parsing is complete, so we can return a throw in case of a malformed type. |
| + // Parsing is complete, so we can return a throw in case of a malformed type |
| + // or report a compile-time error if the constructor is const. |
| if (type.IsMalformed()) { |
| + if (is_const) { |
| + const Error& error = Error::Handle(type.malformed_error()); |
| + ErrorMsg(error); |
| + } |
| return ThrowTypeError(type_pos, type); |
| } |
| @@ -8927,30 +8936,33 @@ |
| Function& constructor = Function::ZoneHandle( |
| type_class.LookupConstructor(constructor_name)); |
| if (constructor.IsNull()) { |
| - // Replace the type with a malformed type and compile a throw. |
| + // Replace the type with a malformed type and compile a throw or report |
| + // a compile-time error if the constructor is const. |
| type = ClassFinalizer::NewFinalizedMalformedType( |
| current_class(), |
| - type_pos, |
| + call_pos, |
| "interface '%s' has no constructor named '%s'", |
| type_class_name.ToCString(), |
| external_constructor_name.ToCString()); |
| - return ThrowTypeError(type_pos, type); |
| + if (is_const) { |
| + const Error& error = Error::Handle(type.malformed_error()); |
| + ErrorMsg(error); |
| + } |
| + return ThrowNoSuchMethodError(call_pos, external_constructor_name); |
| } |
| - // TODO(regis): Throw a NoSuchMethodError instead of a TypeError. |
| String& error_message = String::Handle(); |
| if (!constructor.AreValidArguments(arguments_length, |
| arguments->names(), |
| &error_message)) { |
| - // Replace the type with a malformed type and compile a throw. |
| - type = ClassFinalizer::NewFinalizedMalformedType( |
| - current_class(), |
| - call_pos, |
| - "invalid arguments passed to constructor '%s' " |
| - "for interface '%s': %s", |
| - external_constructor_name.ToCString(), |
| - type_class_name.ToCString(), |
| - error_message.ToCString()); |
| - return ThrowTypeError(call_pos, type); |
| + if (is_const) { |
| + ErrorMsg(call_pos, |
| + "invalid arguments passed to constructor '%s' " |
| + "for interface '%s': %s", |
| + external_constructor_name.ToCString(), |
| + type_class_name.ToCString(), |
| + error_message.ToCString()); |
| + } |
| + return ThrowNoSuchMethodError(call_pos, external_constructor_name); |
| } |
| // TODO(regis): Remove support for obsolete default factory classes. |
| if (!type_class.HasFactoryClass()) { |
| @@ -8992,17 +9004,26 @@ |
| if (constructor.IsNull()) { |
| const String& external_constructor_name = |
| (named_constructor ? constructor_name : constructor_class_name); |
| - // Replace the type with a malformed type and compile a throw. |
| + // Replace the type with a malformed type and compile a throw or report a |
| + // compile-time error if the constructor is const. |
| type = ClassFinalizer::NewFinalizedMalformedType( |
| current_class(), |
| - type_pos, |
| + call_pos, |
| "class '%s' has no constructor or factory named '%s'", |
| String::Handle(constructor_class.Name()).ToCString(), |
| external_constructor_name.ToCString()); |
| - return ThrowTypeError(type_pos, type); |
| + if (is_const) { |
| + const Error& error = Error::Handle(type.malformed_error()); |
| + ErrorMsg(error); |
| + } |
| + return ThrowNoSuchMethodError(call_pos, external_constructor_name); |
| } else if (constructor.IsRedirectingFactory()) { |
| type = constructor.RedirectionType(); |
| if (type.IsMalformed()) { |
| + if (is_const) { |
| + const Error& error = Error::Handle(type.malformed_error()); |
| + ErrorMsg(error); |
| + } |
| return ThrowTypeError(type.token_pos(), type); |
| } |
| constructor = constructor.RedirectionTarget(); |
| @@ -9033,22 +9054,21 @@ |
| const String& func_name = String::Handle(Symbols::ThrowNew()); |
| return MakeStaticCall(cls_name, func_name, arguments); |
| } |
| - // TODO(regis): Throw a NoSuchMethodError instead of a TypeError. |
| String& error_message = String::Handle(); |
| if (!constructor.AreValidArguments(arguments_length, |
| arguments->names(), |
| &error_message)) { |
| const String& external_constructor_name = |
| (named_constructor ? constructor_name : constructor_class_name); |
| - // Replace the type with a malformed type and compile a throw when called. |
| - type = ClassFinalizer::NewFinalizedMalformedType( |
| - current_class(), |
| - call_pos, |
| - "invalid arguments passed to constructor '%s' for class '%s': %s", |
| - external_constructor_name.ToCString(), |
| - String::Handle(constructor_class.Name()).ToCString(), |
| - error_message.ToCString()); |
| - return ThrowTypeError(call_pos, type); |
| + if (is_const) { |
| + ErrorMsg(call_pos, |
| + "invalid arguments passed to constructor '%s' " |
| + "for class '%s': %s", |
| + external_constructor_name.ToCString(), |
| + String::Handle(constructor_class.Name()).ToCString(), |
| + error_message.ToCString()); |
| + } |
| + return ThrowNoSuchMethodError(call_pos, external_constructor_name); |
| } |
| // Now that the constructor to be called is identified, finalize the type |
| @@ -9093,8 +9113,13 @@ |
| type.set_malformed_error(error); |
| } |
| } |
| + // Return a throw in case of a malformed type or report a compile-time error |
| + // if the constructor is const. |
| if (type.IsMalformed()) { |
| - // Return the throw of a dynamic type error if the type is malformed. |
| + if (is_const) { |
| + const Error& error = Error::Handle(type.malformed_error()); |
| + ErrorMsg(error); |
| + } |
| return ThrowTypeError(type_pos, type); |
| } |
| type_arguments ^= type_arguments.Canonicalize(); |