| Index: runtime/vm/parser.cc
|
| ===================================================================
|
| --- runtime/vm/parser.cc (revision 28841)
|
| +++ runtime/vm/parser.cc (working copy)
|
| @@ -3101,10 +3101,14 @@
|
| ErrorMsg(method->name_pos,
|
| "external method '%s' may not have a function body",
|
| method->name->ToCString());
|
| - } else if (method->IsFactoryOrConstructor() && method->has_const) {
|
| + } else if (method->IsConstructor() && method->has_const) {
|
| ErrorMsg(method->name_pos,
|
| - "const constructor or factory '%s' may not have a function body",
|
| + "const constructor '%s' may not have a function body",
|
| method->name->ToCString());
|
| + } else if (method->IsFactory() && method->has_const) {
|
| + ErrorMsg(method->name_pos,
|
| + "const factory '%s' may not have a function body",
|
| + method->name->ToCString());
|
| }
|
| if (method->redirect_name != NULL) {
|
| ErrorMsg(method->name_pos,
|
| @@ -3125,9 +3129,9 @@
|
| ErrorMsg(method->name_pos,
|
| "abstract method '%s' may not have a function body",
|
| method->name->ToCString());
|
| - } else if (method->IsFactoryOrConstructor() && method->has_const) {
|
| + } else if (method->IsConstructor() && method->has_const) {
|
| ErrorMsg(method->name_pos,
|
| - "const constructor or factory '%s' may not be native",
|
| + "const constructor '%s' may not be native",
|
| method->name->ToCString());
|
| }
|
| if (method->redirect_name != NULL) {
|
| @@ -8708,21 +8712,28 @@
|
| const AbstractTypeArguments& type_arguments,
|
| const Function& constructor,
|
| ArgumentListNode* arguments) {
|
| - const int kNumExtraArgs = 2; // implicit rcvr and construction phase args.
|
| + // Factories have one extra argument: the type arguments.
|
| + // Constructors have 2 extra arguments: rcvr and construction phase.
|
| + const int kNumExtraArgs = constructor.IsFactory() ? 1 : 2;
|
| const int num_arguments = arguments->length() + kNumExtraArgs;
|
| const Array& arg_values = Array::Handle(Array::New(num_arguments));
|
| Instance& instance = Instance::Handle();
|
| - ASSERT(!constructor.IsFactory());
|
| - instance = Instance::New(type_class, Heap::kOld);
|
| - if (!type_arguments.IsNull()) {
|
| - if (!type_arguments.IsInstantiated()) {
|
| - ErrorMsg("type must be constant in const constructor");
|
| + if (!constructor.IsFactory()) {
|
| + instance = Instance::New(type_class, Heap::kOld);
|
| + if (!type_arguments.IsNull()) {
|
| + if (!type_arguments.IsInstantiated()) {
|
| + ErrorMsg("type must be constant in const constructor");
|
| + }
|
| + instance.SetTypeArguments(
|
| + AbstractTypeArguments::Handle(type_arguments.Canonicalize()));
|
| }
|
| - instance.SetTypeArguments(
|
| - AbstractTypeArguments::Handle(type_arguments.Canonicalize()));
|
| + arg_values.SetAt(0, instance);
|
| + arg_values.SetAt(1, Smi::Handle(Smi::New(Function::kCtorPhaseAll)));
|
| + } else {
|
| + // Prepend type_arguments to list of arguments to factory.
|
| + ASSERT(type_arguments.IsZoneHandle());
|
| + arg_values.SetAt(0, type_arguments);
|
| }
|
| - arg_values.SetAt(0, instance);
|
| - arg_values.SetAt(1, Smi::Handle(Smi::New(Function::kCtorPhaseAll)));
|
| for (int i = 0; i < arguments->length(); i++) {
|
| AstNode* arg = arguments->NodeAt(i);
|
| // Arguments have been evaluated to a literal value already.
|
| @@ -8749,6 +8760,10 @@
|
| return Object::null();
|
| }
|
| } else {
|
| + if (constructor.IsFactory()) {
|
| + // The factory method returns the allocated object.
|
| + instance ^= result.raw();
|
| + }
|
| return TryCanonicalize(instance, TokenPos());
|
| }
|
| }
|
| @@ -9885,7 +9900,10 @@
|
| if (constructor_result.IsUnhandledException()) {
|
| new_object = GenerateRethrow(new_pos, constructor_result);
|
| } else {
|
| - const Instance& const_instance = Instance::Cast(constructor_result);
|
| + // Const constructors can return null in the case where a const native
|
| + // factory returns a null value. Thus we cannot use a Instance::Cast here.
|
| + Instance& const_instance = Instance::Handle();
|
| + const_instance ^= constructor_result.raw();
|
| new_object = new LiteralNode(new_pos,
|
| Instance::ZoneHandle(const_instance.raw()));
|
| if (!type_bound.IsNull()) {
|
|
|