| Index: runtime/vm/parser.cc
|
| ===================================================================
|
| --- runtime/vm/parser.cc (revision 411)
|
| +++ runtime/vm/parser.cc (working copy)
|
| @@ -1199,6 +1199,38 @@
|
| }
|
|
|
|
|
| +void Parser::GenerateSuperInitializerCall(const Class& cls,
|
| + LocalVariable* receiver) {
|
| + const intptr_t supercall_pos = token_index_;
|
| + const Class& super_class = Class::Handle(cls.SuperClass());
|
| + // Omit the implicit super() if there is no super class (i.e.
|
| + // we're not compiling class Object), or if the super class is an
|
| + // artificially generated "wrapper class" that has no constructor.
|
| + if (super_class.IsNull() || (super_class.num_native_fields() > 0)) {
|
| + return;
|
| + }
|
| + String& ctor_name = String::Handle(super_class.Name());
|
| + 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.
|
| + AstNode* implicit_argument = new LoadLocalNode(supercall_pos, *receiver);
|
| + arguments->Add(implicit_argument);
|
| + const Function& super_ctor = Function::ZoneHandle(
|
| + super_class.LookupConstructor(ctor_name));
|
| + if (super_ctor.IsNull() ||
|
| + !super_ctor.AreValidArguments(arguments->length(),
|
| + arguments->names())) {
|
| + ErrorMsg(supercall_pos,
|
| + "unresolved implicit call to super constructor '%s()'",
|
| + String::Handle(super_class.Name()).ToCString());
|
| + }
|
| + CheckFunctionIsCallable(supercall_pos, super_ctor);
|
| + current_block_->statements->Add(
|
| + new StaticCallNode(supercall_pos, super_ctor, arguments));
|
| +}
|
| +
|
| +
|
| AstNode* Parser::ParseSuperInitializer(const Class& cls,
|
| LocalVariable* receiver) {
|
| TRACE_PARSER("ParseSuperInitializer");
|
| @@ -1328,27 +1360,50 @@
|
| }
|
|
|
|
|
| -void Parser::ParseInitializers(const Class& cls, LocalVariable* receiver) {
|
| +void Parser::ParseInitializers(const Class& cls) {
|
| TRACE_PARSER("ParseInitializers");
|
| - AstNode* init_statement = NULL;
|
| - AstNode* super_init_statement = NULL;
|
| - // TODO(4995181): Allow super initializer to appear in any position
|
| - // of the initializer list.
|
| - if (CurrentToken() == Token::kSUPER) {
|
| - super_init_statement = ParseSuperInitializer(cls, receiver);
|
| - } else {
|
| - init_statement = ParseInitializer(cls, receiver);
|
| - current_block_->statements->Add(init_statement);
|
| + LocalVariable* receiver = current_block_->scope->VariableAt(0);
|
| + bool super_init_seen = false;
|
| + if (CurrentToken() == Token::kCOLON) {
|
| + if ((LookaheadToken(1) == Token::kTHIS) &&
|
| + ((LookaheadToken(2) == Token::kLPAREN) ||
|
| + ((LookaheadToken(2) == Token::kPERIOD) &&
|
| + (LookaheadToken(4) == Token::kLPAREN)))) {
|
| + // Either we see this(...) or this.xxx(...) which is a
|
| + // redirected constructor. We don't need to check whether
|
| + // const fields are initialized. The other constructor will
|
| + // guarantee that.
|
| + ConsumeToken(); // Colon.
|
| + ParseConstructorRedirection(cls, receiver);
|
| + return;
|
| + }
|
| +
|
| + do {
|
| + ConsumeToken(); // Colon or comma.
|
| + AstNode* init_statement = NULL;
|
| + if (CurrentToken() == Token::kSUPER) {
|
| + if (super_init_seen) {
|
| + ErrorMsg("Duplicate call to super constructor");
|
| + }
|
| + init_statement = ParseSuperInitializer(cls, receiver);
|
| + super_init_seen = true;
|
| + } else {
|
| + init_statement = ParseInitializer(cls, receiver);
|
| + }
|
| + current_block_->statements->Add(init_statement);
|
| + } while (CurrentToken() == Token::kCOMMA);
|
| }
|
| - while (CurrentToken() == Token::kCOMMA) {
|
| - ConsumeToken();
|
| - init_statement = ParseInitializer(cls, receiver);
|
| - current_block_->statements->Add(init_statement);
|
| +
|
| + // Generate implicit super() if we haven't seen an explicit super call
|
| + // or constructor redirection.
|
| + // Omit the implicit super() if there is no super class (i.e.
|
| + // we're not compiling class Object), or if the super class is an
|
| + // artificially generated "wrapper class" that has no constructor.
|
| + if (!super_init_seen) {
|
| + GenerateSuperInitializerCall(cls, receiver);
|
| }
|
| - // The call to super constructor is to be done after all initializers.
|
| - if (super_init_statement != NULL) {
|
| - current_block_->statements->Add(super_init_statement);
|
| - }
|
| +
|
| + CheckConstFieldsInitialized(cls);
|
| }
|
|
|
|
|
| @@ -1422,27 +1477,7 @@
|
| current_block_->statements->Add(field_init);
|
| }
|
|
|
| - // Super call to constructor of super class.
|
| - const Class& super_class = Class::Handle(cls.SuperClass());
|
| - ASSERT(!super_class.IsNull());
|
| - String& ctor_name = String::Handle(super_class.Name());
|
| - String& ctor_suffix = String::Handle(String::NewSymbol("."));
|
| - ctor_name = String::Concat(ctor_name, ctor_suffix);
|
| - ctor_name = String::NewSymbol(ctor_name);
|
| - ArgumentListNode* arguments = new ArgumentListNode(ctor_pos);
|
| - AstNode* implicit_argument = new LoadLocalNode(ctor_pos, *receiver);
|
| - arguments->Add(implicit_argument);
|
| - const Function& super_ctor = Function::ZoneHandle(
|
| - super_class.LookupConstructor(ctor_name));
|
| - if (super_ctor.IsNull() ||
|
| - !super_ctor.AreValidArgumentCounts(arguments->length(), 0)) {
|
| - ErrorMsg(ctor_pos,
|
| - "super class constructor '%s' not found",
|
| - ctor_name.ToCString());
|
| - }
|
| - current_block_->statements->Add(
|
| - new StaticCallNode(ctor_pos, super_ctor, arguments));
|
| -
|
| + GenerateSuperInitializerCall(cls, receiver);
|
| CheckConstFieldsInitialized(cls);
|
|
|
| // Empty constructor body.
|
| @@ -1461,6 +1496,9 @@
|
| return MakeImplicitConstructor(func);
|
| }
|
|
|
| + const Class& cls = Class::Handle(func.owner());
|
| + ASSERT(!cls.IsNull());
|
| +
|
| // Build local scope for function.
|
| OpenFunctionBlock(func);
|
|
|
| @@ -1502,7 +1540,6 @@
|
|
|
| GrowableArray<FieldInitExpression> initializers;
|
| if (func.IsConstructor()) {
|
| - Class& cls = Class::Handle(func.owner());
|
| ParseInitializedInstanceFields(cls, &initializers);
|
| }
|
|
|
| @@ -1531,7 +1568,6 @@
|
| // if the function is not a constructor
|
| if (params.has_field_initializer) {
|
| LocalVariable* receiver = current_block_->scope->VariableAt(0);
|
| - Class& cls = Class::ZoneHandle(func.owner());
|
| for (int i = 0; i < params.parameters->length(); i++) {
|
| ParamDesc& param = (*params.parameters)[i];
|
| if (param.is_field_initializer) {
|
| @@ -1562,29 +1598,7 @@
|
| }
|
|
|
| if (func.IsConstructor()) {
|
| - Class& cls = Class::ZoneHandle(func.owner());
|
| - bool initialized_check_needed = true;
|
| - if (CurrentToken() == Token::kCOLON) {
|
| - ConsumeToken();
|
| - LocalVariable* receiver = current_block_->scope->VariableAt(0);
|
| - ASSERT(receiver != NULL);
|
| - if ((CurrentToken() == Token::kTHIS) &&
|
| - ((LookaheadToken(1) == Token::kLPAREN) ||
|
| - ((LookaheadToken(1) == Token::kPERIOD) &&
|
| - (LookaheadToken(3) == Token::kLPAREN)))) {
|
| - // Either we see this(...) or this.xxx(...) which is a
|
| - // redirected constructor. We don't need to check whether
|
| - // const fields are initialized. The other constructor will
|
| - // guarantee that.
|
| - initialized_check_needed = false;
|
| - ParseConstructorRedirection(cls, receiver);
|
| - } else {
|
| - ParseInitializers(cls, receiver);
|
| - }
|
| - }
|
| - if (initialized_check_needed) {
|
| - CheckConstFieldsInitialized(cls);
|
| - }
|
| + ParseInitializers(cls);
|
| }
|
|
|
| if (current_block_->scope->function_level() > 0) {
|
| @@ -1652,35 +1666,29 @@
|
|
|
|
|
| void Parser::SkipInitializers() {
|
| - if (CurrentToken() == Token::kSUPER) {
|
| - ConsumeToken();
|
| - if (CurrentToken() == Token::kPERIOD) {
|
| + ASSERT(CurrentToken() == Token::kCOLON);
|
| + do {
|
| + ConsumeToken(); // Colon or comma.
|
| + if (CurrentToken() == Token::kSUPER) {
|
| ConsumeToken();
|
| + if (CurrentToken() == Token::kPERIOD) {
|
| + ConsumeToken();
|
| + ExpectIdentifier("identifier expected");
|
| + }
|
| + if (CurrentToken() != Token::kLPAREN) {
|
| + ErrorMsg("'(' expected");
|
| + }
|
| + SkipToMatchingParenthesis();
|
| + } else {
|
| + SkipIf(Token::kTHIS);
|
| + SkipIf(Token::kPERIOD);
|
| ExpectIdentifier("identifier expected");
|
| + ExpectToken(Token::kASSIGN);
|
| + SetAllowFunctionLiterals(false);
|
| + SkipExpr();
|
| + SetAllowFunctionLiterals(true);
|
| }
|
| - if (CurrentToken() != Token::kLPAREN) {
|
| - ErrorMsg("'(' expected");
|
| - }
|
| - SkipToMatchingParenthesis();
|
| - } else {
|
| - SkipIf(Token::kTHIS);
|
| - SkipIf(Token::kPERIOD);
|
| - ExpectIdentifier("identifier expected");
|
| - ExpectToken(Token::kASSIGN);
|
| - SetAllowFunctionLiterals(false);
|
| - SkipExpr();
|
| - SetAllowFunctionLiterals(true);
|
| - }
|
| - while (CurrentToken() == Token::kCOMMA) {
|
| - ConsumeToken();
|
| - SkipIf(Token::kTHIS);
|
| - SkipIf(Token::kPERIOD);
|
| - ExpectIdentifier("instance field expected");
|
| - ExpectToken(Token::kASSIGN);
|
| - SetAllowFunctionLiterals(false);
|
| - SkipExpr();
|
| - SetAllowFunctionLiterals(true);
|
| - }
|
| + } while (CurrentToken() == Token::kCOMMA);
|
| }
|
|
|
|
|
| @@ -1802,10 +1810,9 @@
|
| if (!method->IsConstructor()) {
|
| ErrorMsg("initializers only allowed on constructors");
|
| }
|
| - ConsumeToken();
|
| - if ((CurrentToken() == Token::kTHIS) &&
|
| - ((LookaheadToken(1) == Token::kLPAREN) ||
|
| - LookaheadToken(3) == Token::kLPAREN)) {
|
| + if ((LookaheadToken(1) == Token::kTHIS) &&
|
| + ((LookaheadToken(2) == Token::kLPAREN) ||
|
| + LookaheadToken(4) == Token::kLPAREN)) {
|
| // Redirected constructor: either this(...) or this.xxx(...).
|
| if (method->params.has_field_initializer) {
|
| // Constructors that redirect to another constructor must not
|
| @@ -1813,6 +1820,7 @@
|
| ErrorMsg(formal_param_pos, "Redirecting constructor "
|
| "may not use field initializer parameters");
|
| }
|
| + ConsumeToken(); // Colon.
|
| ExpectToken(Token::kTHIS);
|
| String& redir_name = String::ZoneHandle(
|
| String::Concat(members->class_name(),
|
|
|