Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(537)

Unified Diff: runtime/vm/parser.cc

Issue 8286003: Create implicit super constructor call if necessary (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: '' Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/parser.h ('k') | tests/co19/co19-runtime.status » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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(),
« no previous file with comments | « runtime/vm/parser.h ('k') | tests/co19/co19-runtime.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698