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

Unified Diff: runtime/vm/parser.cc

Issue 8676001: Implement type checking of list literals (issue 220). (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: '' Created 9 years, 1 month 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') | runtime/vm/scanner.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 1805)
+++ runtime/vm/parser.cc (working copy)
@@ -26,17 +26,14 @@
DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations.");
DEFINE_FLAG(bool, warning_as_error, false, "Treat warnings as errors.");
DEFINE_FLAG(bool, silent_warnings, false, "Silence warnings.");
-DECLARE_FLAG(bool, expose_core_impl);
// All references to Dart names are listed here.
static const char* kAssertionErrorName = "AssertionError";
static const char* kFallThroughErrorName = "FallThroughError";
static const char* kThrowNewName = "_throwNew";
-static const char* kGrowableObjectArrayFromArrayName =
- "GrowableObjectArray._usingArray";
-static const char* kGrowableObjectArrayName = "GrowableObjectArray";
-static const char* kLiteralMapFactoryName = "_LiteralMapFactory";
-static const char* kLiteralMapFactoryFromLiteralName = "Map.fromLiteral";
+static const char* kLiteralFactoryClassName = "_LiteralFactory";
+static const char* kLiteralFactoryListFromLiteralName = "List.fromLiteral";
+static const char* kLiteralFactoryMapFromLiteralName = "Map.fromLiteral";
static const char* kImmutableMapName = "ImmutableMap";
static const char* kImmutableMapConstructorName = "ImmutableMap.";
static const char* kStringClassName = "StringBase";
@@ -4436,8 +4433,7 @@
static RawClass* LookupCoreClass(const String& class_name) {
const Library& core_lib = Library::Handle(Library::CoreLibrary());
String& name = String::Handle(class_name.raw());
- if ((class_name.CharAt(0) == Scanner::kPrivateIdentifierStart) &&
- !FLAG_expose_core_impl) {
+ if (class_name.CharAt(0) == Scanner::kPrivateIdentifierStart) {
// Private identifiers are mangled on a per script basis.
name = String::Concat(name, String::Handle(core_lib.private_key()));
name = String::NewSymbol(name);
@@ -6584,34 +6580,46 @@
// Parse "[" [ expr { "," expr } ["," ] "]".
-// Note: if the array literal is empty and the brackets have no whitespace
+// Note: if the list literal is empty and the brackets have no whitespace
// between them, the scanner recognizes the opening and closing bracket
// as one token of type Token::kINDEX.
-AstNode* Parser::ParseArrayLiteral(intptr_t type_pos,
- bool is_const,
- const TypeArguments& type_arguments) {
+AstNode* Parser::ParseListLiteral(intptr_t type_pos,
+ bool is_const,
+ const TypeArguments& type_arguments) {
+ TRACE_PARSER("ParseListLiteral");
+ ASSERT(type_pos >= 0);
ASSERT(CurrentToken() == Token::kLBRACK || CurrentToken() == Token::kINDEX);
const intptr_t literal_pos = token_index_;
bool is_empty_literal = CurrentToken() == Token::kINDEX;
ConsumeToken();
- // If no type arguments are provided, leave them as null, which is equivalent
- // to using Array<Dynamic>. See issue 4966724.
+ Type& element_type = Type::Handle(Type::DynamicType());
+ // If no type argument vector is provided, leave it as null, which is
+ // equivalent to using Dynamic as the type argument for the element type.
if (!type_arguments.IsNull()) {
- // For now, only check the number of type arguments. See issue 4975876.
+ ASSERT(type_arguments.Length() > 0);
+ // List literals take a single type argument.
+ element_type = type_arguments.TypeAt(0);
if (type_arguments.Length() != 1) {
- ASSERT(type_pos >= 0);
- ErrorMsg(type_pos, "wrong number of type arguments for Array literal");
+ ErrorMsg(type_pos,
+ "a list literal takes one type argument specifying "
+ "the element type");
}
+ if (is_const && !element_type.IsInstantiated()) {
+ ErrorMsg(type_pos,
+ "the type argument of a constant list literal cannot include "
+ "a type variable");
+ }
}
+ ASSERT(type_arguments.IsNull() || (type_arguments.Length() == 1));
- // Parse the array elements. Note: there may be an optional extra
+ // Parse the list elements. Note: there may be an optional extra
// comma after the last element.
- ArrayNode* array = new ArrayNode(token_index_, type_arguments);
+ ArrayNode* list = new ArrayNode(token_index_, TypeArguments::ZoneHandle());
if (!is_empty_literal) {
const bool saved_mode = SetAllowFunctionLiterals(true);
while (CurrentToken() != Token::kRBRACK) {
- array->AddElement(ParseExpr(is_const));
+ list->AddElement(ParseExpr(is_const));
if (CurrentToken() == Token::kCOMMA) {
ConsumeToken();
} else if (CurrentToken() != Token::kRBRACK) {
@@ -6623,49 +6631,54 @@
}
if (is_const) {
- // Allocate and initialize the array at compile time.
- Array& lit_array =
- Array::ZoneHandle(Array::New(array->length(), Heap::kOld));
- if (!type_arguments.IsNull()) {
- // TODO(regis): Where should we check the constraints on type parameters?
- if (!type_arguments.IsInstantiated()) {
- ErrorMsg("type must be constant in const constructor");
- }
- lit_array.SetTypeArguments(type_arguments);
- }
+ // Allocate and initialize the const list at compile time.
+ Array& const_list =
+ Array::ZoneHandle(Array::New(list->length(), Heap::kOld));
+ const_list.SetTypeArguments(type_arguments);
- for (int i = 0; i < array->length(); i++) {
- AstNode* elem = array->ElementAt(i);
+ for (int i = 0; i < list->length(); i++) {
+ AstNode* elem = list->ElementAt(i);
// Arguments have been evaluated to a literal value already.
ASSERT(elem->IsLiteralNode());
- lit_array.SetAt(i, elem->AsLiteralNode()->literal());
+ if (!element_type.IsDynamicType() &&
+ !elem->AsLiteralNode()->literal().Is(element_type)) {
+ ErrorMsg(elem->AsLiteralNode()->token_index(),
+ "list literal element at index %d must be "
+ "a constant of type '%s'",
+ i,
+ String::Handle(element_type.Name()).ToCString());
+ }
+ const_list.SetAt(i, elem->AsLiteralNode()->literal());
}
- lit_array ^= lit_array.Canonicalize();
- lit_array.MakeImmutable();
- return new LiteralNode(literal_pos, lit_array);
+ const_list ^= const_list.Canonicalize();
+ const_list.MakeImmutable();
+ return new LiteralNode(literal_pos, const_list);
} else {
+ // Factory call at runtime.
+ String& literal_factory_class_name = String::Handle(
+ String::NewSymbol(kLiteralFactoryClassName));
+ const Class& literal_factory_class =
+ Class::Handle(LookupCoreClass(literal_factory_class_name));
+ ASSERT(!literal_factory_class.IsNull());
+ const String& literal_list_factory_name =
+ String::Handle(String::NewSymbol(kLiteralFactoryListFromLiteralName));
+ const Function& literal_list_factory = Function::ZoneHandle(
+ literal_factory_class.LookupFactory(literal_list_factory_name));
+ ASSERT(!literal_list_factory.IsNull());
if (!type_arguments.IsNull() &&
!type_arguments.IsInstantiated() &&
(current_block_->scope->function_level() > 0)) {
// Make sure that the instantiator is captured.
CaptureReceiver();
}
-
- // Make a new growable array from the fixed array.
- String& growable_object_array_class_name = String::Handle(
- String::NewSymbol(kGrowableObjectArrayName));
- const Class& growable_array_class = Class::Handle(
- LookupImplClass(growable_object_array_class_name));
- String& ctor_name =
- String::Handle(String::NewSymbol(kGrowableObjectArrayFromArrayName));
- Function& array_ctor = Function::ZoneHandle(
- growable_array_class.LookupConstructor(ctor_name));
- ASSERT(!array_ctor.IsNull());
- ArgumentListNode* ctor_args = new ArgumentListNode(literal_pos);
- ctor_args->Add(array);
- CheckConstructorCallTypeArguments(literal_pos, array_ctor, type_arguments);
+ ArgumentListNode* factory_param = new ArgumentListNode(literal_pos);
+ factory_param->Add(
+ new LiteralNode(literal_pos, Smi::ZoneHandle(Smi::New(literal_pos))));
+ factory_param->Add(
+ new LiteralNode(literal_pos, String::ZoneHandle(element_type.Name())));
+ factory_param->Add(list);
return new ConstructorCallNode(
- literal_pos, type_arguments, array_ctor, ctor_args);
+ literal_pos, type_arguments, literal_list_factory, factory_param);
}
}
@@ -6704,14 +6717,15 @@
const intptr_t literal_pos = token_index_;
ConsumeToken();
- Type& value_type_argument = Type::Handle(Type::DynamicType());
+ Type& value_type = Type::Handle(Type::DynamicType());
TypeArguments& map_type_arguments =
TypeArguments::ZoneHandle(type_arguments.raw());
- // If no type argument is provided, leave it as null, which is equivalent
- // to using Dynamic as the type argument for the value type.
+ // If no type argument vector is provided, leave it as null, which is
+ // equivalent to using Dynamic as the type argument for the value type.
if (!map_type_arguments.IsNull()) {
- // Map literals only take one type argument.
- value_type_argument = map_type_arguments.TypeAt(0);
+ ASSERT(map_type_arguments.Length() > 0);
+ // Map literals take a single type argument.
+ value_type = map_type_arguments.TypeAt(0);
if (map_type_arguments.Length() > 1) {
// We temporarily accept two type arguments, as long as the first one is
// type String.
@@ -6720,21 +6734,21 @@
"a map literal takes one type argument specifying "
"the value type");
}
- if (!value_type_argument.IsStringInterface()) {
+ if (!value_type.IsStringInterface()) {
ErrorMsg(type_pos,
"the key type of a map literal is implicitly 'String'");
}
Warning(type_pos,
"a map literal takes one type argument specifying "
"the value type");
- value_type_argument = map_type_arguments.TypeAt(1);
+ value_type = map_type_arguments.TypeAt(1);
} else {
TypeArray& type_array = TypeArray::Handle(TypeArray::New(2));
type_array.SetTypeAt(0, Type::Handle(Type::StringInterface()));
- type_array.SetTypeAt(1, value_type_argument);
+ type_array.SetTypeAt(1, value_type);
map_type_arguments = type_array.raw();
}
- if (is_const && !value_type_argument.IsInstantiated()) {
+ if (is_const && !value_type.IsInstantiated()) {
ErrorMsg(type_pos,
"the type argument of a constant map literal cannot include "
"a type variable");
@@ -6785,11 +6799,13 @@
// Arguments have been evaluated to a literal value already.
ASSERT(arg->IsLiteralNode());
if (((i % 2) == 1) && // Check values only, not keys.
- !value_type_argument.IsDynamicType() &&
- !arg->AsLiteralNode()->literal().Is(value_type_argument)) {
+ !value_type.IsDynamicType() &&
+ !arg->AsLiteralNode()->literal().Is(value_type)) {
ErrorMsg(arg->AsLiteralNode()->token_index(),
- "map literal entry value must be a constant of type '%s'",
- String::Handle(value_type_argument.Name()).ToCString());
+ "map literal value at index %d must be "
+ "a constant of type '%s'",
+ i >> 1,
+ String::Handle(value_type.Name()).ToCString());
}
key_value_array.SetAt(i, arg->AsLiteralNode()->literal());
}
@@ -6821,15 +6837,15 @@
}
} else {
// Factory call at runtime.
- String& literal_map_factory_class_name = String::Handle(
- String::NewSymbol(kLiteralMapFactoryName));
- const Class& literal_map_factory_class =
- Class::Handle(LookupCoreClass(literal_map_factory_class_name));
- ASSERT(!literal_map_factory_class.IsNull());
+ String& literal_factory_class_name = String::Handle(
+ String::NewSymbol(kLiteralFactoryClassName));
+ const Class& literal_factory_class =
+ Class::Handle(LookupCoreClass(literal_factory_class_name));
+ ASSERT(!literal_factory_class.IsNull());
const String& literal_map_factory_name =
- String::Handle(String::NewSymbol(kLiteralMapFactoryFromLiteralName));
+ String::Handle(String::NewSymbol(kLiteralFactoryMapFromLiteralName));
const Function& literal_map_factory = Function::ZoneHandle(
- literal_map_factory_class.LookupFactory(literal_map_factory_name));
+ literal_factory_class.LookupFactory(literal_map_factory_name));
ASSERT(!literal_map_factory.IsNull());
if (!map_type_arguments.IsNull() &&
!map_type_arguments.IsInstantiated() &&
@@ -6841,8 +6857,7 @@
factory_param->Add(
new LiteralNode(literal_pos, Smi::ZoneHandle(Smi::New(literal_pos))));
factory_param->Add(
- new LiteralNode(literal_pos,
- String::ZoneHandle(value_type_argument.Name())));
+ new LiteralNode(literal_pos, String::ZoneHandle(value_type.Name())));
factory_param->Add(kv_pairs);
return new ConstructorCallNode(
literal_pos, map_type_arguments, literal_map_factory, factory_param);
@@ -6862,7 +6877,7 @@
AstNode* primary = NULL;
if ((CurrentToken() == Token::kLBRACK) ||
(CurrentToken() == Token::kINDEX)) {
- primary = ParseArrayLiteral(type_pos, is_const, type_arguments);
+ primary = ParseListLiteral(type_pos, is_const, type_arguments);
} else if (CurrentToken() == Token::kLBRACE) {
primary = ParseMapLiteral(type_pos, is_const, type_arguments);
} else {
@@ -7307,9 +7322,9 @@
}
-void Parser::SkipArrayLiteral() {
+void Parser::SkipListLiteral() {
if (CurrentToken() == Token::kINDEX) {
- // Empty array literal.
+ // Empty list literal.
ConsumeToken();
return;
}
@@ -7356,7 +7371,7 @@
}
if ((CurrentToken() == Token::kLBRACK) ||
(CurrentToken() == Token::kINDEX)) {
- SkipArrayLiteral();
+ SkipListLiteral();
} else if (CurrentToken() == Token::kLBRACE) {
SkipMapLiteral();
}
« no previous file with comments | « runtime/vm/parser.h ('k') | runtime/vm/scanner.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698