mirror of
https://github.com/dart-lang/sdk
synced 2024-10-03 19:21:31 +00:00
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:
parent
72a83801c5
commit
9f230a34c6
|
@ -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++) {
|
||||||
|
|
|
@ -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',
|
||||||
],
|
],
|
||||||
|
|
55
runtime/lib/literal_factory.dart
Normal file
55
runtime/lib/literal_factory.dart
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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});
|
||||||
}
|
}
|
||||||
|
|
22
tests/language/src/ListLiteral1NegativeTest.dart
Normal file
22
tests/language/src/ListLiteral1NegativeTest.dart
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
22
tests/language/src/ListLiteral2NegativeTest.dart
Normal file
22
tests/language/src/ListLiteral2NegativeTest.dart
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
53
tests/language/src/ListLiteral4Test.dart
Normal file
53
tests/language/src/ListLiteral4Test.dart
Normal 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue