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

Unified Diff: runtime/vm/parser.cc

Issue 9290065: Simplify parsing of 'new' operator. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 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
Index: runtime/vm/parser.cc
===================================================================
--- runtime/vm/parser.cc (revision 3627)
+++ runtime/vm/parser.cc (working copy)
@@ -1919,12 +1919,19 @@
LibraryPrefix& lib_prefix = LibraryPrefix::ZoneHandle();
lib_prefix = current_class().LookupLibraryPrefix(*(qual_ident->ident));
if (!lib_prefix.IsNull()) {
- // We have a library prefix qualified identifier.
- ConsumeToken(); // Consume the kPERIOD token.
- qual_ident->lib_prefix = &lib_prefix;
- qual_ident->qualifier = qual_ident->ident;
- qual_ident->ident_pos = token_index_;
- qual_ident->ident = ExpectIdentifier("identifier expected after '.'");
+ // We have a library prefix qualified identifier, unless the prefix is
+ // shadowed by a type parameter in scope.
hausner 2012/01/26 23:04:29 Are type parameters always "in scope" when we pars
regis 2012/01/26 23:45:17 Correct. When type parameters are not in scope, Ty
+ const Class& scope_class = Class::Handle(TypeParametersScopeClass());
+ if (scope_class.IsNull() ||
+ (scope_class.LookupTypeParameter(*(qual_ident->ident)) ==
+ TypeParameter::null())) {
+ ConsumeToken(); // Consume the kPERIOD token.
+ qual_ident->lib_prefix = &lib_prefix;
+ qual_ident->qualifier = qual_ident->ident;
+ qual_ident->ident_pos = token_index_;
+ qual_ident->ident =
+ ExpectIdentifier("identifier expected after '.'");
+ }
}
}
}
@@ -2333,6 +2340,7 @@
(CurrentLiteral()->Equals(members->class_name()) || member.has_factory)) {
member.name = CurrentLiteral();
member.name_pos = this->token_index_;
+ // TODO(regis): Simplify the following code by calling ParseQualIdent().
ConsumeToken();
if (member.has_factory) {
String& qualifier = String::Handle();
@@ -2668,7 +2676,10 @@
// At this point, the type parameters have been parsed, so we can resolve the
// result type.
if (!result_type.IsNull()) {
- TryResolveTypeFromClass(result_type_pos, alias_owner, &result_type);
+ ResolveTypeFromClass(result_type_pos,
+ alias_owner,
+ &result_type,
+ kCanResolve);
}
ParamList func_params;
const bool no_explicit_default_values = false;
@@ -2787,33 +2798,35 @@
ParseTypeParameters(factory_class);
unresolved_factory_class.set_factory_signature_class(factory_class);
interface.set_factory_class(unresolved_factory_class);
- // Verify that the type parameters of the factory class and of the interface
- // have identical names.
- String& interface_type_param_name = String::Handle();
- String& factory_type_param_name = String::Handle();
- const Array& interface_type_param_names =
- Array::Handle(interface.type_parameters());
- const Array& factory_type_param_names =
- Array::Handle(factory_class.type_parameters());
- const intptr_t num_type_params = factory_class.NumTypeParameters();
- bool mismatch = interface.NumTypeParameters() != num_type_params;
- for (intptr_t i = 0; !mismatch && (i < num_type_params); i++) {
- interface_type_param_name ^= interface_type_param_names.At(i);
- factory_type_param_name ^= factory_type_param_names.At(i);
- if (!interface_type_param_name.Equals(factory_type_param_name)) {
- mismatch = true;
+ // If a type parameter list is included in the default factory clause (it
+ // can be omitted), verify that it matches the list of type parameters of
+ // the interface in number and names.
+ const intptr_t num_default_type_params = factory_class.NumTypeParameters();
+ if (num_default_type_params > 0) {
+ String& interface_type_param_name = String::Handle();
+ String& factory_type_param_name = String::Handle();
+ const Array& interface_type_param_names =
+ Array::Handle(interface.type_parameters());
+ const Array& factory_type_param_names =
+ Array::Handle(factory_class.type_parameters());
+ bool mismatch = interface.NumTypeParameters() != num_default_type_params;
+ for (intptr_t i = 0; !mismatch && (i < num_default_type_params); i++) {
+ interface_type_param_name ^= interface_type_param_names.At(i);
+ factory_type_param_name ^= factory_type_param_names.At(i);
+ if (!interface_type_param_name.Equals(factory_type_param_name)) {
+ mismatch = true;
+ }
}
+ if (mismatch) {
+ const String& interface_name = String::Handle(interface.Name());
+ const String& factory_name = String::Handle(factory_class.Name());
+ ErrorMsg(factory_pos,
+ "mismatch in number or names of type parameters between "
+ "interface '%s' and default factory class '%s'.\n",
+ interface_name.ToCString(),
+ factory_name.ToCString());
+ }
}
- // The list of type parameters in the default factory clause can be omitted.
- if (mismatch && (num_type_params > 0)) {
- const String& interface_name = String::Handle(interface.Name());
- const String& factory_name = String::Handle(factory_class.Name());
- ErrorMsg(factory_pos,
- "mismatch in number or names of type parameters between "
- "interface '%s' and default factory class '%s'.\n",
- interface_name.ToCString(),
- factory_name.ToCString());
- }
}
ExpectToken(Token::kLBRACE);
@@ -2916,7 +2929,7 @@
const intptr_t num_types = extends_array.Length();
for (intptr_t i = 0; i < num_types; i++) {
type_extends = extends_array.TypeAt(i);
- TryResolveTypeFromClass(type_pos, cls, &type_extends);
+ ResolveTypeFromClass(type_pos, cls, &type_extends, kCanResolve);
extends_array.SetTypeAt(i, type_extends);
}
}
@@ -6127,14 +6140,19 @@
}
-// Try to resolve the given type and its type arguments from the given class.
+// Resolve the given type and its type arguments from the given class according
+// to the given type_resolution.
// Not all involved type classes may get resolved yet, but at least the type
// parameters of the given class will get resolved, thereby relieving the class
// finalizer from resolving type parameters out of context.
-void Parser::TryResolveTypeFromClass(intptr_t type_pos,
- const Class& cls,
- AbstractType* type) {
+void Parser::ResolveTypeFromClass(intptr_t type_pos,
+ const Class& cls,
+ AbstractType* type,
+ TypeResolution type_resolution) {
ASSERT(type != NULL);
+ // TODO(regis): Implement kMustResolve functionality and consolidate with
+ // other resolution code. For now, only support kCanResolve functionality.
+ ASSERT(type_resolution == kCanResolve);
// Resolve class.
if (!type->HasResolvedTypeClass()) {
const UnresolvedClass& unresolved_class =
@@ -6172,7 +6190,7 @@
const intptr_t num_arguments = arguments.Length();
for (intptr_t i = 0; i < num_arguments; i++) {
AbstractType& type_argument = AbstractType::Handle(arguments.TypeAt(i));
- TryResolveTypeFromClass(type_pos, cls, &type_argument);
+ ResolveTypeFromClass(type_pos, cls, &type_argument, type_resolution);
arguments.SetTypeAt(i, type_argument);
}
}
@@ -6184,12 +6202,13 @@
RawObject* Parser::LookupTypeClass(const QualIdent& type_name,
TypeResolution type_resolution) {
ASSERT(type_name.ident != NULL);
+ ASSERT((type_resolution == kCanResolve) || (type_resolution == kMustResolve));
Class& type_class = Class::Handle();
if (type_name.lib_prefix != NULL) {
Library& lib = Library::Handle(type_name.lib_prefix->library());
- type_class ^= lib.LookupLocalClass(*type_name.ident);
+ type_class = lib.LookupLocalClass(*type_name.ident);
} else {
- type_class ^= LookupClass(*type_name.ident);
+ type_class = LookupClass(*type_name.ident);
}
if (!type_class.IsNull()) {
return type_class.raw();
@@ -6619,19 +6638,26 @@
}
type_class = UnresolvedClass::New(type_pos, qualifier, *type_name.ident);
} else {
+ ASSERT((type_resolution == kCanResolve) ||
+ (type_resolution == kMustResolve));
scope_class = TypeParametersScopeClass();
if (!scope_class.IsNull()) {
- TypeParameter& type_parameter = TypeParameter::Handle();
// Check if qualifier is a type parameter in scope.
if (type_name.qualifier != NULL) {
- type_parameter = scope_class.LookupTypeParameter(*type_name.qualifier);
- if (!type_parameter.IsNull()) {
- ErrorMsg(type_pos, "type Parameter '%s' cannot be used as qualifier",
- type_name.qualifier->ToCString());
+ // This was already checked by ParseQualIdent, unless is_top_level_.
hausner 2012/01/26 23:04:29 It's not immediately clear what "This" in the comm
regis 2012/01/26 23:45:17 Correct. I made it clearer by merging both comment
+ if (is_top_level_) {
+ const TypeParameter& type_parameter = TypeParameter::Handle(
+ scope_class.LookupTypeParameter(*type_name.qualifier));
+ if (!type_parameter.IsNull()) {
+ ErrorMsg(type_pos,
hausner 2012/01/26 23:04:29 Same comment as bove: type parameters are not visi
regis 2012/01/26 23:45:17 This is taken care of by TypeParametersScopeClass(
+ "type Parameter '%s' cannot be used as qualifier",
+ type_name.qualifier->ToCString());
+ }
}
} else {
// Check if ident is a type parameter in scope.
- type_parameter = scope_class.LookupTypeParameter(*type_name.ident);
+ TypeParameter& type_parameter = TypeParameter::Handle(
+ scope_class.LookupTypeParameter(*type_name.ident));
if (!type_parameter.IsNull()) {
if (CurrentToken() == Token::kLT) {
// A type parameter cannot be parameterized.
@@ -7068,55 +7094,30 @@
ErrorMsg("type name expected");
}
- // The grammar allows for an optional ('.' identifier)?, which is a named
- // constructor. For that reason, we cannot unconditionally call
- // ParseType(kMustResolve) after we see an identifier, because the named
- // constructor would be misinterpreted as a qualified type name.
- // TODO(regis): Revisit once we correctly support qualified identifiers.
- // For now, we inline a customized version of ParseType(kMustResolve).
- const intptr_t type_pos = token_index_;
- QualIdent type_name;
- ParseQualIdent(&type_name);
- ASSERT(!is_top_level_);
- if ((type_name.qualifier == NULL) &&
- ResolveIdentInLocalScope(type_pos, *type_name.ident, NULL)) {
- ErrorMsg(type_pos, "using '%s' in this context is invalid",
- type_name.ident->ToCString());
+ const AbstractType& type = AbstractType::Handle(ParseType(kMustResolve));
+ if (type.IsTypeParameter()) {
+ // TODO(regis): Use type position once supported.
+ ErrorMsg(new_pos, "type parameter '%s' cannot be instantiated",
+ String::Handle(type.Name()).ToCString());
}
+ Class& type_class = Class::Handle(type.type_class());
+ String& type_class_name = String::Handle(type_class.Name());
+ AbstractTypeArguments& type_arguments =
+ AbstractTypeArguments::ZoneHandle(type.arguments());
+
+ // Unless the parsed type is an interface and a default factory class is
+ // specified (checked below), the constructor class and its name are those of
+ // the parsed type.
hausner 2012/01/26 23:04:29 I would switch the two parts of the sentence aroun
regis 2012/01/26 23:45:17 Done.
+ Class& constructor_class = Class::ZoneHandle(type_class.raw());
+ String& constructor_class_name = String::Handle(type_class_name.raw());
+
+ // The grammar allows for an optional ('.' identifier)? after the type, which
+ // is a named constructor. Note that ParseType(kMustResolve) above will not
+ // consume it as part of a misinterpreted qualified identifier, because only a
+ // valid library prefix is accepted as qualifier.
String* named_constructor = NULL;
if (CurrentToken() == Token::kPERIOD) {
ConsumeToken();
- named_constructor = ExpectIdentifier("identifier expected after '.'");
- }
- const Class& scope_class = Class::Handle(TypeParametersScopeClass());
- if (!scope_class.IsNull()) {
- TypeParameter& type_parameter = TypeParameter::Handle();
- if (type_name.lib_prefix != NULL) {
- // Check if qualifier is a type parameter in scope.
- type_parameter ^= scope_class.LookupTypeParameter(*type_name.qualifier);
- if (!type_parameter.IsNull()) {
- ErrorMsg(type_pos, "type parameter '%s' cannot be used as qualifier",
- String::Handle(type_parameter.Name()).ToCString());
- }
- }
- // Check if ident is a type parameter in scope.
- type_parameter = scope_class.LookupTypeParameter(*type_name.ident);
- if (!type_parameter.IsNull()) {
- ErrorMsg(type_pos, "type parameter '%s' cannot be instantiated",
- String::Handle(type_parameter.Name()).ToCString());
- }
- }
- Class& type_class = Class::ZoneHandle();
- type_class ^= LookupTypeClass(type_name, kMustResolve);
- String& type_class_name = String::Handle();
- type_class_name = type_class.Name();
- AbstractTypeArguments& type_arguments = AbstractTypeArguments::ZoneHandle();
- // Type arguments are not allowed after the optional constructor name.
- if (named_constructor == NULL) {
- type_arguments = ParseTypeArguments(kMustResolve);
- }
- if ((named_constructor == NULL) && (CurrentToken() == Token::kPERIOD)) {
- ConsumeToken();
named_constructor = ExpectIdentifier("name of constructor expected");
}
@@ -7170,54 +7171,81 @@
TypeArguments::Handle())) {
// Class finalization verifies that the factory class has identical type
// parameters as the interface.
- type_class_name = factory_class.Name();
+ constructor_class_name = factory_class.Name();
}
// Always change the result type of the constructor to the factory type.
- type_class = factory_class.raw();
- ASSERT(!type_class.is_interface());
+ constructor_class = factory_class.raw();
+ // The finalized type_arguments are still those of the interface type.
+ ASSERT(!constructor_class.is_interface());
}
// Make sure that an appropriate constructor exists.
const String& constructor_name =
- BuildConstructorName(type_class_name, named_constructor);
- const String& external_constructor_name =
- (named_constructor ? constructor_name : type_class_name);
+ BuildConstructorName(constructor_class_name, named_constructor);
Function& constructor = Function::ZoneHandle(
- type_class.LookupConstructor(constructor_name));
+ constructor_class.LookupConstructor(constructor_name));
if (constructor.IsNull()) {
- constructor = type_class.LookupFactory(constructor_name);
+ constructor = constructor_class.LookupFactory(constructor_name);
// A factory does not have the implicit 'phase' parameter.
arguments_length -= 1;
}
if (constructor.IsNull()) {
+ const String& external_constructor_name =
+ (named_constructor ? constructor_name : constructor_class_name);
ErrorMsg(new_pos, "class '%s' has no constructor or factory named '%s'",
- String::Handle(type_class.Name()).ToCString(),
+ String::Handle(constructor_class.Name()).ToCString(),
external_constructor_name.ToCString());
}
if (!constructor.AreValidArguments(arguments_length, arguments->names())) {
+ const String& external_constructor_name =
+ (named_constructor ? constructor_name : constructor_class_name);
ErrorMsg(new_pos, "invalid arguments passed to constructor '%s' "
"for class '%s'",
external_constructor_name.ToCString(),
- String::Handle(type_class.Name()).ToCString());
+ String::Handle(constructor_class.Name()).ToCString());
}
// Now that the constructor to be called is identified, finalize the type
// argument vector to be passed.
- {
- ASSERT(constructor.owner() == type_class.raw());
+ // The type argument vector of the parsed type was finalized in ParseType.
+ // If the constructor class was changed from the interface class to the
+ // factory class, we need to finalize the type argument vector again, because
+ // it may be longer due to the factory class extending a class, or/and because
+ // the bounds on the factory class may be tighter than on the interface.
+ if (constructor_class.raw() != type_class.raw()) {
+ const intptr_t num_type_parameters = constructor_class.NumTypeParameters();
+ // TODO(regis): Temporary type args should be allocated in new gen heap.
+ TypeArguments& temp_type_arguments = TypeArguments::Handle();
+ if (!type_arguments.IsNull()) {
+ // Copy the parsed type arguments starting at offset 0, because interfaces
+ // have no super types.
+ ASSERT(type_class.NumTypeArguments() == type_class.NumTypeParameters());
+ const intptr_t num_type_arguments = type_arguments.Length();
+ temp_type_arguments = TypeArguments::New(num_type_parameters);
+ AbstractType& type_argument = AbstractType::Handle();
+ for (intptr_t i = 0; i < num_type_parameters; i++) {
+ if (i < num_type_arguments) {
+ type_argument = type_arguments.TypeAt(i);
+ } else {
+ type_argument = Type::DynamicType();
+ }
+ temp_type_arguments.SetTypeAt(i, type_argument);
+ }
+ }
// TODO(regis): Temporary type should be allocated in new gen heap.
- Type& type = Type::Handle(
- Type::NewParameterizedType(type_class, type_arguments));
+ Type& temp_type = Type::Handle(
+ Type::NewParameterizedType(constructor_class, temp_type_arguments));
Error& error = Error::Handle();
- type ^= ClassFinalizer::FinalizeAndCanonicalizeType(type_class,
- type,
- &error);
+ const Class& scope_class = Class::Handle(TypeParametersScopeClass());
+ temp_type ^= ClassFinalizer::FinalizeAndCanonicalizeType(scope_class,
+ temp_type,
+ &error);
if (!error.IsNull()) {
ErrorMsg(error.ToErrorCString());
}
// The type argument vector may have been expanded with the type arguments
- // of the super type when finalizing the type.
- type_arguments = type.arguments();
+ // of the super type when finalizing the temporary type.
+ type_arguments = temp_type.arguments();
}
type_arguments ^= type_arguments.Canonicalize();
@@ -7229,7 +7257,7 @@
String::Handle(constructor.name()).ToCString());
}
const Instance& const_instance = Instance::ZoneHandle(
- EvaluateConstConstructorCall(type_class,
+ EvaluateConstConstructorCall(constructor_class,
type_arguments,
constructor,
arguments));

Powered by Google App Engine
This is Rietveld 408576698