Index: runtime/vm/parser.cc |
=================================================================== |
--- runtime/vm/parser.cc (revision 12790) |
+++ runtime/vm/parser.cc (working copy) |
@@ -519,7 +519,7 @@ |
const AbstractType* type; |
intptr_t name_pos; |
String* name; |
- // For constructors: NULL or redirected constructor. |
+ // For constructors: NULL or name of redirected to constructor. |
String* redirect_name; |
// For constructors: NULL for unnamed constructor, |
// identifier after classname for named constructors. |
@@ -708,6 +708,8 @@ |
case RawFunction::kGetterFunction: |
case RawFunction::kSetterFunction: |
case RawFunction::kConstructor: |
+ // The call to a redirecting factory is redirected. |
+ ASSERT(!func.IsRedirectingFactory()); |
node_sequence = parser.ParseFunc(func, default_parameter_values); |
break; |
case RawFunction::kImplicitGetter: |
@@ -2360,7 +2362,7 @@ |
ErrorMsg(method->name_pos, "constructor cannot be abstract"); |
} |
if (method->IsConstructor() && method->has_const) { |
- Class& cls = Class::ZoneHandle(library_.LookupClass(members->class_name())); |
+ Class& cls = Class::Handle(library_.LookupClass(members->class_name())); |
cls.set_is_const(); |
} |
if (method->has_abstract && members->is_interface()) { |
@@ -2382,7 +2384,7 @@ |
// the type of the instance to be allocated. |
if (!method->has_static || method->IsConstructor()) { |
method->params.AddReceiver(ReceiverType(formal_param_pos)); |
- } else if (method->has_factory) { |
+ } else if (method->IsFactory()) { |
method->params.AddFinalParameter( |
formal_param_pos, |
&String::ZoneHandle(Symbols::TypeArgumentsParameter()), |
@@ -2443,8 +2445,27 @@ |
} |
} |
- // Parse initializers. |
- if (CurrentToken() == Token::kCOLON) { |
+ // Parse redirecting factory constructor. |
+ Type& redirection_type = Type::Handle(); |
+ String& redirection_identifier = String::Handle(); |
+ if (method->IsFactory() && (CurrentToken() == Token::kASSIGN)) { |
+ ConsumeToken(); |
+ const intptr_t type_pos = TokenPos(); |
+ const AbstractType& type = AbstractType::Handle( |
+ ParseType(ClassFinalizer::kTryResolve)); |
+ if (type.IsTypeParameter()) { |
+ // TODO(regis): Spec is not clear. Throw dynamic error or report |
+ // compile-time error? Same question for new and const operators. |
+ ErrorMsg(type_pos, "factory may not redirect via a type parameter"); |
+ } |
+ redirection_type ^= type.raw(); |
+ if (CurrentToken() == Token::kPERIOD) { |
+ // Named constructor or factory. |
+ ConsumeToken(); |
+ redirection_identifier = ExpectIdentifier("identifier expected")->raw(); |
+ } |
+ } else if (CurrentToken() == Token::kCOLON) { |
+ // Parse initializers. |
if (!method->IsConstructor()) { |
ErrorMsg("initializers only allowed on constructors"); |
} |
@@ -2538,7 +2559,9 @@ |
// We haven't found a method body. Issue error if one is required. |
const bool must_have_body = |
!members->is_interface() && |
- method->has_static && !method->has_external; |
+ method->has_static && |
+ !method->has_external && |
+ redirection_type.IsNull(); |
if (must_have_body) { |
ErrorMsg(method->name_pos, |
"function body expected for method '%s'", |
@@ -2595,6 +2618,15 @@ |
func.set_result_type(*method->type); |
func.set_end_token_pos(method_end_pos); |
+ // If this method is a redirecting factory, set the redirection information. |
+ if (!redirection_type.IsNull()) { |
+ ASSERT(func.IsFactory()); |
+ func.SetRedirectionType(redirection_type); |
+ if (!redirection_identifier.IsNull()) { |
+ func.SetRedirectionIdentifier(redirection_identifier); |
+ } |
+ } |
+ |
// No need to resolve parameter types yet, or add parameters to local scope. |
ASSERT(is_top_level_); |
AddFormalParamsToFunction(&method->params, func); |
@@ -2971,6 +3003,7 @@ |
if (member.type == NULL) { |
member.type = &Type::ZoneHandle(Type::DynamicType()); |
} |
+ ASSERT(member.IsFactory() == member.has_factory); |
ParseMethodOrConstructor(members, &member); |
if (member.has_operator) { |
CheckOperatorArity(member, operator_token); |
@@ -8719,7 +8752,7 @@ |
ErrorMsg("type name expected"); |
} |
intptr_t type_pos = TokenPos(); |
- const AbstractType& type = AbstractType::Handle( |
+ AbstractType& type = AbstractType::Handle( |
ParseType(ClassFinalizer::kCanonicalizeWellFormed)); |
// Malformed bounds never result in a compile time error, therefore, the |
// parsed type may be malformed although we requested kCanonicalizeWellFormed. |
@@ -8733,7 +8766,7 @@ |
if (type.IsDynamicType()) { |
ErrorMsg(type_pos, "Dynamic cannot be instantiated"); |
} |
- const Class& type_class = Class::Handle(type.type_class()); |
+ Class& type_class = Class::Handle(type.type_class()); |
const String& type_class_name = String::Handle(type_class.Name()); |
AbstractTypeArguments& type_arguments = |
AbstractTypeArguments::ZoneHandle(type.arguments()); |
@@ -8828,21 +8861,39 @@ |
constructor_class.LookupConstructor(constructor_name)); |
if (constructor.IsNull()) { |
constructor = constructor_class.LookupFactory(constructor_name); |
- // A factory does not have the implicit 'phase' parameter. |
- arguments_length -= 1; |
+ if (constructor.IsNull()) { |
+ const String& external_constructor_name = |
+ (named_constructor ? constructor_name : constructor_class_name); |
+ ErrorMsg(type_pos, |
+ "class '%s' has no constructor or factory named '%s'", |
+ String::Handle(constructor_class.Name()).ToCString(), |
+ external_constructor_name.ToCString()); |
+ } else if (constructor.IsRedirectingFactory()) { |
+ type = constructor.RedirectionType(); |
+ constructor = constructor.RedirectionTarget(); |
+ if (constructor.IsNull()) { |
+ // TODO(regis): We normally report a compile-time error if the |
+ // constructor is not found. See above. However, we should throw a |
+ // dynamic error instead. We do it here. This is the first step. |
+ ASSERT(type.IsMalformed()); |
+ } else { |
+ type_class = type.type_class(); |
+ type_arguments = type.arguments(); |
+ constructor_class = constructor.Owner(); |
+ ASSERT(type_class.raw() == constructor_class.raw()); |
+ } |
+ } |
+ if (!constructor.IsNull() && constructor.IsFactory()) { |
+ // A factory does not have the implicit 'phase' parameter. |
+ arguments_length -= 1; |
+ } |
} |
- if (constructor.IsNull()) { |
- const String& external_constructor_name = |
- (named_constructor ? constructor_name : constructor_class_name); |
- ErrorMsg(type_pos, |
- "class '%s' has no constructor or factory named '%s'", |
- String::Handle(constructor_class.Name()).ToCString(), |
- external_constructor_name.ToCString()); |
- } |
// It is ok to call a factory method of an abstract class, but it is |
// a dynamic error to instantiate an abstract class. |
- if (constructor_class.is_abstract() && !constructor.IsFactory()) { |
+ if (!constructor.IsNull() && |
+ constructor_class.is_abstract() && |
+ !constructor.IsFactory()) { |
ArgumentListNode* arguments = new ArgumentListNode(type_pos); |
arguments->Add(new LiteralNode( |
TokenPos(), Integer::ZoneHandle(Integer::New(type_pos)))); |
@@ -8855,7 +8906,8 @@ |
} |
String& error_message = String::Handle(); |
- if (!constructor.AreValidArguments(arguments_length, |
+ if (!constructor.IsNull() && |
+ !constructor.AreValidArguments(arguments_length, |
arguments->names(), |
&error_message)) { |
const String& external_constructor_name = |
@@ -8874,7 +8926,7 @@ |
// factory class, we need to finalize the type argument vector again, because |
// it may be longer due to the factory class extending a class, or/and because |
// the bounds on the factory class may be tighter than on the interface. |
- if (constructor_class.raw() != type_class.raw()) { |
+ if (!constructor.IsNull() && (constructor_class.raw() != type_class.raw())) { |
const intptr_t num_type_parameters = constructor_class.NumTypeParameters(); |
TypeArguments& temp_type_arguments = TypeArguments::Handle(); |
if (!type_arguments.IsNull()) { |
@@ -8909,7 +8961,11 @@ |
type.set_malformed_error(error); |
} |
} |
- |
+ if (type.IsMalformed()) { |
+ // Compile the throw of a dynamic type error due to a bound error or to |
+ // a redirection error. |
+ return ThrowTypeError(type_pos, type); |
+ } |
type_arguments ^= type_arguments.Canonicalize(); |
// Make the constructor call. |
AstNode* new_object = NULL; |
@@ -8918,10 +8974,6 @@ |
ErrorMsg("'const' requires const constructor: '%s'", |
String::Handle(constructor.name()).ToCString()); |
} |
- if (type.IsMalformed()) { |
- // Compile the throw of a dynamic type error due to a bound error. |
- return ThrowTypeError(type_pos, type); |
- } |
const Object& constructor_result = Object::Handle( |
EvaluateConstConstructorCall(constructor_class, |
type_arguments, |
@@ -8943,10 +8995,6 @@ |
// Make sure that the instantiator is captured. |
CaptureInstantiator(); |
} |
- if (type.IsMalformed()) { |
- // Compile the throw of a dynamic type error due to a bound error. |
- return ThrowTypeError(type_pos, type); |
- } |
// If the type argument vector is not instantiated, we verify in checked |
// mode at runtime that it is within its declared bounds. |
new_object = CreateConstructorCallNode( |