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(); |
} |