OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/parser.h" | 5 #include "vm/parser.h" |
6 | 6 |
7 #include "lib/invocation_mirror.h" | 7 #include "lib/invocation_mirror.h" |
8 #include "platform/utils.h" | 8 #include "platform/utils.h" |
9 #include "vm/ast_transformer.h" | 9 #include "vm/ast_transformer.h" |
10 #include "vm/bootstrap.h" | 10 #include "vm/bootstrap.h" |
11 #include "vm/class_finalizer.h" | 11 #include "vm/class_finalizer.h" |
12 #include "vm/compiler.h" | 12 #include "vm/compiler.h" |
13 #include "vm/compiler_stats.h" | 13 #include "vm/compiler_stats.h" |
14 #include "vm/dart_api_impl.h" | 14 #include "vm/dart_api_impl.h" |
15 #include "vm/dart_entry.h" | 15 #include "vm/dart_entry.h" |
16 #include "vm/flags.h" | 16 #include "vm/flags.h" |
17 #include "vm/growable_array.h" | 17 #include "vm/growable_array.h" |
18 #include "vm/handles.h" | 18 #include "vm/handles.h" |
| 19 #include "vm/hash_table.h" |
19 #include "vm/heap.h" | 20 #include "vm/heap.h" |
20 #include "vm/isolate.h" | 21 #include "vm/isolate.h" |
21 #include "vm/longjump.h" | 22 #include "vm/longjump.h" |
22 #include "vm/native_arguments.h" | 23 #include "vm/native_arguments.h" |
23 #include "vm/native_entry.h" | 24 #include "vm/native_entry.h" |
24 #include "vm/object.h" | 25 #include "vm/object.h" |
25 #include "vm/object_store.h" | 26 #include "vm/object_store.h" |
26 #include "vm/os.h" | 27 #include "vm/os.h" |
27 #include "vm/regexp_assembler.h" | 28 #include "vm/regexp_assembler.h" |
28 #include "vm/report.h" | 29 #include "vm/report.h" |
(...skipping 11849 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11878 bool Parser::IsInstantiatorRequired() const { | 11879 bool Parser::IsInstantiatorRequired() const { |
11879 ASSERT(!current_function().IsNull()); | 11880 ASSERT(!current_function().IsNull()); |
11880 if (current_function().is_static() && | 11881 if (current_function().is_static() && |
11881 !current_function().IsInFactoryScope()) { | 11882 !current_function().IsInFactoryScope()) { |
11882 return false; | 11883 return false; |
11883 } | 11884 } |
11884 return current_class().NumTypeParameters() > 0; | 11885 return current_class().NumTypeParameters() > 0; |
11885 } | 11886 } |
11886 | 11887 |
11887 | 11888 |
| 11889 class ConstMapKeyEqualsTraits { |
| 11890 public: |
| 11891 static bool IsMatch(const Object& a, const Object& b) { |
| 11892 return String::Cast(a).Equals(String::Cast(b)); |
| 11893 } |
| 11894 static bool IsMatch(const char* key, const Object& b) { |
| 11895 return String::Cast(b).Equals(key); |
| 11896 } |
| 11897 static uword Hash(const Object& obj) { |
| 11898 return String::Cast(obj).Hash(); |
| 11899 } |
| 11900 static uword Hash(const char* key) { |
| 11901 return String::Hash(key, strlen(key)); |
| 11902 } |
| 11903 }; |
| 11904 typedef UnorderedHashMap<ConstMapKeyEqualsTraits> ConstantsMap; |
| 11905 |
| 11906 |
| 11907 void Parser::CacheConstantValue(intptr_t token_pos, const Instance& value) { |
| 11908 String& key = String::Handle(Z, script_.url()); |
| 11909 String& suffix = |
| 11910 String::Handle(Z, String::NewFormatted("_%" Pd "", token_pos)); |
| 11911 key = Symbols::FromConcat(key, suffix); |
| 11912 if (isolate()->object_store()->compile_time_constants() == Array::null()) { |
| 11913 const intptr_t kInitialConstMapSize = 16; |
| 11914 isolate()->object_store()->set_compile_time_constants( |
| 11915 Array::Handle(Z, HashTables::New<ConstantsMap>(kInitialConstMapSize))); |
| 11916 } |
| 11917 ConstantsMap constants(isolate()->object_store()->compile_time_constants()); |
| 11918 constants.UpdateOrInsert(key, value); |
| 11919 if (FLAG_compiler_stats) { |
| 11920 isolate_->compiler_stats()->num_cached_consts = constants.NumOccupied(); |
| 11921 } |
| 11922 isolate()->object_store()->set_compile_time_constants(constants.Release()); |
| 11923 } |
| 11924 |
| 11925 |
| 11926 bool Parser::GetCachedConstant(intptr_t token_pos, Instance* value) { |
| 11927 if (isolate()->object_store()->compile_time_constants() == Array::null()) { |
| 11928 return false; |
| 11929 } |
| 11930 // We don't want to allocate anything in the heap here since this code |
| 11931 // is called from the optimizing compiler in the background thread. Allocate |
| 11932 // the key value in the zone instead. |
| 11933 const char* key = Z->PrintToString("%s_%" Pd "", |
| 11934 String::Handle(Z, script_.url()).ToCString(), |
| 11935 token_pos); |
| 11936 ConstantsMap constants(isolate()->object_store()->compile_time_constants()); |
| 11937 bool is_present = false; |
| 11938 *value ^= constants.GetOrNull<const char *>(key, &is_present); |
| 11939 ASSERT(constants.Release().raw() == |
| 11940 isolate()->object_store()->compile_time_constants()); |
| 11941 if (FLAG_compiler_stats && is_present) { |
| 11942 isolate_->compiler_stats()->num_const_cache_hits++; |
| 11943 } |
| 11944 return is_present; |
| 11945 } |
| 11946 |
| 11947 |
11888 RawInstance* Parser::TryCanonicalize(const Instance& instance, | 11948 RawInstance* Parser::TryCanonicalize(const Instance& instance, |
11889 intptr_t token_pos) { | 11949 intptr_t token_pos) { |
11890 if (instance.IsNull()) { | 11950 if (instance.IsNull()) { |
11891 return instance.raw(); | 11951 return instance.raw(); |
11892 } | 11952 } |
11893 const char* error_str = NULL; | 11953 const char* error_str = NULL; |
11894 Instance& result = | 11954 Instance& result = |
11895 Instance::Handle(Z, instance.CheckAndCanonicalize(&error_str)); | 11955 Instance::Handle(Z, instance.CheckAndCanonicalize(&error_str)); |
11896 if (result.IsNull()) { | 11956 if (result.IsNull()) { |
11897 ReportError(token_pos, "Invalid const object %s", error_str); | 11957 ReportError(token_pos, "Invalid const object %s", error_str); |
(...skipping 602 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12500 // Note: if the list literal is empty and the brackets have no whitespace | 12560 // Note: if the list literal is empty and the brackets have no whitespace |
12501 // between them, the scanner recognizes the opening and closing bracket | 12561 // between them, the scanner recognizes the opening and closing bracket |
12502 // as one token of type Token::kINDEX. | 12562 // as one token of type Token::kINDEX. |
12503 AstNode* Parser::ParseListLiteral(intptr_t type_pos, | 12563 AstNode* Parser::ParseListLiteral(intptr_t type_pos, |
12504 bool is_const, | 12564 bool is_const, |
12505 const TypeArguments& type_arguments) { | 12565 const TypeArguments& type_arguments) { |
12506 TRACE_PARSER("ParseListLiteral"); | 12566 TRACE_PARSER("ParseListLiteral"); |
12507 ASSERT(type_pos >= 0); | 12567 ASSERT(type_pos >= 0); |
12508 ASSERT(CurrentToken() == Token::kLBRACK || CurrentToken() == Token::kINDEX); | 12568 ASSERT(CurrentToken() == Token::kLBRACK || CurrentToken() == Token::kINDEX); |
12509 const intptr_t literal_pos = TokenPos(); | 12569 const intptr_t literal_pos = TokenPos(); |
| 12570 |
| 12571 if (is_const) { |
| 12572 Instance& existing_const = Instance::ZoneHandle(Z); |
| 12573 if (GetCachedConstant(literal_pos, &existing_const)) { |
| 12574 SkipListLiteral(); |
| 12575 return new(Z) LiteralNode(literal_pos, existing_const); |
| 12576 } |
| 12577 } |
| 12578 |
12510 bool is_empty_literal = CurrentToken() == Token::kINDEX; | 12579 bool is_empty_literal = CurrentToken() == Token::kINDEX; |
12511 ConsumeToken(); | 12580 ConsumeToken(); |
12512 | 12581 |
12513 AbstractType& element_type = Type::ZoneHandle(Z, Type::DynamicType()); | 12582 AbstractType& element_type = Type::ZoneHandle(Z, Type::DynamicType()); |
12514 TypeArguments& list_type_arguments = | 12583 TypeArguments& list_type_arguments = |
12515 TypeArguments::ZoneHandle(Z, type_arguments.raw()); | 12584 TypeArguments::ZoneHandle(Z, type_arguments.raw()); |
12516 // If no type argument vector is provided, leave it as null, which is | 12585 // If no type argument vector is provided, leave it as null, which is |
12517 // equivalent to using dynamic as the type argument for the element type. | 12586 // equivalent to using dynamic as the type argument for the element type. |
12518 if (!list_type_arguments.IsNull()) { | 12587 if (!list_type_arguments.IsNull()) { |
12519 ASSERT(list_type_arguments.Length() > 0); | 12588 ASSERT(list_type_arguments.Length() > 0); |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12567 } else if (CurrentToken() != Token::kRBRACK) { | 12636 } else if (CurrentToken() != Token::kRBRACK) { |
12568 ReportError("comma or ']' expected"); | 12637 ReportError("comma or ']' expected"); |
12569 } | 12638 } |
12570 } | 12639 } |
12571 ExpectToken(Token::kRBRACK); | 12640 ExpectToken(Token::kRBRACK); |
12572 SetAllowFunctionLiterals(saved_mode); | 12641 SetAllowFunctionLiterals(saved_mode); |
12573 } | 12642 } |
12574 | 12643 |
12575 if (is_const) { | 12644 if (is_const) { |
12576 // Allocate and initialize the const list at compile time. | 12645 // Allocate and initialize the const list at compile time. |
12577 Array& const_list = | 12646 Array& const_list = Array::ZoneHandle(Z, |
12578 Array::ZoneHandle(Z, Array::New(element_list.length(), Heap::kOld)); | 12647 Array::New(element_list.length(), Heap::kOld)); |
12579 const_list.SetTypeArguments( | 12648 const_list.SetTypeArguments( |
12580 TypeArguments::Handle(Z, list_type_arguments.Canonicalize())); | 12649 TypeArguments::Handle(Z, list_type_arguments.Canonicalize())); |
12581 Error& malformed_error = Error::Handle(Z); | 12650 Error& malformed_error = Error::Handle(Z); |
12582 for (int i = 0; i < element_list.length(); i++) { | 12651 for (int i = 0; i < element_list.length(); i++) { |
12583 AstNode* elem = element_list[i]; | 12652 AstNode* elem = element_list[i]; |
12584 // Arguments have been evaluated to a literal value already. | 12653 // Arguments have been evaluated to a literal value already. |
12585 ASSERT(elem->IsLiteralNode()); | 12654 ASSERT(elem->IsLiteralNode()); |
12586 ASSERT(!is_top_level_); // We cannot check unresolved types. | 12655 ASSERT(!is_top_level_); // We cannot check unresolved types. |
12587 if (I->flags().type_checks() && | 12656 if (I->flags().type_checks() && |
12588 !element_type.IsDynamicType() && | 12657 !element_type.IsDynamicType() && |
(...skipping 11 matching lines...) Expand all Loading... |
12600 "a constant of type '%s'", | 12669 "a constant of type '%s'", |
12601 i, | 12670 i, |
12602 String::Handle(Z, | 12671 String::Handle(Z, |
12603 element_type.UserVisibleName()).ToCString()); | 12672 element_type.UserVisibleName()).ToCString()); |
12604 } | 12673 } |
12605 } | 12674 } |
12606 const_list.SetAt(i, elem->AsLiteralNode()->literal()); | 12675 const_list.SetAt(i, elem->AsLiteralNode()->literal()); |
12607 } | 12676 } |
12608 const_list.MakeImmutable(); | 12677 const_list.MakeImmutable(); |
12609 const_list ^= TryCanonicalize(const_list, literal_pos); | 12678 const_list ^= TryCanonicalize(const_list, literal_pos); |
| 12679 CacheConstantValue(literal_pos, const_list); |
12610 return new(Z) LiteralNode(literal_pos, const_list); | 12680 return new(Z) LiteralNode(literal_pos, const_list); |
12611 } else { | 12681 } else { |
12612 // Factory call at runtime. | 12682 // Factory call at runtime. |
12613 const Class& factory_class = | 12683 const Class& factory_class = |
12614 Class::Handle(Z, Library::LookupCoreClass(Symbols::List())); | 12684 Class::Handle(Z, Library::LookupCoreClass(Symbols::List())); |
12615 ASSERT(!factory_class.IsNull()); | 12685 ASSERT(!factory_class.IsNull()); |
12616 const Function& factory_method = Function::ZoneHandle(Z, | 12686 const Function& factory_method = Function::ZoneHandle(Z, |
12617 factory_class.LookupFactory( | 12687 factory_class.LookupFactory( |
12618 Library::PrivateCoreLibName(Symbols::ListLiteralFactory()))); | 12688 Library::PrivateCoreLibName(Symbols::ListLiteralFactory()))); |
12619 ASSERT(!factory_method.IsNull()); | 12689 ASSERT(!factory_method.IsNull()); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12693 } | 12763 } |
12694 | 12764 |
12695 | 12765 |
12696 AstNode* Parser::ParseMapLiteral(intptr_t type_pos, | 12766 AstNode* Parser::ParseMapLiteral(intptr_t type_pos, |
12697 bool is_const, | 12767 bool is_const, |
12698 const TypeArguments& type_arguments) { | 12768 const TypeArguments& type_arguments) { |
12699 TRACE_PARSER("ParseMapLiteral"); | 12769 TRACE_PARSER("ParseMapLiteral"); |
12700 ASSERT(type_pos >= 0); | 12770 ASSERT(type_pos >= 0); |
12701 ASSERT(CurrentToken() == Token::kLBRACE); | 12771 ASSERT(CurrentToken() == Token::kLBRACE); |
12702 const intptr_t literal_pos = TokenPos(); | 12772 const intptr_t literal_pos = TokenPos(); |
12703 ConsumeToken(); | |
12704 | 12773 |
| 12774 if (is_const) { |
| 12775 Instance& existing_const = Instance::ZoneHandle(Z); |
| 12776 if (GetCachedConstant(literal_pos, &existing_const)) { |
| 12777 SkipMapLiteral(); |
| 12778 return new(Z) LiteralNode(literal_pos, existing_const); |
| 12779 } |
| 12780 } |
| 12781 |
| 12782 ConsumeToken(); // Opening brace. |
12705 AbstractType& key_type = Type::ZoneHandle(Z, Type::DynamicType()); | 12783 AbstractType& key_type = Type::ZoneHandle(Z, Type::DynamicType()); |
12706 AbstractType& value_type = Type::ZoneHandle(Z, Type::DynamicType()); | 12784 AbstractType& value_type = Type::ZoneHandle(Z, Type::DynamicType()); |
12707 TypeArguments& map_type_arguments = | 12785 TypeArguments& map_type_arguments = |
12708 TypeArguments::ZoneHandle(Z, type_arguments.raw()); | 12786 TypeArguments::ZoneHandle(Z, type_arguments.raw()); |
12709 // If no type argument vector is provided, leave it as null, which is | 12787 // If no type argument vector is provided, leave it as null, which is |
12710 // equivalent to using dynamic as the type argument for the both key and value | 12788 // equivalent to using dynamic as the type argument for the both key and value |
12711 // types. | 12789 // types. |
12712 if (!map_type_arguments.IsNull()) { | 12790 if (!map_type_arguments.IsNull()) { |
12713 ASSERT(map_type_arguments.Length() > 0); | 12791 ASSERT(map_type_arguments.Length() > 0); |
12714 // Map literals take two type arguments. | 12792 // Map literals take two type arguments. |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12851 EvaluateConstConstructorCall(immutable_map_class, | 12929 EvaluateConstConstructorCall(immutable_map_class, |
12852 map_type_arguments, | 12930 map_type_arguments, |
12853 map_constr, | 12931 map_constr, |
12854 constr_args)); | 12932 constr_args)); |
12855 if (constructor_result.IsUnhandledException()) { | 12933 if (constructor_result.IsUnhandledException()) { |
12856 ReportErrors(Error::Cast(constructor_result), | 12934 ReportErrors(Error::Cast(constructor_result), |
12857 script_, literal_pos, | 12935 script_, literal_pos, |
12858 "error executing const Map constructor"); | 12936 "error executing const Map constructor"); |
12859 } else { | 12937 } else { |
12860 const Instance& const_instance = Instance::Cast(constructor_result); | 12938 const Instance& const_instance = Instance::Cast(constructor_result); |
| 12939 CacheConstantValue(literal_pos, const_instance); |
12861 return new(Z) LiteralNode( | 12940 return new(Z) LiteralNode( |
12862 literal_pos, Instance::ZoneHandle(Z, const_instance.raw())); | 12941 literal_pos, Instance::ZoneHandle(Z, const_instance.raw())); |
12863 } | 12942 } |
12864 } else { | 12943 } else { |
12865 // Factory call at runtime. | 12944 // Factory call at runtime. |
12866 const Class& factory_class = | 12945 const Class& factory_class = |
12867 Class::Handle(Z, Library::LookupCoreClass(Symbols::Map())); | 12946 Class::Handle(Z, Library::LookupCoreClass(Symbols::Map())); |
12868 ASSERT(!factory_class.IsNull()); | 12947 ASSERT(!factory_class.IsNull()); |
12869 const Function& factory_method = Function::ZoneHandle(Z, | 12948 const Function& factory_method = Function::ZoneHandle(Z, |
12870 factory_class.LookupFactory( | 12949 factory_class.LookupFactory( |
(...skipping 523 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13394 // Make the constructor call. | 13473 // Make the constructor call. |
13395 AstNode* new_object = NULL; | 13474 AstNode* new_object = NULL; |
13396 if (is_const) { | 13475 if (is_const) { |
13397 if (!constructor.is_const()) { | 13476 if (!constructor.is_const()) { |
13398 const String& external_constructor_name = | 13477 const String& external_constructor_name = |
13399 (named_constructor ? constructor_name : type_class_name); | 13478 (named_constructor ? constructor_name : type_class_name); |
13400 ReportError("non-const constructor '%s' cannot be used in " | 13479 ReportError("non-const constructor '%s' cannot be used in " |
13401 "const object creation", | 13480 "const object creation", |
13402 external_constructor_name.ToCString()); | 13481 external_constructor_name.ToCString()); |
13403 } | 13482 } |
13404 const Object& constructor_result = Object::Handle(Z, | 13483 |
13405 EvaluateConstConstructorCall(type_class, | 13484 Instance& const_instance = Instance::ZoneHandle(Z); |
13406 type_arguments, | 13485 if (GetCachedConstant(new_pos, &const_instance)) { |
13407 constructor, | 13486 // Cache hit, nothing else to do. |
13408 arguments)); | |
13409 if (constructor_result.IsUnhandledException()) { | |
13410 // It's a compile-time error if invocation of a const constructor | |
13411 // call fails. | |
13412 ReportErrors(Error::Cast(constructor_result), | |
13413 script_, new_pos, | |
13414 "error while evaluating const constructor"); | |
13415 } else { | 13487 } else { |
13416 // Const constructors can return null in the case where a const native | 13488 Object& constructor_result = Object::Handle(Z, |
13417 // factory returns a null value. Thus we cannot use a Instance::Cast here. | 13489 EvaluateConstConstructorCall(type_class, |
13418 Instance& const_instance = Instance::Handle(Z); | 13490 type_arguments, |
| 13491 constructor, |
| 13492 arguments)); |
| 13493 if (constructor_result.IsUnhandledException()) { |
| 13494 // It's a compile-time error if invocation of a const constructor |
| 13495 // call fails. |
| 13496 ReportErrors(Error::Cast(constructor_result), |
| 13497 script_, new_pos, |
| 13498 "error while evaluating const constructor"); |
| 13499 } |
13419 const_instance ^= constructor_result.raw(); | 13500 const_instance ^= constructor_result.raw(); |
13420 new_object = new(Z) LiteralNode( | 13501 CacheConstantValue(new_pos, const_instance); |
13421 new_pos, Instance::ZoneHandle(Z, const_instance.raw())); | 13502 } |
13422 if (!type_bound.IsNull()) { | 13503 new_object = new(Z) LiteralNode(new_pos, const_instance); |
13423 ASSERT(!type_bound.IsMalformed()); | 13504 if (!type_bound.IsNull()) { |
13424 Error& malformed_error = Error::Handle(Z); | 13505 ASSERT(!type_bound.IsMalformed()); |
13425 ASSERT(!is_top_level_); // We cannot check unresolved types. | 13506 Error& malformed_error = Error::Handle(Z); |
13426 if (!const_instance.IsInstanceOf(type_bound, | 13507 ASSERT(!is_top_level_); // We cannot check unresolved types. |
13427 TypeArguments::Handle(Z), | 13508 if (!const_instance.IsInstanceOf(type_bound, |
13428 &malformed_error)) { | 13509 TypeArguments::Handle(Z), |
13429 type_bound = ClassFinalizer::NewFinalizedMalformedType( | 13510 &malformed_error)) { |
13430 malformed_error, | 13511 type_bound = ClassFinalizer::NewFinalizedMalformedType( |
13431 script_, | 13512 malformed_error, |
13432 new_pos, | 13513 script_, |
13433 "const factory result is not an instance of '%s'", | 13514 new_pos, |
13434 String::Handle(Z, type_bound.UserVisibleName()).ToCString()); | 13515 "const factory result is not an instance of '%s'", |
13435 new_object = ThrowTypeError(new_pos, type_bound); | 13516 String::Handle(Z, type_bound.UserVisibleName()).ToCString()); |
13436 } | 13517 new_object = ThrowTypeError(new_pos, type_bound); |
13437 type_bound = AbstractType::null(); | |
13438 } | 13518 } |
| 13519 type_bound = AbstractType::null(); |
13439 } | 13520 } |
13440 } else { | 13521 } else { |
13441 CheckConstructorCallTypeArguments(new_pos, constructor, type_arguments); | 13522 CheckConstructorCallTypeArguments(new_pos, constructor, type_arguments); |
13442 if (!type_arguments.IsNull() && | 13523 if (!type_arguments.IsNull() && |
13443 !type_arguments.IsInstantiated() && | 13524 !type_arguments.IsInstantiated() && |
13444 (current_block_->scope->function_level() > 0)) { | 13525 (current_block_->scope->function_level() > 0)) { |
13445 // Make sure that the instantiator is captured. | 13526 // Make sure that the instantiator is captured. |
13446 CaptureInstantiator(); | 13527 CaptureInstantiator(); |
13447 } | 13528 } |
13448 // If the type argument vector is not instantiated, we verify in checked | 13529 // If the type argument vector is not instantiated, we verify in checked |
(...skipping 738 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
14187 void Parser::SkipQualIdent() { | 14268 void Parser::SkipQualIdent() { |
14188 ASSERT(IsIdentifier()); | 14269 ASSERT(IsIdentifier()); |
14189 ConsumeToken(); | 14270 ConsumeToken(); |
14190 if (CurrentToken() == Token::kPERIOD) { | 14271 if (CurrentToken() == Token::kPERIOD) { |
14191 ConsumeToken(); // Consume the kPERIOD token. | 14272 ConsumeToken(); // Consume the kPERIOD token. |
14192 ExpectIdentifier("identifier expected after '.'"); | 14273 ExpectIdentifier("identifier expected after '.'"); |
14193 } | 14274 } |
14194 } | 14275 } |
14195 | 14276 |
14196 } // namespace dart | 14277 } // namespace dart |
OLD | NEW |