Implement type checking of list literals (issue 220).

Remove expose_core_impl flag.
Add tests.
Fix tests.
Cleanup type checking of map literals.
Review URL: http://codereview.chromium.org//8676001

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@1809 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
regis@google.com 2011-11-23 19:34:23 +00:00
parent 72a83801c5
commit 9f230a34c6
15 changed files with 268 additions and 142 deletions

View file

@ -47,7 +47,7 @@ class GrowableObjectArray<T> implements List<T> {
if (start < 0 || start > this.length) { if (start < 0 || start > this.length) {
throw new IndexOutOfRangeException(start); throw new IndexOutOfRangeException(start);
} }
if (this.length + length >= backingArray.length) { if (this.length + length > backingArray.length) {
grow(backingArray.length + length); grow(backingArray.length + length);
} }
Arrays.copy(backingArray, Arrays.copy(backingArray,
@ -72,8 +72,10 @@ class GrowableObjectArray<T> implements List<T> {
return list; return list;
} }
// The length of this growable array. It is always less than the // The length of this growable array. It is always less than or equal to the
// length of the backing array. // length of the backing array, which itself is always greater than 0, so that
// grow() does not have to check for a zero length backing array before
// doubling its size.
int _length; int _length;
GrowableObjectArray() GrowableObjectArray()
@ -87,14 +89,6 @@ class GrowableObjectArray<T> implements List<T> {
backingArray = new ObjectArray<T>(capacity); backingArray = new ObjectArray<T>(capacity);
} }
GrowableObjectArray._usingArray(List<T> array) {
backingArray = array;
_length = array.length;
if (_length == 0) {
grow(4);
}
}
factory GrowableObjectArray<T>.from(Collection<T> other) { factory GrowableObjectArray<T>.from(Collection<T> other) {
List<T> result = new GrowableObjectArray<T>(); List<T> result = new GrowableObjectArray<T>();
result.addAll(other); result.addAll(other);
@ -106,7 +100,7 @@ class GrowableObjectArray<T> implements List<T> {
} }
void set length(int new_length) { void set length(int new_length) {
if (new_length >= backingArray.length) { if (new_length > backingArray.length) {
grow(new_length); grow(new_length);
} else { } else {
for (int i = new_length; i < _length; i++) { for (int i = new_length; i < _length; i++) {

View file

@ -13,7 +13,7 @@
'error.cc', 'error.cc',
'error.dart', 'error.dart',
'error.h', 'error.h',
'literal_map_factory.dart', 'literal_factory.dart',
'object.cc', 'object.cc',
'object.dart', 'object.dart',
], ],

View file

@ -0,0 +1,55 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Factory class constructing mutable List and Map objects from parser generated
// list and map literals.
class _LiteralFactory {
// [elements] contains elements that are not yet type checked.
factory List<E>.fromLiteral(int location,
String element_type,
List elements) {
var len = elements.length;
var list = new GrowableObjectArray<E>.withCapacity(len);
for (int i = 0; i < len; i++) {
// In checked mode only, rethrow a potential type error with a more user
// friendly error message.
try {
list.backingArray[i] = elements[i];
} catch (TypeError error) {
TypeError._throwNew(location,
elements[i],
element_type,
"list literal element at index ${i}");
}
}
list.length = len;
return list;
}
// [elements] contains n key-value pairs.
// The keys are at position 2*n and are already type checked by the parser
// in checked mode.
// The values are at position 2*n+1 and are not yet type checked.
factory Map<K, V>.fromLiteral(int location,
String value_type,
List elements) {
var map = new LinkedHashMap<String, V>();
var len = elements.length;
for (int i = 1; i < len; i += 2) {
// The type of the key has been checked in the parser already.
// In checked mode only, rethrow a potential type error with a more user
// friendly error message.
try {
map[elements[i - 1]] = elements[i];
} catch (TypeError error) {
TypeError._throwNew(location,
elements[i],
value_type,
"map literal value at index ${i ~/ 2}");
}
}
return map;
}
}

View file

@ -1,26 +0,0 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Immutable map class for compiler generated map literals.
class _LiteralMapFactory {
// [elements] contains n key-value pairs. The keys are at position
// 2*n, the values at position 2*n+1.
factory Map<K, V>.fromLiteral(int location,
String value_type,
List elements) {
var map = new LinkedHashMap<String, V>();
var len = elements.length;
for (int i = 1; i < len; i += 2) {
// The type of the key has been checked in the parser already.
if (elements[i] is !V) {
TypeError._throwNew(location,
elements[i],
value_type,
"map literal value at index ${i ~/ 2}");
}
map[elements[i-1]] = elements[i];
}
return map;
}
}

View file

@ -28,8 +28,6 @@
namespace dart { namespace dart {
DEFINE_FLAG(bool, expose_core_impl, false,
"Enables access to core implementation library (only for testing).");
DEFINE_FLAG(bool, generate_gdb_symbols, false, DEFINE_FLAG(bool, generate_gdb_symbols, false,
"Generate symbols of generated dart functions for debugging with GDB"); "Generate symbols of generated dart functions for debugging with GDB");
@ -4170,10 +4168,6 @@ RawLibrary* Library::NewLibraryHelper(const String& url,
Library& core_lib = Library::Handle(Library::CoreLibrary()); Library& core_lib = Library::Handle(Library::CoreLibrary());
ASSERT(!core_lib.IsNull()); ASSERT(!core_lib.IsNull());
result.AddImport(core_lib); result.AddImport(core_lib);
if (FLAG_expose_core_impl) {
// Make implementation corelib visible to Dart code.
result.AddImport(Library::Handle(Library::CoreImplLibrary()));
}
} }
return result.raw(); return result.raw();
} }

View file

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

View file

@ -162,7 +162,7 @@ class Parser : ValueObject {
void SkipNewOperator(); void SkipNewOperator();
void SkipActualParameters(); void SkipActualParameters();
void SkipMapLiteral(); void SkipMapLiteral();
void SkipArrayLiteral(); void SkipListLiteral();
void SkipFunctionLiteral(); void SkipFunctionLiteral();
void SkipStringLiteral(); void SkipStringLiteral();
@ -342,9 +342,9 @@ class Parser : ValueObject {
AstNode* ParsePrimary(); AstNode* ParsePrimary();
AstNode* ParseStringLiteral(); AstNode* ParseStringLiteral();
AstNode* ParseCompoundLiteral(); AstNode* ParseCompoundLiteral();
AstNode* ParseArrayLiteral(intptr_t type_pos, AstNode* ParseListLiteral(intptr_t type_pos,
bool is_const, bool is_const,
const TypeArguments& type_arguments); const TypeArguments& type_arguments);
AstNode* ParseMapLiteral(intptr_t type_pos, AstNode* ParseMapLiteral(intptr_t type_pos,
bool is_const, bool is_const,
const TypeArguments& type_arguments); const TypeArguments& type_arguments);

View file

@ -13,7 +13,6 @@
namespace dart { namespace dart {
DEFINE_FLAG(bool, print_tokens, false, "Print scanned tokens."); DEFINE_FLAG(bool, print_tokens, false, "Print scanned tokens.");
DECLARE_FLAG(bool, expose_core_impl);
void Scanner::InitKeywordTable() { void Scanner::InitKeywordTable() {
for (int i = 0; i < Token::numKeywords; i++) { for (int i = 0; i < Token::numKeywords; i++) {
@ -252,7 +251,7 @@ void Scanner::ScanIdentChars(bool allow_dollar) {
current_token_.kind = Token::kIDENT; current_token_.kind = Token::kIDENT;
String& literal = String& literal =
String::ZoneHandle(String::NewSymbol(source_, ident_pos, ident_length)); String::ZoneHandle(String::NewSymbol(source_, ident_pos, ident_length));
if ((ident_char0 == kPrivateIdentifierStart) && !FLAG_expose_core_impl) { if (ident_char0 == kPrivateIdentifierStart) {
// Private identifiers are mangled on a per script basis. // Private identifiers are mangled on a per script basis.
literal = String::Concat(literal, private_key_); literal = String::Concat(literal, private_key_);
literal = String::NewSymbol(literal); literal = String::NewSymbol(literal);

View file

@ -301,7 +301,6 @@ LangSpecTest/13_Types/13_8_Parameterized_Types/A02/t01: Fail # Issue 441
# Started failing after changing how @dynamic-type-error is handled. # Started failing after changing how @dynamic-type-error is handled.
[ $component == vm && $checked ] [ $component == vm && $checked ]
LangSpecTest/13_Types/13_2_Dynamic_Type_System/A01/t01: Fail # Issue 220
LibTest/core/List/every/List/every/A01/t04: Fail # Issue co19 - 46 LibTest/core/List/every/List/every/A01/t04: Fail # Issue co19 - 46
LibTest/core/List/filter/List/filter/A01/t04: Fail # Issue co19 - 46 LibTest/core/List/filter/List/filter/A01/t04: Fail # Issue co19 - 46
LibTest/core/List/forEach/List/forEach/A01/t05: Fail # Issue co19 - 46 LibTest/core/List/forEach/List/forEach/A01/t05: Fail # Issue co19 - 46

View file

@ -2,8 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a // for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file. // BSD-style license that can be found in the LICENSE file.
// Dart test program for testing class 'StringBase' (currently VM specific). // Dart test program for testing class 'StringBase' (currently VM specific).
// We use that flag to disable privacy.
// VMOptions=--expose_core_impl
#library("StringBaseTest.dart"); #library("StringBaseTest.dart");
#import("dart:coreimpl"); #import("dart:coreimpl");
@ -25,18 +23,14 @@ class StringBaseTest {
} }
static testInterpolation() { static testInterpolation() {
Expect.equals("", StringBase._interpolate([]));
Expect.equals("Hello World",
StringBase._interpolate(["Hello", " ", "World"]));
Expect.equals("Hello StringBase Tester!",
StringBase._interpolate(["Hello ", new StringBaseTest(), "!"]));
var answer = 40 + 2; var answer = 40 + 2;
var s = "The answer is $answer."; var s = "The answer is $answer.";
Expect.equals("The answer is 42.", s); Expect.equals("The answer is 42.", s);
int numBottles = 99; int numBottles = 33;
String wall = "wall"; String wall = "wall";
s = "${numBottles*3} bottles of beer on the $wall.";
Expect.equals("99 bottles of beer on the wall.", s);
} }
static testCreation() { static testCreation() {

View file

@ -118,7 +118,10 @@ ImplicitThisTest/none: Fail # Issue 375
InterfaceFactory3NegativeTest: Fail # Bug 5387405 InterfaceFactory3NegativeTest: Fail # Bug 5387405
IsObjectTest: Skip # Hasn't be tested on DartC yet IsObjectTest: Skip # Hasn't be tested on DartC yet
Library4NegativeTest: Fail # Bug 5406175 Library4NegativeTest: Fail # Bug 5406175
ListLiteral3Test: Fail # Bug 4510015. ListLiteral1NegativeTest: Skip # Issue 220
ListLiteral2NegativeTest: Fail # Issue 220
ListLiteral3Test: Fail # Issue 220
ListLiteral4Test: Fail # Issue 220
ListTest: Fail # Bug 5146975. ListTest: Fail # Bug 5146975.
LocalFunction3Test: Fail # Bug 4202974. LocalFunction3Test: Fail # Bug 4202974.
LocalFunctionTest: Fail # Bug in test. Bug 4202989 (shadowing). LocalFunctionTest: Fail # Bug in test. Bug 4202989 (shadowing).
@ -205,7 +208,6 @@ FactoryImplementationTest: Fail # Issue 523
BitOperationsTest: Fail # relies on big integers not available in JS BitOperationsTest: Fail # relies on big integers not available in JS
CallThroughGetterTest: Fail CallThroughGetterTest: Fail
CanonicalConstTest: Fail # type in const array allocation is erased
CharEscapeTest: Fail CharEscapeTest: Fail
ClassOverrideNegativeTest: Fail ClassOverrideNegativeTest: Fail
ClosureSharedStateTest: Fail ClosureSharedStateTest: Fail
@ -257,7 +259,10 @@ Library1NegativeTest: Fail # issue with test see #354
Library4NegativeTest: Fail # issue with test see #354 Library4NegativeTest: Fail # issue with test see #354
Library5NegativeTest: Fail # issue with test see #354 Library5NegativeTest: Fail # issue with test see #354
Library6NegativeTest: Fail # issue with test see #354 Library6NegativeTest: Fail # issue with test see #354
ListLiteral3Test: Fail ListLiteral1NegativeTest: Fail # Issue 220
ListLiteral2NegativeTest: Fail # Issue 220
ListLiteral3Test: Fail # Issue 220
ListLiteral4Test: Fail # Issue 220
ListTest: Fail # array bound checks not implemented ListTest: Fail # array bound checks not implemented
LocalFunction3Test: Fail LocalFunction3Test: Fail
LocalFunctionTest: Fail LocalFunctionTest: Fail

View file

@ -25,7 +25,7 @@ class CanonicalConstTest {
Expect.isTrue(const [2,1] !== const[1,2]); Expect.isTrue(const [2,1] !== const[1,2]);
Expect.isTrue(const <int>[1,2] === const <int>[1,2]); Expect.isTrue(const <int>[1,2] === const <int>[1,2]);
Expect.isTrue(const <Object>[1,2] === const <Object>[1,2]); Expect.isTrue(const <Object>[1,2] === const <Object>[1,2]);
Expect.isTrue(const <int>[1,2] !== const <double>[1,2]); Expect.isTrue(const <int>[1,2] !== const <double>[1.0,2.0]);
Expect.isTrue(const {"a":1, "b":2} === const {"a":1, "b":2}); Expect.isTrue(const {"a":1, "b":2} === const {"a":1, "b":2});
Expect.isTrue(const {"a":1, "b":2} !== const {"a":2, "b":2}); Expect.isTrue(const {"a":1, "b":2} !== const {"a":2, "b":2});
} }

View file

@ -0,0 +1,22 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// VMOptions=--enable_type_checks
//
// Dart test program testing type checks in list literals.
class ListLiteral1NegativeTest {
test() {
try {
var m = const <String>[0, 1]; // 0 is not a String.
} catch (TypeError error) {
}
}
}
main() {
var t = new ListLiteral1NegativeTest();
t.test();
}

View file

@ -0,0 +1,22 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// VMOptions=--enable_type_checks
//
// Dart test program const map literals.
class ListLiteral2NegativeTest<T> {
test() {
try {
var m = const <T>[0, 1]; // Type parameter is not allowed with const.
} catch (TypeError error) {
}
}
}
main() {
var t = new ListLiteral2NegativeTest<int>();
t.test();
}

View file

@ -0,0 +1,53 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// VMOptions=--enable_type_checks
//
// Dart test program testing type checks in list literals.
class ListLiteral4Test<T> {
test() {
int result = 0;
try {
var m = <String>[0, 1]; // 0 is not a String.
} catch (TypeError error) {
result += 1;
}
try {
var m = <int>[0, 1];
m["0"] = 1; // "0" is not an int.
} catch (TypeError error) {
result += 10;
}
try {
var m = <T>{"a": "b"}; // "b" is not an int.
} catch (TypeError error) {
result += 100;
}
try {
var m = <T>[0, 1]; // OK.
} catch (TypeError error) {
result += 1000;
}
try {
var m = <T>[0, 1];
m["0"] = 1; // "0" is not an int.
} catch (TypeError error) {
result += 10000;
}
try {
var m = const <int>[0, 1];
m["0"] = 1; // "0" is not an int.
} catch (TypeError error) {
result += 100000;
}
return result;
}
}
main() {
var t = new ListLiteral4Test<int>();
Expect.equals(110111, t.test());
}