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

Unified Diff: runtime/vm/parser.cc

Issue 10916039: Throw AbstractClassInstantiationError if an abstract class is instantiated (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 4 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/object.cc ('k') | runtime/vm/symbols.h » ('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 11699)
+++ runtime/vm/parser.cc (working copy)
@@ -525,6 +525,7 @@
: clazz_(cls),
class_name_(cls_name),
is_interface_(is_interface),
+ is_abstract_(false),
token_pos_(token_pos),
functions_(GrowableObjectArray::Handle(GrowableObjectArray::New())),
fields_(GrowableObjectArray::Handle(GrowableObjectArray::New())) {
@@ -600,6 +601,14 @@
return is_interface_;
}
+ void set_is_abstract() {
+ is_abstract_ = true;
+ }
+
+ bool is_abstract() const {
+ return is_abstract_;
+ }
+
bool has_constructor() const {
Function& func = Function::Handle();
for (int i = 0; i < functions_.Length(); i++) {
@@ -650,6 +659,7 @@
const Class& clazz_;
const String& class_name_;
const bool is_interface_;
+ bool is_abstract_;
intptr_t token_pos_; // Token index of "class" keyword.
GrowableObjectArray& functions_;
GrowableObjectArray& fields_;
@@ -2501,29 +2511,42 @@
"Constructor with redirection may not have a function body");
}
ParseNativeDeclaration();
- } else if (CurrentToken() == Token::kSEMICOLON) {
- if (members->is_interface() ||
- method->has_abstract ||
- method->has_external ||
- (method->redirect_name != NULL) ||
- method->IsConstructor()) {
- ConsumeToken();
- } else {
+ } else {
+ // 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;
+ if (must_have_body) {
ErrorMsg(method->name_pos,
"function body expected for method '%s'",
method->name->ToCString());
}
- } else {
- if (members->is_interface() ||
- method->has_abstract ||
- method->has_external ||
- (method->redirect_name != NULL) ||
- (method->IsConstructor() && method->has_const)) {
- ExpectSemicolon();
+
+ if (CurrentToken() == Token::kSEMICOLON) {
+ ConsumeToken();
+ if (!members->is_interface() &&
+ !method->has_static &&
+ !method->has_external &&
+ !method->IsConstructor()) {
+ // Methods, getters and setters without a body are
+ // implicitly abstract.
+ method->has_abstract = true;
+ }
} else {
- ErrorMsg(method->name_pos,
- "function body expected for method '%s'",
- method->name->ToCString());
+ // Signature is not followed by semicolon or body. Issue an
+ // appropriate error.
+ const bool must_have_semicolon =
+ members->is_interface() ||
+ (method->redirect_name != NULL) ||
+ (method->IsConstructor() && method->has_const) ||
+ method->has_external;
+ if (must_have_semicolon) {
+ ExpectSemicolon();
+ } else {
+ ErrorMsg(method->name_pos,
+ "function body or semicolon expected for method '%s'",
+ method->name->ToCString());
+ }
}
}
@@ -2553,6 +2576,9 @@
ASSERT(is_top_level_);
AddFormalParamsToFunction(&method->params, func);
members->AddFunction(func);
+ if (method->has_abstract) {
+ members->set_is_abstract();
+ }
}
@@ -2956,14 +2982,18 @@
void Parser::ParseClassDefinition(const GrowableObjectArray& pending_classes) {
TRACE_PARSER("ParseClassDefinition");
- const intptr_t class_pos = TokenPos();
bool is_patch = false;
+ bool is_abstract = false;
if (is_patch_source() &&
(CurrentToken() == Token::kIDENT) &&
CurrentLiteral()->Equals("patch")) {
ConsumeToken();
is_patch = true;
+ } else if (CurrentToken() == Token::kABSTRACT) {
+ is_abstract = true;
+ ConsumeToken();
}
+ const intptr_t class_pos = TokenPos();
ExpectToken(Token::kCLASS);
const intptr_t classname_pos = TokenPos();
String& class_name = *ExpectClassIdentifier("class name expected");
@@ -3051,6 +3081,10 @@
}
ExpectToken(Token::kRBRACE);
+ if (is_abstract || members.is_abstract()) {
+ cls.set_is_abstract();
+ }
+
// Add an implicit constructor if no explicit constructor is present. No
// implicit constructors are needed for patch classes.
if (!members.has_constructor() && !is_patch) {
@@ -4101,7 +4135,6 @@
ParseInterfaceDefinition(pending_classes);
} else if ((CurrentToken() == Token::kABSTRACT) &&
(LookaheadToken(1) == Token::kCLASS)) {
- ConsumeToken(); // Consume and ignore 'abstract'.
ParseClassDefinition(pending_classes);
} else if (is_patch_source() && IsLiteral("patch") &&
(LookaheadToken(1) == Token::kCLASS)) {
@@ -8545,8 +8578,8 @@
if (type.IsDynamicType()) {
ErrorMsg(type_pos, "Dynamic cannot be instantiated");
}
- Class& type_class = Class::Handle(type.type_class());
- String& type_class_name = String::Handle(type_class.Name());
+ const 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());
@@ -8651,6 +8684,21 @@
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()) {
+ ArgumentListNode* arguments = new ArgumentListNode(type_pos);
+ arguments->Add(new LiteralNode(
+ TokenPos(), Integer::ZoneHandle(Integer::New(type_pos))));
+ arguments->Add(new LiteralNode(
+ TokenPos(), String::ZoneHandle(constructor_class_name.raw())));
+ const String& cls_name =
+ String::Handle(Symbols::AbstractClassInstantiationError());
+ const String& func_name = String::Handle(Symbols::ThrowNew());
+ return MakeStaticCall(cls_name, func_name, arguments);
+ }
+
String& error_message = String::Handle();
if (!constructor.AreValidArguments(arguments_length,
arguments->names(),
« no previous file with comments | « runtime/vm/object.cc ('k') | runtime/vm/symbols.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698