Index: runtime/vm/parser.cc |
=================================================================== |
--- runtime/vm/parser.cc (revision 13204) |
+++ 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, throw a NoSuchMethodError. |
+ 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(); |