Chromium Code Reviews| Index: runtime/vm/parser.cc |
| =================================================================== |
| --- runtime/vm/parser.cc (revision 1775) |
| +++ runtime/vm/parser.cc (working copy) |
| @@ -32,11 +32,9 @@ |
| 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"; |
| @@ -6584,34 +6582,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 +6633,52 @@ |
| } |
| 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 must be a constant of type '%s'", |
|
hausner
2011/11/23 17:34:34
Even though we indicate the column position of the
regis
2011/11/23 19:29:44
Done here and for map literals below.
|
| + 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,11 @@ |
| // 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()); |
| + String::Handle(value_type.Name()).ToCString()); |
| } |
| key_value_array.SetAt(i, arg->AsLiteralNode()->literal()); |
| } |
| @@ -6821,15 +6835,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 +6855,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 +6875,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 +7320,9 @@ |
| } |
| -void Parser::SkipArrayLiteral() { |
| +void Parser::SkipListLiteral() { |
| if (CurrentToken() == Token::kINDEX) { |
| - // Empty array literal. |
| + // Empty list literal. |
| ConsumeToken(); |
| return; |
| } |
| @@ -7356,7 +7369,7 @@ |
| } |
| if ((CurrentToken() == Token::kLBRACK) || |
| (CurrentToken() == Token::kINDEX)) { |
| - SkipArrayLiteral(); |
| + SkipListLiteral(); |
| } else if (CurrentToken() == Token::kLBRACE) { |
| SkipMapLiteral(); |
| } |