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

Side by Side Diff: runtime/vm/parser.cc

Issue 8637018: Implement type checking of map literals (issue 221). (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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, 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 "vm/bigint_operations.h" 7 #include "vm/bigint_operations.h"
8 #include "vm/class_finalizer.h" 8 #include "vm/class_finalizer.h"
9 #include "vm/compiler.h" 9 #include "vm/compiler.h"
10 #include "vm/compiler_stats.h" 10 #include "vm/compiler_stats.h"
11 #include "vm/dart_api_impl.h" 11 #include "vm/dart_api_impl.h"
12 #include "vm/dart_entry.h" 12 #include "vm/dart_entry.h"
13 #include "vm/flags.h" 13 #include "vm/flags.h"
14 #include "vm/growable_array.h" 14 #include "vm/growable_array.h"
15 #include "vm/longjump.h" 15 #include "vm/longjump.h"
16 #include "vm/native_entry.h" 16 #include "vm/native_entry.h"
17 #include "vm/object.h" 17 #include "vm/object.h"
18 #include "vm/object_store.h" 18 #include "vm/object_store.h"
19 #include "vm/resolver.h" 19 #include "vm/resolver.h"
20 #include "vm/scopes.h" 20 #include "vm/scopes.h"
21 21
22 namespace dart { 22 namespace dart {
23 23
24 DEFINE_FLAG(bool, enable_asserts, false, "Enable assert statements."); 24 DEFINE_FLAG(bool, enable_asserts, false, "Enable assert statements.");
25 DEFINE_FLAG(bool, enable_type_checks, false, "Enable type checks."); 25 DEFINE_FLAG(bool, enable_type_checks, false, "Enable type checks.");
26 DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations."); 26 DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations.");
27 DEFINE_FLAG(bool, warning_as_error, false, "Treat warnings as errors."); 27 DEFINE_FLAG(bool, warning_as_error, false, "Treat warnings as errors.");
28 DEFINE_FLAG(bool, silent_warnings, false, "Silence warnings."); 28 DEFINE_FLAG(bool, silent_warnings, false, "Silence warnings.");
29 DECLARE_FLAG(bool, expose_core_impl);
29 30
30 // All references to Dart names are listed here. 31 // All references to Dart names are listed here.
31 static const char* kAssertionErrorName = "AssertionError"; 32 static const char* kAssertionErrorName = "AssertionError";
32 static const char* kFallThroughErrorName = "FallThroughError"; 33 static const char* kFallThroughErrorName = "FallThroughError";
33 static const char* kThrowNewName = "_throwNew"; 34 static const char* kThrowNewName = "_throwNew";
34 static const char* kGrowableObjectArrayFromArrayName = 35 static const char* kGrowableObjectArrayFromArrayName =
35 "GrowableObjectArray._usingArray"; 36 "GrowableObjectArray._usingArray";
36 static const char* kGrowableObjectArrayName = "GrowableObjectArray"; 37 static const char* kGrowableObjectArrayName = "GrowableObjectArray";
37 static const char* kMutableMapName = "MutableMap"; 38 static const char* kLiteralMapFactoryName = "_LiteralMapFactory";
38 static const char* kMutableMapFromLiteralName = "fromLiteral"; 39 static const char* kLiteralMapFactoryFromLiteralName = "Map.fromLiteral";
39 static const char* kImmutableMapName = "ImmutableMap"; 40 static const char* kImmutableMapName = "ImmutableMap";
40 static const char* kImmutableMapConstructorName = "ImmutableMap."; 41 static const char* kImmutableMapConstructorName = "ImmutableMap.";
41 static const char* kStringClassName = "StringBase"; 42 static const char* kStringClassName = "StringBase";
42 static const char* kInterpolateName = "_interpolate"; 43 static const char* kInterpolateName = "_interpolate";
43 static const char* kThisName = "this"; 44 static const char* kThisName = "this";
44 static const char* kPhaseParameterName = ":phase"; 45 static const char* kPhaseParameterName = ":phase";
45 static const char* kGetIteratorName = "iterator"; 46 static const char* kGetIteratorName = "iterator";
46 47
47 #if defined(DEBUG) 48 #if defined(DEBUG)
48 49
(...skipping 4370 matching lines...) Expand 10 before | Expand all | Expand 10 after
4419 } 4420 }
4420 4421
4421 4422
4422 // Lookup class in the corelib implementation which contains various VM 4423 // Lookup class in the corelib implementation which contains various VM
4423 // helper methods and classes. 4424 // helper methods and classes.
4424 static RawClass* LookupImplClass(const String& class_name) { 4425 static RawClass* LookupImplClass(const String& class_name) {
4425 return Library::Handle(Library::CoreImplLibrary()).LookupClass(class_name); 4426 return Library::Handle(Library::CoreImplLibrary()).LookupClass(class_name);
4426 } 4427 }
4427 4428
4428 4429
4430 // Lookup class in the corelib which also contains various VM
4431 // helper methods and classes. Allow look up of private classes.
4432 static RawClass* LookupCoreClass(const String& class_name) {
4433 const Library& core_lib = Library::Handle(Library::CoreLibrary());
4434 String& name = String::Handle(class_name.raw());
4435 if ((class_name.CharAt(0) == Scanner::kPrivateIdentifierStart) &&
4436 !FLAG_expose_core_impl) {
4437 // Private identifiers are mangled on a per script basis.
4438 name = String::Concat(name, String::Handle(core_lib.private_key()));
4439 name = String::NewSymbol(name);
4440 }
4441 return core_lib.LookupClass(name);
4442 }
4443
4444
4429 RawClass* Parser::LookupClass(const String& class_name) { 4445 RawClass* Parser::LookupClass(const String& class_name) {
4430 return library_.LookupClass(class_name); 4446 return library_.LookupClass(class_name);
4431 } 4447 }
4432 4448
4433 4449
4434 // Calling VM-internal helpers, uses implementation core library. 4450 // Calling VM-internal helpers, uses implementation core library.
4435 AstNode* Parser::MakeStaticCall(const char* class_name, 4451 AstNode* Parser::MakeStaticCall(const char* class_name,
4436 const char* function_name, 4452 const char* function_name,
4437 ArgumentListNode* arguments) { 4453 ArgumentListNode* arguments) {
4438 const String& cls_name = 4454 const String& cls_name =
(...skipping 664 matching lines...) Expand 10 before | Expand all | Expand 10 after
5103 va_start(args, format); 5119 va_start(args, format);
5104 FormatMessage(script_, token_index_, "Error", 5120 FormatMessage(script_, token_index_, "Error",
5105 message_buffer, kMessageBufferSize, 5121 message_buffer, kMessageBufferSize,
5106 format, args); 5122 format, args);
5107 va_end(args); 5123 va_end(args);
5108 Isolate::Current()->long_jump_base()->Jump(1, message_buffer); 5124 Isolate::Current()->long_jump_base()->Jump(1, message_buffer);
5109 UNREACHABLE(); 5125 UNREACHABLE();
5110 } 5126 }
5111 5127
5112 5128
5129 void Parser::Warning(intptr_t token_index, const char* format, ...) {
5130 const intptr_t kMessageBufferSize = 512;
5131 char message_buffer[kMessageBufferSize];
5132 if (FLAG_silent_warnings) return;
5133 va_list args;
5134 va_start(args, format);
5135 FormatMessage(script_, token_index, "Warning",
5136 message_buffer, kMessageBufferSize,
5137 format, args);
5138 va_end(args);
5139 if (FLAG_warning_as_error) {
5140 Isolate::Current()->long_jump_base()->Jump(1, message_buffer);
5141 UNREACHABLE();
5142 } else {
5143 OS::Print(message_buffer);
5144 }
5145 }
5146
5147
5113 void Parser::Warning(const char* format, ...) { 5148 void Parser::Warning(const char* format, ...) {
5114 const intptr_t kMessageBufferSize = 512; 5149 const intptr_t kMessageBufferSize = 512;
5115 char message_buffer[kMessageBufferSize]; 5150 char message_buffer[kMessageBufferSize];
5116 if (FLAG_silent_warnings) return; 5151 if (FLAG_silent_warnings) return;
5117 va_list args; 5152 va_list args;
5118 va_start(args, format); 5153 va_start(args, format);
5119 FormatMessage(script_, token_index_, "Warning", 5154 FormatMessage(script_, token_index_, "Warning",
5120 message_buffer, kMessageBufferSize, 5155 message_buffer, kMessageBufferSize,
5121 format, args); 5156 format, args);
5122 va_end(args); 5157 va_end(args);
(...skipping 1530 matching lines...) Expand 10 before | Expand all | Expand 10 after
6653 } 6688 }
6654 pairs->AddElement(key); 6689 pairs->AddElement(key);
6655 pairs->AddElement(value); 6690 pairs->AddElement(value);
6656 } 6691 }
6657 6692
6658 6693
6659 AstNode* Parser::ParseMapLiteral(intptr_t type_pos, 6694 AstNode* Parser::ParseMapLiteral(intptr_t type_pos,
6660 bool is_const, 6695 bool is_const,
6661 const TypeArguments& type_arguments) { 6696 const TypeArguments& type_arguments) {
6662 TRACE_PARSER("ParseMapLiteral"); 6697 TRACE_PARSER("ParseMapLiteral");
6698 ASSERT(type_pos >= 0);
6663 ASSERT(CurrentToken() == Token::kLBRACE); 6699 ASSERT(CurrentToken() == Token::kLBRACE);
6664 const intptr_t literal_pos = token_index_; 6700 const intptr_t literal_pos = token_index_;
6665 ConsumeToken(); 6701 ConsumeToken();
6666 6702
6667 String& map_class_name = String::Handle( 6703 Type& value_type_argument = Type::Handle(Type::DynamicType());
6668 String::NewSymbol(is_const ? kImmutableMapName : kMutableMapName));
6669 const Class& map_class = Class::Handle(LookupImplClass(map_class_name));
6670 ASSERT(!map_class.IsNull());
6671
6672 TypeArguments& map_type_arguments = 6704 TypeArguments& map_type_arguments =
6673 TypeArguments::ZoneHandle(type_arguments.raw()); 6705 TypeArguments::ZoneHandle(type_arguments.raw());
6674 // If no type arguments are provided, leave them as null, which is equivalent 6706 // If no type argument is provided, leave it as null, which is equivalent
6675 // to using Map<Dynamic, Dynamic>. See issue 4966724. 6707 // to using Dynamic as the type argument for the value type.
6676 if (!map_type_arguments.IsNull()) { 6708 if (!map_type_arguments.IsNull()) {
6677 // For now, only check the number of type arguments. See issue 4975876. 6709 // Map literals only take one type argument.
6678 if (map_type_arguments.Length() != 2) { 6710 value_type_argument = map_type_arguments.TypeAt(0);
6679 ASSERT(type_pos >= 0); 6711 if (map_type_arguments.Length() > 1) {
6680 ErrorMsg(type_pos, "wrong number of type arguments for Map literal"); 6712 // We temporarily accept two type arguments, as long as the first one is
6713 // type String.
6714 if (map_type_arguments.Length() != 2) {
6715 ErrorMsg(type_pos,
6716 "a map literal takes one type argument specifying "
6717 "the value type");
6718 }
6719 if (!value_type_argument.IsStringInterface()) {
6720 ErrorMsg(type_pos,
6721 "the key type of a map literal is implicitly 'String'");
6722 }
6723 Warning(type_pos,
6724 "a map literal takes one type argument specifying "
6725 "the value type");
6726 value_type_argument = map_type_arguments.TypeAt(1);
6727 } else {
6728 TypeArray& type_array = TypeArray::Handle(TypeArray::New(2));
6729 type_array.SetTypeAt(0, Type::Handle(Type::StringInterface()));
6730 type_array.SetTypeAt(1, value_type_argument);
6731 map_type_arguments = type_array.raw();
6732 }
6733 if (is_const && !value_type_argument.IsInstantiated()) {
6734 ErrorMsg(type_pos,
6735 "the type argument of a constant map literal cannot include "
6736 "a type variable");
6681 } 6737 }
6682 } 6738 }
6739 ASSERT(map_type_arguments.IsNull() || (map_type_arguments.Length() == 2));
6683 6740
6684 // Parse the map entries. Note: there may be an optional extra 6741 // Parse the map entries. Note: there may be an optional extra
6685 // comma after the last entry. 6742 // comma after the last entry.
6686 ArrayNode* kv_pairs = 6743 ArrayNode* kv_pairs =
6687 new ArrayNode(token_index_, TypeArguments::ZoneHandle()); 6744 new ArrayNode(token_index_, TypeArguments::ZoneHandle());
6688 while (CurrentToken() != Token::kRBRACE) { 6745 while (CurrentToken() != Token::kRBRACE) {
6689 AstNode* key = NULL; 6746 AstNode* key = NULL;
6690 if (CurrentToken() == Token::kSTRING) { 6747 if (CurrentToken() == Token::kSTRING) {
6691 key = ParseStringLiteral(); 6748 key = ParseStringLiteral();
6692 } 6749 }
(...skipping 23 matching lines...) Expand all
6716 // the immutable map object with it. This all happens at compile time. 6773 // the immutable map object with it. This all happens at compile time.
6717 // The resulting immutable map object is returned as a literal. 6774 // The resulting immutable map object is returned as a literal.
6718 6775
6719 // First, create the canonicalized key-value pair array. 6776 // First, create the canonicalized key-value pair array.
6720 Array& key_value_array = 6777 Array& key_value_array =
6721 Array::ZoneHandle(Array::New(kv_pairs->length(), Heap::kOld)); 6778 Array::ZoneHandle(Array::New(kv_pairs->length(), Heap::kOld));
6722 for (int i = 0; i < kv_pairs->length(); i++) { 6779 for (int i = 0; i < kv_pairs->length(); i++) {
6723 AstNode* arg = kv_pairs->ElementAt(i); 6780 AstNode* arg = kv_pairs->ElementAt(i);
6724 // Arguments have been evaluated to a literal value already. 6781 // Arguments have been evaluated to a literal value already.
6725 ASSERT(arg->IsLiteralNode()); 6782 ASSERT(arg->IsLiteralNode());
6783 if (((i % 2) == 1) && // Check values only, not keys.
6784 !value_type_argument.IsDynamicType() &&
6785 !arg->AsLiteralNode()->literal().Is(value_type_argument)) {
6786 ErrorMsg(arg->AsLiteralNode()->token_index(),
6787 "map literal entry value must be a constant of type '%s'",
6788 String::Handle(value_type_argument.Name()).ToCString());
6789 }
6726 key_value_array.SetAt(i, arg->AsLiteralNode()->literal()); 6790 key_value_array.SetAt(i, arg->AsLiteralNode()->literal());
6727 } 6791 }
6728 key_value_array ^= key_value_array.Canonicalize(); 6792 key_value_array ^= key_value_array.Canonicalize();
6729 key_value_array.MakeImmutable(); 6793 key_value_array.MakeImmutable();
6730 6794
6731 // Construct the map object. 6795 // Construct the map object.
6796 const String& immutable_map_class_name =
6797 String::Handle(String::NewSymbol(kImmutableMapName));
6798 const Class& immutable_map_class =
6799 Class::Handle(LookupImplClass(immutable_map_class_name));
6800 ASSERT(!immutable_map_class.IsNull());
6732 ArgumentListNode* constr_args = new ArgumentListNode(token_index_); 6801 ArgumentListNode* constr_args = new ArgumentListNode(token_index_);
6733 constr_args->Add(new LiteralNode(literal_pos, key_value_array)); 6802 constr_args->Add(new LiteralNode(literal_pos, key_value_array));
6734 const String& constr_name = 6803 const String& constr_name =
6735 String::Handle(String::NewSymbol(kImmutableMapConstructorName)); 6804 String::Handle(String::NewSymbol(kImmutableMapConstructorName));
6736 const Function& map_constr = Function::ZoneHandle( 6805 const Function& map_constr = Function::ZoneHandle(
6737 map_class.LookupConstructor(constr_name)); 6806 immutable_map_class.LookupConstructor(constr_name));
6738 ASSERT(!map_constr.IsNull()); 6807 ASSERT(!map_constr.IsNull());
6739 const Instance& const_instance = Instance::ZoneHandle( 6808 const Instance& const_instance = Instance::ZoneHandle(
6740 EvaluateConstConstructorCall(map_class, 6809 EvaluateConstConstructorCall(immutable_map_class,
6741 map_type_arguments, 6810 map_type_arguments,
6742 map_constr, 6811 map_constr,
6743 constr_args)); 6812 constr_args));
6744 if (const_instance.IsUnhandledException()) { 6813 if (const_instance.IsUnhandledException()) {
6745 return CreateEvalConstConstructorThrow(literal_pos, const_instance); 6814 return CreateEvalConstConstructorThrow(literal_pos, const_instance);
6746 } else { 6815 } else {
6747 return new LiteralNode(literal_pos, const_instance); 6816 return new LiteralNode(literal_pos, const_instance);
6748 } 6817 }
6749 } else { 6818 } else {
6750 // Static call at runtime. 6819 // Factory call at runtime.
6751 const String& static_factory_name = 6820 String& literal_map_factory_class_name = String::Handle(
6752 String::Handle(String::NewSymbol(kMutableMapFromLiteralName)); 6821 String::NewSymbol(kLiteralMapFactoryName));
6753 const Function& static_factory = Function::ZoneHandle( 6822 const Class& literal_map_factory_class =
6754 map_class.LookupStaticFunction(static_factory_name)); 6823 Class::Handle(LookupCoreClass(literal_map_factory_class_name));
6755 ASSERT(!static_factory.IsNull()); 6824 ASSERT(!literal_map_factory_class.IsNull());
6825 const String& literal_map_factory_name =
6826 String::Handle(String::NewSymbol(kLiteralMapFactoryFromLiteralName));
6827 const Function& literal_map_factory = Function::ZoneHandle(
6828 literal_map_factory_class.LookupFactory(literal_map_factory_name));
6829 ASSERT(!literal_map_factory.IsNull());
6756 if (!map_type_arguments.IsNull() && 6830 if (!map_type_arguments.IsNull() &&
6757 !map_type_arguments.IsInstantiated() && 6831 !map_type_arguments.IsInstantiated() &&
6758 (current_block_->scope->function_level() > 0)) { 6832 (current_block_->scope->function_level() > 0)) {
6759 // Make sure that the instantiator is captured. 6833 // Make sure that the instantiator is captured.
6760 CaptureReceiver(); 6834 CaptureReceiver();
6761 } 6835 }
6762 ArgumentListNode* factory_param = new ArgumentListNode(literal_pos); 6836 ArgumentListNode* factory_param = new ArgumentListNode(literal_pos);
6837 factory_param->Add(
6838 new LiteralNode(literal_pos, Smi::ZoneHandle(Smi::New(literal_pos))));
6839 factory_param->Add(
6840 new LiteralNode(literal_pos,
6841 String::ZoneHandle(value_type_argument.Name())));
6763 factory_param->Add(kv_pairs); 6842 factory_param->Add(kv_pairs);
6764 return new StaticCallNode( 6843 return new ConstructorCallNode(
6765 literal_pos, static_factory, factory_param); 6844 literal_pos, map_type_arguments, literal_map_factory, factory_param);
6766 } 6845 }
6767 } 6846 }
6768 6847
6769 6848
6770 AstNode* Parser::ParseCompoundLiteral() { 6849 AstNode* Parser::ParseCompoundLiteral() {
6771 bool is_const = false; 6850 bool is_const = false;
6772 if (CurrentToken() == Token::kCONST) { 6851 if (CurrentToken() == Token::kCONST) {
6773 is_const = true; 6852 is_const = true;
6774 ConsumeToken(); 6853 ConsumeToken();
6775 } 6854 }
(...skipping 656 matching lines...) Expand 10 before | Expand all | Expand 10 after
7432 } 7511 }
7433 7512
7434 7513
7435 void Parser::SkipNestedExpr() { 7514 void Parser::SkipNestedExpr() {
7436 const bool saved_mode = SetAllowFunctionLiterals(true); 7515 const bool saved_mode = SetAllowFunctionLiterals(true);
7437 SkipExpr(); 7516 SkipExpr();
7438 SetAllowFunctionLiterals(saved_mode); 7517 SetAllowFunctionLiterals(saved_mode);
7439 } 7518 }
7440 7519
7441 } // namespace dart 7520 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698