| Index: runtime/vm/parser.cc
|
| ===================================================================
|
| --- runtime/vm/parser.cc (revision 1098)
|
| +++ runtime/vm/parser.cc (working copy)
|
| @@ -41,6 +41,7 @@
|
| static const char* kStringClassName = "StringBase";
|
| static const char* kInterpolateName = "_interpolate";
|
| static const char* kThisName = "this";
|
| +static const char* kPhaseParameterName = ":phase";
|
| static const char* kGetIteratorName = "iterator";
|
|
|
| #if defined(DEBUG)
|
| @@ -1037,10 +1038,11 @@
|
| const Function& super_function = Function::ZoneHandle(
|
| GetSuperFunction(supercall_pos, function_name));
|
|
|
| + ArgumentListNode* arguments = new ArgumentListNode(supercall_pos);
|
| // 'this' parameter is the first argument to super call.
|
| AstNode* receiver = LoadReceiver(supercall_pos);
|
| - ArgumentListNode* arguments =
|
| - ParseActualParameters(receiver, kAllowConst);
|
| + arguments->Add(receiver);
|
| + ParseActualParameters(arguments, kAllowConst);
|
| return new StaticCallNode(supercall_pos, super_function, arguments);
|
| }
|
|
|
| @@ -1212,7 +1214,7 @@
|
| }
|
|
|
|
|
| -void Parser::GenerateSuperInitializerCall(const Class& cls,
|
| +void Parser::GenerateSuperConstructorCall(const Class& cls,
|
| LocalVariable* receiver) {
|
| const intptr_t supercall_pos = token_index_;
|
| const Class& super_class = Class::Handle(cls.SuperClass());
|
| @@ -1226,9 +1228,14 @@
|
| String& ctor_suffix = String::Handle(String::NewSymbol("."));
|
| ctor_name = String::Concat(ctor_name, ctor_suffix);
|
| ArgumentListNode* arguments = new ArgumentListNode(supercall_pos);
|
| - // implicit 'this' parameter is the only argument.
|
| + // Implicit 'this' parameter is the first argument.
|
| AstNode* implicit_argument = new LoadLocalNode(supercall_pos, *receiver);
|
| arguments->Add(implicit_argument);
|
| + // Implicit constructor phase parameter is second argument.
|
| + AstNode* phase_parameter =
|
| + new LiteralNode(supercall_pos,
|
| + Smi::ZoneHandle(Smi::New(Function::kCtorPhaseAll)));
|
| + arguments->Add(phase_parameter);
|
| const Function& super_ctor = Function::ZoneHandle(
|
| super_class.LookupConstructor(ctor_name));
|
| if (super_ctor.IsNull() ||
|
| @@ -1263,13 +1270,24 @@
|
| if (CurrentToken() != Token::kLPAREN) {
|
| ErrorMsg("parameter list expected");
|
| }
|
| +
|
| + ArgumentListNode* arguments = new ArgumentListNode(supercall_pos);
|
| // 'this' parameter is the first argument to super class constructor.
|
| AstNode* implicit_argument = new LoadLocalNode(supercall_pos, *receiver);
|
| + arguments->Add(implicit_argument);
|
| + // Second implicit parameter is the constructor phase. We optimistically
|
| + // assume that we can execute both the super initializer and the super
|
| + // constructor body. We may later change this to only execute the
|
| + // super initializer.
|
| + AstNode* phase_parameter =
|
| + new LiteralNode(supercall_pos,
|
| + Smi::ZoneHandle(Smi::New(Function::kCtorPhaseAll)));
|
| + arguments->Add(phase_parameter);
|
| // 'this' parameter must not be accessible to the other super call arguments.
|
| receiver->set_invisible(true);
|
| - ArgumentListNode* arguments =
|
| - ParseActualParameters(implicit_argument, kAllowConst);
|
| + ParseActualParameters(arguments, kAllowConst);
|
| receiver->set_invisible(false);
|
| +
|
| // Resolve the constructor.
|
| const Function& super_ctor = Function::ZoneHandle(
|
| super_class.LookupConstructor(ctor_name));
|
| @@ -1373,10 +1391,9 @@
|
| }
|
|
|
|
|
| -void Parser::ParseInitializers(const Class& cls) {
|
| +void Parser::ParseInitializers(const Class& cls, LocalVariable* receiver) {
|
| TRACE_PARSER("ParseInitializers");
|
| - LocalVariable* receiver = current_block_->scope->VariableAt(0);
|
| - AstNode* super_init_statement = NULL;
|
| + bool super_init_seen = false;
|
| if (CurrentToken() == Token::kCOLON) {
|
| if ((LookaheadToken(1) == Token::kTHIS) &&
|
| ((LookaheadToken(2) == Token::kLPAREN) ||
|
| @@ -1390,33 +1407,26 @@
|
| ParseConstructorRedirection(cls, receiver);
|
| return;
|
| }
|
| -
|
| do {
|
| ConsumeToken(); // Colon or comma.
|
| + AstNode* init_statement;
|
| if (CurrentToken() == Token::kSUPER) {
|
| - if (super_init_statement != NULL) {
|
| + if (super_init_seen) {
|
| ErrorMsg("Duplicate call to super constructor");
|
| }
|
| - super_init_statement = ParseSuperInitializer(cls, receiver);
|
| + init_statement = ParseSuperInitializer(cls, receiver);
|
| + super_init_seen = true;
|
| } else {
|
| - AstNode* init_statement = ParseInitializer(cls, receiver);
|
| - current_block_->statements->Add(init_statement);
|
| + init_statement = ParseInitializer(cls, receiver);
|
| }
|
| + current_block_->statements->Add(init_statement);
|
| } while (CurrentToken() == Token::kCOMMA);
|
| }
|
| -
|
| - if (super_init_statement != NULL) {
|
| - // Move explicit supercall to the end of the initializer list to
|
| - // avoid executing constructor code on partially initialized objects.
|
| - // TODO(hausner): Fix issue 4995181, evaluation order of constructor
|
| - // initializer lists.
|
| - current_block_->statements->Add(super_init_statement);
|
| - } else {
|
| + if (!super_init_seen) {
|
| // Generate implicit super() if we haven't seen an explicit super call
|
| // or constructor redirection.
|
| - GenerateSuperInitializerCall(cls, receiver);
|
| + GenerateSuperConstructorCall(cls, receiver);
|
| }
|
| -
|
| CheckConstFieldsInitialized(cls);
|
| }
|
|
|
| @@ -1438,10 +1448,17 @@
|
| if (CurrentToken() != Token::kLPAREN) {
|
| ErrorMsg("parameter list expected");
|
| }
|
| - // 'this' parameter is the first argument to super class constructor.
|
| +
|
| + ArgumentListNode* arguments = new ArgumentListNode(call_pos);
|
| + // 'this' parameter is the first argument to constructor.
|
| AstNode* implicit_argument = new LoadLocalNode(call_pos, *receiver);
|
| - ArgumentListNode* arguments =
|
| - ParseActualParameters(implicit_argument, kAllowConst);
|
| + arguments->Add(implicit_argument);
|
| + // Constructor phase parameter is second argument.
|
| + LocalVariable* phase_param = LookupPhaseParameter();
|
| + ASSERT(phase_param != NULL);
|
| + AstNode* phase_argument = new LoadLocalNode(call_pos, *phase_param);
|
| + arguments->Add(phase_argument);
|
| + ParseActualParameters(arguments, kAllowConst);
|
|
|
| // Resolve the constructor.
|
| const Function& redirect_ctor = Function::ZoneHandle(
|
| @@ -1465,7 +1482,6 @@
|
| // Implicit 'this' is the only parameter/local variable.
|
| OpenFunctionBlock(func);
|
|
|
| -
|
| // Parse expressions of instance fields that have an explicit
|
| // initializers.
|
| GrowableArray<FieldInitExpression> initializers;
|
| @@ -1478,6 +1494,12 @@
|
| Type::ZoneHandle(Type::DynamicType()));
|
| current_block_->scope->AddVariable(receiver);
|
|
|
| + LocalVariable* phase_parameter = new LocalVariable(
|
| + ctor_pos,
|
| + String::ZoneHandle(String::NewSymbol(kPhaseParameterName)),
|
| + Type::ZoneHandle(Type::DynamicType()));
|
| + current_block_->scope->AddVariable(phase_parameter);
|
| +
|
| // Now that the "this" parameter is in scope, we can generate the code
|
| // to strore the initializer expressions in the respective instance fields.
|
| for (int i = 0; i < initializers.length(); i++) {
|
| @@ -1491,7 +1513,7 @@
|
| current_block_->statements->Add(field_init);
|
| }
|
|
|
| - GenerateSuperInitializerCall(cls, receiver);
|
| + GenerateSuperConstructorCall(cls, receiver);
|
| CheckConstFieldsInitialized(cls);
|
|
|
| // Empty constructor body.
|
| @@ -1531,6 +1553,11 @@
|
| if (has_receiver) {
|
| params.AddReceiver(token_index_);
|
| }
|
| + if (func.IsConstructor()) {
|
| + // Add implicit parameter for constructor phase.
|
| + params.AddFinalParameter(token_index_, kPhaseParameterName,
|
| + &Type::ZoneHandle(Type::DynamicType()));
|
| + }
|
| if (are_implicitly_final) {
|
| params.SetImplicitlyFinal();
|
| }
|
| @@ -1551,70 +1578,95 @@
|
| // NB: the instance field initializers have to be compiled before
|
| // the parameters are added to the scope, so that a parameter
|
| // name cannot shadow a name used in the field initializer expression.
|
| -
|
| - GrowableArray<FieldInitExpression> initializers;
|
| + SequenceNode* init_statements = NULL;
|
| if (func.IsConstructor()) {
|
| + GrowableArray<FieldInitExpression> initializers;
|
| ParseInitializedInstanceFields(cls, &initializers);
|
| - }
|
|
|
| - // Now populate function scope with the formal parameters.
|
| - AddFormalParamsToScope(¶ms, current_block_->scope);
|
| + // Now populate function scope with the formal parameters.
|
| + AddFormalParamsToScope(¶ms, current_block_->scope);
|
| + LocalVariable* receiver = current_block_->scope->VariableAt(0);
|
|
|
| - // Now that the "this" parameter is in scope, we can generate the code
|
| - // to strore the initializer expressions in the respective instance fields.
|
| - // We do this before the field parameters and the initializers from the
|
| - // constuctor's initializer list get compiled.
|
| - if (initializers.length() > 0) {
|
| - LocalVariable* receiver = current_block_->scope->VariableAt(0);
|
| - for (int i = 0; i < initializers.length(); i++) {
|
| - const Field* field = initializers[i].inst_field;
|
| - AstNode* instance = new LoadLocalNode(field->token_index(), *receiver);
|
| - AstNode* field_init =
|
| - new StoreInstanceFieldNode(field->token_index(),
|
| - instance,
|
| - *field,
|
| - initializers[i].expr);
|
| - current_block_->statements->Add(field_init);
|
| + // Now that the "this" parameter is in scope, we can generate the code
|
| + // to strore the initializer expressions in the respective instance fields.
|
| + // We do this before the field parameters and the initializers from the
|
| + // constructor's initializer list get compiled.
|
| + OpenBlock();
|
| + if (initializers.length() > 0) {
|
| + for (int i = 0; i < initializers.length(); i++) {
|
| + const Field* field = initializers[i].inst_field;
|
| + AstNode* instance = new LoadLocalNode(field->token_index(), *receiver);
|
| + AstNode* field_init =
|
| + new StoreInstanceFieldNode(field->token_index(),
|
| + instance,
|
| + *field,
|
| + initializers[i].expr);
|
| + current_block_->statements->Add(field_init);
|
| + }
|
| }
|
| - }
|
|
|
| - // Turn formal field parameters into field initializers or report error
|
| - // if the function is not a constructor
|
| - if (params.has_field_initializer) {
|
| - LocalVariable* receiver = current_block_->scope->VariableAt(0);
|
| - for (int i = 0; i < params.parameters->length(); i++) {
|
| - ParamDesc& param = (*params.parameters)[i];
|
| - if (param.is_field_initializer) {
|
| - if (!func.IsConstructor()) {
|
| + // Turn formal field parameters into field initializers or report error
|
| + // if the function is not a constructor
|
| + if (params.has_field_initializer) {
|
| + for (int i = 0; i < params.parameters->length(); i++) {
|
| + ParamDesc& param = (*params.parameters)[i];
|
| + if (param.is_field_initializer) {
|
| + if (!func.IsConstructor()) {
|
| + ErrorMsg(param.name_pos,
|
| + "field initializer only allowed in constructors");
|
| + }
|
| +
|
| + const String& field_name = *param.name;
|
| + Field& field = Field::ZoneHandle(cls.LookupInstanceField(field_name));
|
| + if (field.IsNull()) {
|
| + ErrorMsg(param.name_pos,
|
| + "unresolved reference to instance field '%s'",
|
| + field_name.ToCString());
|
| + }
|
| + const String& mangled_name =
|
| + String::ZoneHandle(MangledInitParamName(field_name));
|
| + AstNode* instance = new LoadLocalNode(param.name_pos, *receiver);
|
| + LocalVariable* p =
|
| + current_block_->scope->LookupVariable(mangled_name, false);
|
| + ASSERT(p != NULL);
|
| + AstNode* value = new LoadLocalNode(param.name_pos, *p);
|
| + AstNode* initializer = new StoreInstanceFieldNode(
|
| + param.name_pos, instance, field, value);
|
| + current_block_->statements->Add(initializer);
|
| + }
|
| + }
|
| + }
|
| + ParseInitializers(cls, receiver);
|
| + init_statements = CloseBlock();
|
| + LocalVariable* phase_param = LookupPhaseParameter();
|
| + AstNode* phase_value = new LoadLocalNode(token_index_, *phase_param);
|
| + AstNode* phase_check =
|
| + new BinaryOpNode(token_index_, Token::kBIT_AND,
|
| + phase_value,
|
| + new LiteralNode(token_index_,
|
| + Smi::ZoneHandle(Smi::New(Function::kCtorPhaseInit))));
|
| + AstNode* comparison =
|
| + new ComparisonNode(token_index_, Token::kNE_STRICT,
|
| + phase_check,
|
| + new LiteralNode(token_index_, Smi::ZoneHandle(Smi::New(0))));
|
| + AstNode* guarded_init_statements =
|
| + new IfNode(token_index_, comparison, init_statements, NULL);
|
| + current_block_->statements->Add(guarded_init_statements);
|
| + } else {
|
| + // Parsing a function that is not a constructor.
|
| + if (params.has_field_initializer) {
|
| + for (int i = 0; i < params.parameters->length(); i++) {
|
| + ParamDesc& param = (*params.parameters)[i];
|
| + if (param.is_field_initializer) {
|
| ErrorMsg(param.name_pos,
|
| "field initializer only allowed in constructors");
|
| }
|
| -
|
| - const String& field_name = *param.name;
|
| - Field& field = Field::ZoneHandle(cls.LookupInstanceField(field_name));
|
| - if (field.IsNull()) {
|
| - ErrorMsg(param.name_pos,
|
| - "unresolved reference to instance field '%s'",
|
| - field_name.ToCString());
|
| - }
|
| - const String& mangled_name =
|
| - String::ZoneHandle(MangledInitParamName(field_name));
|
| - AstNode* instance = new LoadLocalNode(param.name_pos, *receiver);
|
| - LocalVariable* p =
|
| - current_block_->scope->LocalLookupVariable(mangled_name);
|
| - ASSERT(p != NULL);
|
| - AstNode* value = new LoadLocalNode(param.name_pos, *p);
|
| - AstNode* initializer =
|
| - new StoreInstanceFieldNode(param.name_pos, instance, field, value);
|
| - current_block_->statements->Add(initializer);
|
| }
|
| }
|
| + // Populate function scope with the formal parameters.
|
| + AddFormalParamsToScope(¶ms, current_block_->scope);
|
| }
|
|
|
| - if (func.IsConstructor()) {
|
| - ParseInitializers(cls);
|
| - }
|
| -
|
| if (FLAG_enable_type_checks &&
|
| (current_block_->scope->function_level() > 0)) {
|
| // We are parsing, but not compiling, a local function.
|
| @@ -1630,6 +1682,87 @@
|
| }
|
| }
|
|
|
| + if (func.IsConstructor()) {
|
| + LocalVariable* receiver = current_block_->scope->VariableAt(0);
|
| + StaticCallNode* super_call = NULL;
|
| + ASSERT(init_statements != NULL);
|
| + // Look for the super initializer call in the sequence of initializer
|
| + // statements. If it exists and is not the last initializer statement,
|
| + // we need to create an implicit super call to the super constructor's
|
| + // body.
|
| + // Thus, iterate over all but the last initializer to see whether
|
| + // it's a super constructor call.
|
| + for (int i = 0; i < init_statements->length() - 1; i++) {
|
| + if (init_statements->NodeAt(i)->IsStaticCallNode()) {
|
| + StaticCallNode* static_call =
|
| + init_statements->NodeAt(i)->AsStaticCallNode();
|
| + if (static_call->function().IsConstructor()) {
|
| + super_call = static_call;
|
| + break;
|
| + }
|
| + }
|
| + }
|
| + if (super_call != NULL) {
|
| + // Generate an implicit call to the super constructor's body.
|
| + // We need to patch the super _initializer_ call so that it
|
| + // saves the evaluated actual arguments in temporary variables.
|
| + // The temporary variables are necessary so that the argument
|
| + // expressions are not evaluated twice.
|
| + ArgumentListNode* ctor_args = super_call->arguments();
|
| + // The super initializer call has at least 2 arguments: the
|
| + // implicit receiver, and the hidden constructor phase.
|
| + ASSERT(ctor_args->length() >= 2);
|
| + for (int i = 2; i < ctor_args->length(); i++) {
|
| + AstNode* arg = ctor_args->NodeAt(i);
|
| + if (!arg->IsLoadLocalNode() && !arg->IsLiteralNode()) {
|
| + LocalVariable* temp =
|
| + CreateTempConstVariable(arg->token_index(), arg->id(), "sca");
|
| + AstNode* save_temp =
|
| + new StoreLocalNode(arg->token_index(), *temp, arg);
|
| + ctor_args->SetNodeAt(i, save_temp);
|
| + }
|
| + }
|
| + }
|
| + OpenBlock();
|
| + if (super_call != NULL) {
|
| + ArgumentListNode* initializer_args = super_call->arguments();
|
| + const Function& super_ctor = super_call->function();
|
| + // Patch the initializer call so it only executes the super
|
| + // initializer.
|
| + initializer_args->SetNodeAt(1,
|
| + new LiteralNode(token_index_,
|
| + Smi::ZoneHandle(Smi::New(Function::kCtorPhaseInit))));
|
| +
|
| + ArgumentListNode* super_call_args = new ArgumentListNode(token_index_);
|
| + // First argument is the receiver.
|
| + super_call_args->Add(new LoadLocalNode(token_index_, *receiver));
|
| + // Second argument is the constructor phase argument.
|
| + AstNode* phase_parameter =
|
| + new LiteralNode(token_index_,
|
| + Smi::ZoneHandle(Smi::New(Function::kCtorPhaseBody)));
|
| + super_call_args->Add(phase_parameter);
|
| + for (int i = 2; i < initializer_args->length(); i++) {
|
| + AstNode* arg = initializer_args->NodeAt(i);
|
| + if (arg->IsLiteralNode()) {
|
| + LiteralNode* lit = arg->AsLiteralNode();
|
| + super_call_args->Add(new LiteralNode(token_index_, lit->literal()));
|
| + } else {
|
| + ASSERT(arg->IsLoadLocalNode() || arg->IsStoreLocalNode());
|
| + if (arg->IsLoadLocalNode()) {
|
| + const LocalVariable& temp = arg->AsLoadLocalNode()->local();
|
| + super_call_args->Add(new LoadLocalNode(token_index_, temp));
|
| + } else if (arg->IsStoreLocalNode()) {
|
| + const LocalVariable& temp = arg->AsStoreLocalNode()->local();
|
| + super_call_args->Add(new LoadLocalNode(token_index_, temp));
|
| + }
|
| + }
|
| + }
|
| + ASSERT(super_ctor.AreValidArguments(super_call_args->length(),
|
| + super_call_args->names()));
|
| + current_block_->statements->Add(
|
| + new StaticCallNode(token_index_, super_ctor, super_call_args));
|
| + }
|
| + }
|
| if (CurrentToken() == Token::kLBRACE) {
|
| ConsumeToken();
|
| ParseStatementSequence();
|
| @@ -1649,6 +1782,23 @@
|
| } else {
|
| UnexpectedToken();
|
| }
|
| + if (func.IsConstructor()) {
|
| + SequenceNode* ctor_block = CloseBlock();
|
| + LocalVariable* phase_param = LookupPhaseParameter();
|
| + AstNode* phase_value = new LoadLocalNode(token_index_, *phase_param);
|
| + AstNode* phase_check =
|
| + new BinaryOpNode(token_index_, Token::kBIT_AND,
|
| + phase_value,
|
| + new LiteralNode(token_index_,
|
| + Smi::ZoneHandle(Smi::New(Function::kCtorPhaseBody))));
|
| + AstNode* comparison =
|
| + new ComparisonNode(token_index_, Token::kNE_STRICT,
|
| + phase_check,
|
| + new LiteralNode(token_index_, Smi::ZoneHandle(Smi::New(0))));
|
| + AstNode* guarded_block_statements =
|
| + new IfNode(token_index_, comparison, ctor_block, NULL);
|
| + current_block_->statements->Add(guarded_block_statements);
|
| + }
|
|
|
| SequenceNode* statements = CloseBlock();
|
| return statements;
|
| @@ -1796,6 +1946,11 @@
|
| if (has_this_param) {
|
| method->params.AddReceiver(formal_param_pos);
|
| }
|
| + // Constructors have an implicit parameter for the constructor phase.
|
| + if (method->IsConstructor()) {
|
| + method->params.AddFinalParameter(token_index_, kPhaseParameterName,
|
| + &Type::ZoneHandle(Type::DynamicType()));
|
| + }
|
| if (are_implicitly_final) {
|
| method->params.SetImplicitlyFinal();
|
| }
|
| @@ -2307,8 +2462,8 @@
|
| void Parser::CheckConstructors(ClassDesc* class_desc) {
|
| // Add an implicit constructor if no explicit constructor is present.
|
| if (!class_desc->has_constructor()) {
|
| - // The implicit constructor is unnamed, has no parameter, and contains
|
| - // a supercall in the initializer list.
|
| + // The implicit constructor is unnamed, has no explicit parameter,
|
| + // and contains a supercall in the initializer list.
|
| String& ctor_name = String::ZoneHandle(
|
| String::Concat(class_desc->class_name(),
|
| String::Handle(String::NewSymbol("."))));
|
| @@ -2320,7 +2475,12 @@
|
| /* is_const = */ false,
|
| class_desc->token_pos()));
|
| ParamList params;
|
| + // Add implicit 'this' parameter.
|
| params.AddReceiver(token_index_);
|
| + // Add implicit parameter for constructor phase.
|
| + params.AddFinalParameter(token_index_, kPhaseParameterName,
|
| + &Type::ZoneHandle(Type::DynamicType()));
|
| +
|
| AddFormalParamsToFunction(¶ms, ctor);
|
| // TODO(regis): What are the type arguments?
|
| Type& result_type = Type::ZoneHandle(
|
| @@ -3200,6 +3360,14 @@
|
| }
|
|
|
|
|
| +LocalVariable* Parser::LookupPhaseParameter() {
|
| + const String& phase_name =
|
| + String::Handle(String::NewSymbol(kPhaseParameterName));
|
| + const bool kTestOnly = false;
|
| + return current_block_->scope->LookupVariable(phase_name, kTestOnly);
|
| +}
|
| +
|
| +
|
| void Parser::CaptureReceiver() {
|
| ASSERT(current_block_->scope->function_level() > 0);
|
| const bool kTestOnly = false;
|
| @@ -5200,14 +5368,17 @@
|
| }
|
|
|
|
|
| -ArgumentListNode* Parser::ParseActualParameters(AstNode* implicit_argument,
|
| - bool require_const) {
|
| +ArgumentListNode* Parser::ParseActualParameters(
|
| + ArgumentListNode* implicit_arguments,
|
| + bool require_const) {
|
| TRACE_PARSER("ParseActualParameters");
|
| ASSERT(CurrentToken() == Token::kLPAREN);
|
| const bool saved_mode = SetAllowFunctionLiterals(true);
|
| - ArgumentListNode* arguments = new ArgumentListNode(token_index_);
|
| - if (implicit_argument != NULL) {
|
| - arguments->Add(implicit_argument);
|
| + ArgumentListNode* arguments;
|
| + if (implicit_arguments == NULL) {
|
| + arguments = new ArgumentListNode(token_index_);
|
| + } else {
|
| + arguments = implicit_arguments;
|
| }
|
| GrowableArray<const String*> names;
|
| bool named_argument_seen = false;
|
| @@ -5807,7 +5978,8 @@
|
| const TypeArguments& type_arguments,
|
| const Function& constructor,
|
| ArgumentListNode* arguments) {
|
| - GrowableArray<const Object*> arg_values(arguments->length() + 1);
|
| + // +2 for implicit receiver and constructor phase arguments.
|
| + GrowableArray<const Object*> arg_values(arguments->length() + 2);
|
| Instance& instance = Instance::Handle();
|
| if (!constructor.IsFactory()) {
|
| instance = Instance::New(type_class);
|
| @@ -5819,6 +5991,7 @@
|
| instance.SetTypeArguments(type_arguments);
|
| }
|
| arg_values.Add(&instance);
|
| + arg_values.Add(&Smi::ZoneHandle(Smi::New(Function::kCtorPhaseAll)));
|
| } else {
|
| // Prepend type_arguments to list of arguments to factory.
|
| ASSERT(type_arguments.IsZoneHandle());
|
| @@ -6483,7 +6656,8 @@
|
|
|
| // A constructor has an implicit 'this' parameter (instance to construct)
|
| // and a factory has an implicit 'this' parameter (type_arguments).
|
| - intptr_t arguments_length = arguments->length() + 1;
|
| + // A constructor has a second implicit 'phase' parameter.
|
| + intptr_t arguments_length = arguments->length() + 2;
|
|
|
| if (type_class.is_interface()) {
|
| // We need to make sure that an appropriate constructor is
|
| @@ -6548,6 +6722,8 @@
|
| type_class.LookupConstructor(constructor_name));
|
| if (constructor.IsNull()) {
|
| constructor = type_class.LookupFactory(constructor_name);
|
| + // A factory does not have the implicit 'phase' parameter.
|
| + arguments_length -= 1;
|
| }
|
| if (constructor.IsNull()) {
|
| ErrorMsg(new_pos, "class '%s' has no constructor or factory named '%s'",
|
|
|