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

Unified Diff: runtime/vm/parser.cc

Issue 12123002: Fix class patching involving type parameters: type parameters of patched classes (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 11 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_test.cc ('k') | runtime/vm/raw_object_snapshot.cc » ('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 17960)
+++ runtime/vm/parser.cc (working copy)
@@ -1180,7 +1180,8 @@
if (signature_class.IsNull()) {
signature_class = Class::NewSignatureClass(signature,
signature_function,
- script_);
+ script_,
+ parameter.name_pos);
// Record the function signature class in the current library.
library_.AddClass(signature_class);
} else {
@@ -2157,7 +2158,7 @@
const Function& super_ctor = super_call->function();
// Patch the initializer call so it only executes the super initializer.
initializer_args->SetNodeAt(1,
- new LiteralNode(TokenPos(),
+ new LiteralNode(TokenPos(),
Smi::ZoneHandle(Smi::New(Function::kCtorPhaseInit))));
ArgumentListNode* super_call_args = new ArgumentListNode(TokenPos());
@@ -3126,6 +3127,7 @@
OS::Print("TopLevel parsing class '%s'\n", class_name.ToCString());
}
Class& cls = Class::Handle();
+ TypeArguments& orig_type_parameters = TypeArguments::Handle();
Object& obj = Object::Handle(library_.LookupLocalObject(class_name));
if (obj.IsNull()) {
if (is_patch) {
@@ -3141,6 +3143,9 @@
}
cls ^= obj.raw();
if (is_patch) {
+ // Preserve and reuse the original type parameters and bounds since the
+ // ones defined in the patch class will not be finalized.
+ orig_type_parameters = cls.type_parameters();
String& patch = String::Handle(
String::Concat(Symbols::PatchSpace(), class_name));
patch = Symbols::New(patch);
@@ -3161,6 +3166,41 @@
ASSERT(cls.functions() == Object::empty_array().raw());
set_current_class(cls);
ParseTypeParameters(cls);
+ if (is_patch) {
+ // Check that the new type parameters are identical to the original ones.
+ const TypeArguments& new_type_parameters =
+ TypeArguments::Handle(cls.type_parameters());
+ const int new_type_params_count =
+ new_type_parameters.IsNull() ? 0 : new_type_parameters.Length();
+ const int orig_type_params_count =
+ orig_type_parameters.IsNull() ? 0 : orig_type_parameters.Length();
+ if (new_type_params_count != orig_type_params_count) {
+ ErrorMsg(classname_pos,
+ "class '%s' must be patched with identical type parameters",
+ class_name.ToCString());
+ }
+ TypeParameter& new_type_param = TypeParameter::Handle();
+ TypeParameter& orig_type_param = TypeParameter::Handle();
+ String& new_name = String::Handle();
+ String& orig_name = String::Handle();
+ for (int i = 0; i < new_type_params_count; i++) {
+ new_type_param ^= new_type_parameters.TypeAt(i);
+ orig_type_param ^= orig_type_parameters.TypeAt(i);
+ new_name = new_type_param.name();
+ orig_name = orig_type_param.name();
+ if (!new_name.Equals(orig_name)) {
+ ErrorMsg(new_type_param.token_pos(),
+ "type parameter '%s' of patch class '%s' does not match "
+ "original type parameter '%s'",
+ new_name.ToCString(),
+ class_name.ToCString(),
+ orig_name.ToCString());
+ }
+ // We do not check that the bounds are repeated. We use the original ones.
+ // TODO(regis): Should we check?
+ }
+ cls.set_type_parameters(orig_type_parameters);
+ }
Type& super_type = Type::Handle();
if (CurrentToken() == Token::kEXTENDS) {
ConsumeToken();
@@ -3218,8 +3258,10 @@
if (!is_patch) {
pending_classes.Add(cls, Heap::kOld);
} else {
- // Lookup the patched class and apply the changes.
- obj = library_.LookupLocalObject(class_name);
+ // Apply the changes to the patched class looked up above.
+ ASSERT(obj.raw() == library_.LookupLocalObject(class_name));
+ // The patched class must not be finalized yet.
+ ASSERT(!Class::Cast(obj).is_finalized());
const char* err_msg = Class::Cast(obj).ApplyPatch(cls);
if (err_msg != NULL) {
ErrorMsg(classname_pos, "applying patch failed with '%s'", err_msg);
@@ -3330,15 +3372,6 @@
TRACE_PARSER("ParseFunctionTypeAlias");
ExpectToken(Token::kTYPEDEF);
- // Allocate an abstract class to hold the type parameters and their bounds.
- // Make it the owner of the function type descriptor.
- const Class& alias_owner = Class::Handle(
- Class::New(Symbols::AliasOwner(), Script::Handle(), TokenPos()));
-
- alias_owner.set_is_abstract();
- alias_owner.set_library(library_);
- set_current_class(alias_owner);
-
// Parse the result type of the function type.
AbstractType& result_type = Type::Handle(Type::DynamicType());
if (CurrentToken() == Token::kVOID) {
@@ -3354,12 +3387,31 @@
const String* alias_name =
ExpectUserDefinedTypeIdentifier("function alias name expected");
+ // Lookup alias name and report an error if it is already defined in
+ // the library scope.
+ const Object& obj = Object::Handle(library_.LookupLocalObject(*alias_name));
+ if (!obj.IsNull()) {
+ ErrorMsg(alias_name_pos,
+ "'%s' is already defined", alias_name->ToCString());
+ }
+
+ // Create the function type alias signature class. It will be linked to its
+ // signature function after it has been parsed. The type parameters, in order
+ // to be properly finalized, need to be associated to this signature class as
+ // they are parsed.
+ const Class& function_type_alias = Class::Handle(
+ Class::NewSignatureClass(*alias_name,
+ Function::Handle(),
+ script_,
+ alias_name_pos));
+ library_.AddClass(function_type_alias);
+ set_current_class(function_type_alias);
// Parse the type parameters of the function type.
- ParseTypeParameters(alias_owner);
+ ParseTypeParameters(function_type_alias);
// At this point, the type parameters have been parsed, so we can resolve the
// result type.
if (!result_type.IsNull()) {
- ResolveTypeFromClass(alias_owner,
+ ResolveTypeFromClass(function_type_alias,
ClassFinalizer::kTryResolve,
&result_type);
}
@@ -3377,6 +3429,7 @@
const bool no_explicit_default_values = false;
ParseFormalParameterList(no_explicit_default_values, &func_params);
+ ExpectSemicolon();
// The field 'is_static' has no meaning for signature functions.
Function& signature_function = Function::Handle(
Function::New(*alias_name,
@@ -3385,10 +3438,14 @@
/* is_const = */ false,
/* is_abstract = */ false,
/* is_external = */ false,
- alias_owner,
+ function_type_alias,
alias_name_pos));
signature_function.set_result_type(result_type);
AddFormalParamsToFunction(&func_params, signature_function);
+
+ // Patch the signature function in the signature class.
+ function_type_alias.PatchSignatureFunction(signature_function);
+
const String& signature = String::Handle(signature_function.Signature());
if (FLAG_trace_parser) {
OS::Print("TopLevel parsing function type alias '%s'\n",
@@ -3402,35 +3459,21 @@
if (signature_class.IsNull()) {
signature_class = Class::NewSignatureClass(signature,
signature_function,
- script_);
+ script_,
+ alias_name_pos);
// Record the function signature class in the current library.
library_.AddClass(signature_class);
} else {
// Forget the just created signature function and use the existing one.
signature_function = signature_class.signature_function();
+ function_type_alias.PatchSignatureFunction(signature_function);
}
ASSERT(signature_function.signature_class() == signature_class.raw());
- // Lookup alias name and report an error if it is already defined in
- // the library scope.
- const Object& obj = Object::Handle(library_.LookupLocalObject(*alias_name));
- if (!obj.IsNull()) {
- ErrorMsg(alias_name_pos,
- "'%s' is already defined", alias_name->ToCString());
- }
-
- // Create the function type alias, but share the signature function of the
- // canonical signature class.
- Class& function_type_alias = Class::Handle(
- Class::NewSignatureClass(*alias_name,
- signature_function,
- script_));
- // This alias should not be marked as finalized yet, since it needs to be
+ // The alias should not be marked as finalized yet, since it needs to be
// checked in the class finalizer for illegal self references.
ASSERT(!function_type_alias.IsCanonicalSignatureClass());
ASSERT(!function_type_alias.is_finalized());
- library_.AddClass(function_type_alias);
- ExpectSemicolon();
pending_classes.Add(function_type_alias, Heap::kOld);
}
@@ -4368,6 +4411,7 @@
ParseClassDefinition(pending_classes);
} else if ((CurrentToken() == Token::kTYPEDEF) &&
(LookaheadToken(1) != Token::kLPAREN)) {
+ set_current_class(toplevel_class);
ParseFunctionTypeAlias(pending_classes);
} else if ((CurrentToken() == Token::kABSTRACT) &&
(LookaheadToken(1) == Token::kCLASS)) {
@@ -4859,7 +4903,8 @@
ASSERT(is_new_closure);
signature_class = Class::NewSignatureClass(signature,
function,
- script_);
+ script_,
+ function.token_pos());
// Record the function signature class in the current library.
library_.AddClass(signature_class);
} else if (is_new_closure) {
@@ -7820,7 +7865,7 @@
type_arguments = current_class().type_parameters();
}
Type& type = Type::ZoneHandle(
- Type::New(current_class(), type_arguments, type_pos));
+ Type::New(current_class(), type_arguments, type_pos));
if (!is_top_level_) {
type ^= ClassFinalizer::FinalizeType(
current_class(), type, ClassFinalizer::kCanonicalizeWellFormed);
« no previous file with comments | « runtime/vm/object_test.cc ('k') | runtime/vm/raw_object_snapshot.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698