mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 11:03:19 +00:00
fix list_test for strong mode, and fix DDC List constructors
R=vsm@google.com Review-Url: https://codereview.chromium.org/3009623002 .
This commit is contained in:
parent
343452d43f
commit
087c5c6a81
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -151,6 +151,7 @@ class CodeGenerator extends Object
|
|||
final ClassElement stringClass;
|
||||
final ClassElement functionClass;
|
||||
final ClassElement privateSymbolClass;
|
||||
final PropertyAccessorElement _undefinedConstant;
|
||||
|
||||
ConstFieldVisitor _constants;
|
||||
|
||||
|
@ -225,7 +226,10 @@ class CodeGenerator extends Object
|
|||
functionClass = _getLibrary(c, 'dart:core').getType('Function'),
|
||||
privateSymbolClass =
|
||||
_getLibrary(c, 'dart:_internal').getType('PrivateSymbol'),
|
||||
dartJSLibrary = _getLibrary(c, 'dart:js') {
|
||||
dartJSLibrary = _getLibrary(c, 'dart:js'),
|
||||
_undefinedConstant =
|
||||
_getLibrary(c, 'dart:_runtime').publicNamespace.get('undefined') {
|
||||
assert(_undefinedConstant != null);
|
||||
typeRep = new JSTypeRep(rules, types);
|
||||
}
|
||||
|
||||
|
@ -595,7 +599,8 @@ class CodeGenerator extends Object
|
|||
for (var declaration in unit.declarations) {
|
||||
if (declaration is TopLevelVariableDeclaration) {
|
||||
inferNullableTypes(declaration);
|
||||
if (isInternalSdk && declaration.variables.isFinal) {
|
||||
if (isInternalSdk &&
|
||||
(declaration.variables.isFinal || declaration.variables.isConst)) {
|
||||
_emitInternalSdkFields(declaration.variables.variables);
|
||||
} else {
|
||||
(fields ??= []).addAll(declaration.variables.variables);
|
||||
|
@ -2439,25 +2444,38 @@ class CodeGenerator extends Object
|
|||
for (var param in parameters.parameters) {
|
||||
var jsParam = _emitSimpleIdentifier(param.identifier);
|
||||
|
||||
if (!options.destructureNamedParams) {
|
||||
if (!options.destructureNamedParams &&
|
||||
param.kind != ParameterKind.REQUIRED) {
|
||||
if (param.kind == ParameterKind.NAMED) {
|
||||
// Parameters will be passed using their real names, not the (possibly
|
||||
// renamed) local variable.
|
||||
var paramName = js.string(param.identifier.name, "'");
|
||||
|
||||
// TODO(ochafik): Fix `'prop' in obj` to please Closure's renaming.
|
||||
body.add(js.statement('let # = # && # in # ? #.# : #;', [
|
||||
jsParam,
|
||||
namedArgumentTemp,
|
||||
paramName,
|
||||
namedArgumentTemp,
|
||||
namedArgumentTemp,
|
||||
paramName,
|
||||
_defaultParamValue(param),
|
||||
]));
|
||||
var defaultValue = _defaultParamValue(param);
|
||||
if (defaultValue != null) {
|
||||
// TODO(ochafik): Fix `'prop' in obj` to please Closure's renaming.
|
||||
body.add(js.statement('let # = # && # in # ? #.# : #;', [
|
||||
jsParam,
|
||||
namedArgumentTemp,
|
||||
paramName,
|
||||
namedArgumentTemp,
|
||||
namedArgumentTemp,
|
||||
paramName,
|
||||
defaultValue,
|
||||
]));
|
||||
} else {
|
||||
body.add(js.statement('let # = # && #.#;', [
|
||||
jsParam,
|
||||
namedArgumentTemp,
|
||||
namedArgumentTemp,
|
||||
paramName,
|
||||
]));
|
||||
}
|
||||
} else if (param.kind == ParameterKind.POSITIONAL) {
|
||||
body.add(js.statement('if (# === void 0) # = #;',
|
||||
[jsParam, jsParam, _defaultParamValue(param)]));
|
||||
var defaultValue = _defaultParamValue(param);
|
||||
if (defaultValue != null) {
|
||||
body.add(js.statement(
|
||||
'if (# === void 0) # = #;', [jsParam, jsParam, defaultValue]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2481,12 +2499,18 @@ class CodeGenerator extends Object
|
|||
|
||||
JS.Expression _defaultParamValue(FormalParameter param) {
|
||||
if (param is DefaultFormalParameter && param.defaultValue != null) {
|
||||
return _visit(param.defaultValue);
|
||||
var defaultValue = param.defaultValue;
|
||||
return _isJSUndefined(defaultValue) ? null : _visit(defaultValue);
|
||||
} else {
|
||||
return new JS.LiteralNull();
|
||||
}
|
||||
}
|
||||
|
||||
bool _isJSUndefined(Expression expr) {
|
||||
expr = expr is AsExpression ? expr.expression : expr;
|
||||
return expr is Identifier && expr.staticElement == _undefinedConstant;
|
||||
}
|
||||
|
||||
JS.Fun _emitNativeFunctionBody(MethodDeclaration node) {
|
||||
String name =
|
||||
getAnnotationName(node.element, isJSAnnotation) ?? node.name.name;
|
||||
|
@ -3947,18 +3971,19 @@ class CodeGenerator extends Object
|
|||
} else {
|
||||
name = _visit(param.identifier);
|
||||
}
|
||||
|
||||
var defaultValue = _defaultParamValue(param);
|
||||
namedVars.add(new JS.DestructuredVariable(
|
||||
name: name,
|
||||
structure: structure,
|
||||
defaultValue: _defaultParamValue(param)));
|
||||
name: name, structure: structure, defaultValue: defaultValue));
|
||||
} else {
|
||||
needsOpts = true;
|
||||
}
|
||||
} else {
|
||||
var jsParam = _visit(param);
|
||||
result.add(param is DefaultFormalParameter && destructure
|
||||
var defaultValue = _defaultParamValue(param);
|
||||
result.add(destructure && defaultValue != null
|
||||
? new JS.DestructuredVariable(
|
||||
name: jsParam, defaultValue: _defaultParamValue(param))
|
||||
name: jsParam, defaultValue: defaultValue)
|
||||
: jsParam);
|
||||
}
|
||||
}
|
||||
|
@ -4066,7 +4091,7 @@ class CodeGenerator extends Object
|
|||
}
|
||||
|
||||
/// This is not used--we emit top-level fields as we are emitting the
|
||||
/// compilation unit, see [_emitCompilationUnit].
|
||||
/// compilation unit, see [visitCompilationUnit].
|
||||
@override
|
||||
visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
|
||||
assert(false);
|
||||
|
@ -4127,6 +4152,9 @@ class CodeGenerator extends Object
|
|||
// TODO(jmesserly): it'd be nice to avoid this special case.
|
||||
void _emitInternalSdkFields(List<VariableDeclaration> fields) {
|
||||
for (var field in fields) {
|
||||
// Skip our magic undefined constant.
|
||||
var element = field.element as TopLevelVariableElement;
|
||||
if (element.getter == _undefinedConstant) continue;
|
||||
_moduleItems.add(annotate(
|
||||
js.statement('# = #;',
|
||||
[_emitTopLevelName(field.element), _visitInitializer(field)]),
|
||||
|
|
|
@ -20,8 +20,14 @@ pushd $LIBROOT > /dev/null
|
|||
# script, so you could debug the output without recompiling?
|
||||
echo "
|
||||
let sdk = require(\"dart_sdk\");
|
||||
let main = require(\"$BASENAME\").$BASENAME.main;
|
||||
sdk._isolate_helper.startRootIsolate(main, []);" \
|
||||
let main = require(\"./$BASENAME\").$BASENAME.main;
|
||||
sdk.dart.ignoreWhitelistedErrors(false);
|
||||
try {
|
||||
sdk._isolate_helper.startRootIsolate(main, []);
|
||||
} catch(e) {
|
||||
console.error(e.toString(), sdk.dart.stackTrace(e).toString());
|
||||
process.exit(1);
|
||||
}" \
|
||||
> $LIBROOT/$BASENAME.run.js
|
||||
node $BASENAME.run.js
|
||||
node $BASENAME.run.js || exit 1
|
||||
popd > /dev/null
|
||||
|
|
|
@ -21,6 +21,8 @@ import 'dart:_js_helper'
|
|||
Primitives,
|
||||
stringJoinUnchecked;
|
||||
|
||||
import 'dart:_runtime' show undefined;
|
||||
|
||||
import 'dart:_foreign_helper' show JS;
|
||||
|
||||
import 'dart:_native_typed_data' show NativeUint8List;
|
||||
|
@ -318,39 +320,39 @@ class Stopwatch {
|
|||
@patch
|
||||
class List<E> {
|
||||
@patch
|
||||
factory List([int _length]) {
|
||||
factory List([int _length = undefined]) {
|
||||
dynamic list;
|
||||
if (_length == null) {
|
||||
if (JS('bool', '# === void 0', _length)) {
|
||||
list = JS('', '[]');
|
||||
} else {
|
||||
@notNull
|
||||
var length = _length;
|
||||
if (length < 0) {
|
||||
var length = JS('int', '#', _length);
|
||||
if (_length == null || length < 0) {
|
||||
throw new ArgumentError(
|
||||
"Length must be a non-negative integer: $length");
|
||||
"Length must be a non-negative integer: $_length");
|
||||
}
|
||||
list = JSArray.markFixedList(JS('', 'new Array(#)', length));
|
||||
list = JS('', 'new Array(#)', length);
|
||||
JSArray.markFixedList(list);
|
||||
}
|
||||
return new JSArray<E>.of(list);
|
||||
}
|
||||
|
||||
@patch
|
||||
factory List.filled(int length, E fill, {bool growable: true}) {
|
||||
List<E> result = new List<E>(length);
|
||||
factory List.filled(@nullCheck int length, E fill, {bool growable: false}) {
|
||||
var list = new JSArray<E>.of(JS('', 'new Array(#)', length));
|
||||
if (length != 0 && fill != null) {
|
||||
@notNull
|
||||
var length = result.length;
|
||||
var length = list.length;
|
||||
for (int i = 0; i < length; i++) {
|
||||
result[i] = fill;
|
||||
list[i] = fill;
|
||||
}
|
||||
}
|
||||
if (growable) return result;
|
||||
return makeListFixedLength<E>(result);
|
||||
if (!growable) JSArray.markFixedList(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
@patch
|
||||
factory List.from(Iterable elements, {bool growable: true}) {
|
||||
List<E> list = new List<E>();
|
||||
var list = new JSArray<E>.of(JS('', '[]'));
|
||||
// Specialize the copy loop for the case that doesn't need a
|
||||
// runtime check.
|
||||
if (elements is Iterable<E>) {
|
||||
|
@ -362,14 +364,15 @@ class List<E> {
|
|||
list.add(e as E);
|
||||
}
|
||||
}
|
||||
if (growable) return list;
|
||||
return makeListFixedLength/*<E>*/(list);
|
||||
if (!growable) JSArray.markFixedList(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
@patch
|
||||
factory List.unmodifiable(Iterable elements) {
|
||||
var result = new List<E>.from(elements, growable: false);
|
||||
return makeFixedListUnmodifiable/*<E>*/(result);
|
||||
var list = new List<E>.from(elements);
|
||||
JSArray.markUnmodifiableList(list);
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -531,12 +531,6 @@ defineExtensionMembers(type, methodNames) => JS('', '''(() => {
|
|||
upgradeSig($_setterSig);
|
||||
})()''');
|
||||
|
||||
/// Sets the type of `obj` to be `type`
|
||||
setType(obj, type) {
|
||||
JS('', '#.__proto__ = #.prototype', obj, type);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// Link the extension to the type it's extending as a base class.
|
||||
setBaseClass(derived, base) {
|
||||
JS('', '#.prototype.__proto__ = #.prototype', derived, base);
|
||||
|
|
|
@ -790,9 +790,9 @@ constList(elements, elementType) => JS('', '''(() => {
|
|||
let value = map.get($elementType);
|
||||
if (value) return value;
|
||||
|
||||
value = $setType($elements, ${getGenericClass(JSArray)}($elementType));
|
||||
map.set($elementType, value);
|
||||
return value;
|
||||
${getGenericClass(JSArray)}($elementType).unmodifiable($elements);
|
||||
map.set($elementType, elements);
|
||||
return elements;
|
||||
})()''');
|
||||
|
||||
// The following are helpers for Object methods when the receiver
|
||||
|
|
|
@ -7,6 +7,11 @@ part of dart._runtime;
|
|||
/// by the Dart runtime.
|
||||
// TODO(ochafik): Rewrite some of these in Dart when possible.
|
||||
|
||||
/// The JavaScript undefined constant.
|
||||
///
|
||||
/// This is initialized by DDC to JS void 0.
|
||||
const undefined = null;
|
||||
|
||||
defineProperty(obj, name, desc) =>
|
||||
JS('', 'Object.defineProperty(#, #, #)', obj, name, desc);
|
||||
|
||||
|
|
|
@ -104,11 +104,23 @@ class NullError extends Interceptor implements NoSuchMethodError {
|
|||
// TODO(vsm): Distinguish between null reference errors and other
|
||||
// TypeErrors. We should not get non-null TypeErrors from DDC code,
|
||||
// but we may from native JavaScript.
|
||||
var message = JS('String', '#.message', this);
|
||||
return "NullError: $message";
|
||||
return "NullError: ${JS('String', '#.message', this)}";
|
||||
}
|
||||
}
|
||||
|
||||
// Note that this needs to be in interceptors.dart in order for
|
||||
// it to be picked up as an extension type.
|
||||
@JsPeerInterface(name: 'RangeError')
|
||||
class JSRangeError extends Interceptor implements ArgumentError {
|
||||
StackTrace get stackTrace => Primitives.extractStackTrace(this);
|
||||
|
||||
get invalidValue => null;
|
||||
get name => null;
|
||||
get message => JS('String', '#.message', this);
|
||||
|
||||
String toString() => "Invalid argument: $message";
|
||||
}
|
||||
|
||||
// Obsolete in dart dev compiler. Added only so that the same version of
|
||||
// dart:html can be used in dart2js an dev compiler.
|
||||
// Warning: calls to these methods need to be removed before custom elements
|
||||
|
|
|
@ -263,7 +263,7 @@ class _Deserializer {
|
|||
assert(x[0] == 'fixed');
|
||||
List result = x[1];
|
||||
deserializedObjects.add(result);
|
||||
return new JSArray.markFixed(deserializeArrayInPlace(result));
|
||||
return new JSArray.fixed(deserializeArrayInPlace(result));
|
||||
}
|
||||
|
||||
// ['extendable', <array>].
|
||||
|
@ -271,7 +271,7 @@ class _Deserializer {
|
|||
assert(x[0] == 'extendable');
|
||||
List result = x[1];
|
||||
deserializedObjects.add(result);
|
||||
return new JSArray.markGrowable(deserializeArrayInPlace(result));
|
||||
return new JSArray.of(deserializeArrayInPlace(result));
|
||||
}
|
||||
|
||||
// ['mutable', <array>].
|
||||
|
@ -288,7 +288,7 @@ class _Deserializer {
|
|||
List result = x[1];
|
||||
deserializedObjects.add(result);
|
||||
// TODO(floitsch): need to mark list as non-changeable.
|
||||
return new JSArray.markFixed(deserializeArrayInPlace(result));
|
||||
return new JSArray.unmodifiable(deserializeArrayInPlace(result));
|
||||
}
|
||||
|
||||
// ['map', <key-list>, <value-list>].
|
||||
|
|
|
@ -18,33 +18,40 @@ class JSArray<E> implements List<E>, JSIndexable<E> {
|
|||
* Constructor for adding type parameters to an existing JavaScript
|
||||
* Array. Used for creating literal lists.
|
||||
*/
|
||||
factory JSArray.of(allocation) {
|
||||
factory JSArray.of(list) {
|
||||
// TODO(sra): Move this to core.List for better readability.
|
||||
// Capture the parameterized ES6 'JSArray' class.
|
||||
return JS('-dynamic', '#', dart.setType(allocation, JS('', 'JSArray')));
|
||||
JS('', '#.__proto__ = JSArray.prototype', list);
|
||||
return JS('-dynamic', '#', list);
|
||||
}
|
||||
|
||||
// TODO(jmesserly): consider a fixed array subclass instead.
|
||||
factory JSArray.markFixed(allocation) =>
|
||||
new JSArray<E>.of(markFixedList(allocation));
|
||||
|
||||
factory JSArray.markGrowable(allocation) = JSArray<E>.of;
|
||||
|
||||
static List markFixedList(List list) {
|
||||
// Functions are stored in the hidden class and not as properties in
|
||||
// the object. We never actually look at the value, but only want
|
||||
// to know if the property exists.
|
||||
JS('void', r'#.fixed$length = Array', list);
|
||||
return JS('JSFixedArray', '#', list);
|
||||
factory JSArray.fixed(list) {
|
||||
JS('', '#.__proto__ = JSArray.prototype', list);
|
||||
JS('', r'#.fixed$length = Array', list);
|
||||
return JS('-dynamic', '#', list);
|
||||
}
|
||||
|
||||
static List markUnmodifiableList(List list) {
|
||||
factory JSArray.unmodifiable(list) {
|
||||
JS('', '#.__proto__ = JSArray.prototype', list);
|
||||
JS('', r'#.fixed$length = Array', list);
|
||||
JS('', r'#.immutable$list = Array', list);
|
||||
return JS('-dynamic', '#', list);
|
||||
}
|
||||
|
||||
static void markFixedList(list) {
|
||||
// Functions are stored in the hidden class and not as properties in
|
||||
// the object. We never actually look at the value, but only want
|
||||
// to know if the property exists.
|
||||
JS('void', r'#.fixed$length = Array', list);
|
||||
JS('void', r'#.immutable$list = Array', list);
|
||||
return JS('JSUnmodifiableArray', '#', list);
|
||||
JS('', r'#.fixed$length = Array', list);
|
||||
}
|
||||
|
||||
static void markUnmodifiableList(list) {
|
||||
// Functions are stored in the hidden class and not as properties in
|
||||
// the object. We never actually look at the value, but only want
|
||||
// to know if the property exists.
|
||||
JS('', r'#.fixed$length = Array', list);
|
||||
JS('', r'#.immutable$list = Array', list);
|
||||
}
|
||||
|
||||
checkMutable(reason) {
|
||||
|
|
|
@ -14,7 +14,7 @@ void expectUOE(f()) {
|
|||
Expect.throws(f, (e) => e is UnsupportedError);
|
||||
}
|
||||
|
||||
testImmutable(var list) {
|
||||
testImmutable(List list) {
|
||||
expectUOE(() {
|
||||
list.setRange(0, 0, const []);
|
||||
});
|
||||
|
|
|
@ -87,17 +87,12 @@ apply2_test: RuntimeError # Issue 29921
|
|||
apply3_test: RuntimeError # Issue 29921
|
||||
big_integer_arith_vm_test: RuntimeError # Issue 30170
|
||||
big_integer_parsed_arith_vm_test: RuntimeError # Issue 29921
|
||||
const_list_literal_test: RuntimeError # Issue 29921
|
||||
const_list_remove_range_test: RuntimeError # Issue 29921
|
||||
const_list_set_range_test: RuntimeError # Issue 29921
|
||||
compare_to2_test: RuntimeError # Issue 30170
|
||||
date_time10_test: RuntimeError # Issue 29921
|
||||
growable_list_test: RuntimeError # Issue 29921
|
||||
hash_set_test/01: RuntimeError # Issue 29921
|
||||
iterable_reduce_test/none: RuntimeError
|
||||
iterable_to_list_test/*: RuntimeError
|
||||
list_test/none: RuntimeError
|
||||
list_test/01: RuntimeError
|
||||
list_concurrent_modify_test: RuntimeError # DDC uses ES6 array iterators so it does not issue this
|
||||
nan_infinity_test/01: RuntimeError # Issue 29921
|
||||
null_nosuchmethod_test: RuntimeError # Issue 29921
|
||||
main_test: RuntimeError # Issue 29921
|
||||
|
@ -181,7 +176,9 @@ integer_to_string_test/01: RuntimeError
|
|||
iterable_to_set_test: RuntimeError # is-checks do not implement strong mode type system
|
||||
int_parse_radix_test/01: RuntimeError
|
||||
int_parse_radix_test/02: RuntimeError
|
||||
list_test/*: RuntimeError # dart2js doesn't implement strong mode covariance checks
|
||||
string_split_test: RuntimeError # does not return List<String>
|
||||
list_concurrent_modify_test: RuntimeError # dart2js does not fully implement these
|
||||
|
||||
[ $compiler == dart2js && $runtime == drt && $csp && $minified ]
|
||||
core_runtime_types_test: Pass, Fail # Issue 27913
|
||||
|
@ -192,8 +189,6 @@ iterable_element_at_test/static: MissingCompileTimeError
|
|||
|
||||
[ $compiler == dartdevc && $runtime != none ]
|
||||
error_stack_trace_test/nullThrown: RuntimeError # .stackTrace not present for exception caught from 'throw null;'
|
||||
list_fill_range_test: RuntimeError # Issue 29921
|
||||
list_insert_test: RuntimeError # Issue 29921
|
||||
list_removeat_test: RuntimeError # Issue 29921
|
||||
list_replace_range_test: RuntimeError # Issue 29921
|
||||
list_set_all_test: RuntimeError # Issue 29921
|
||||
|
@ -327,6 +322,7 @@ big_integer_parsed_mul_div_vm_test: Pass, Timeout # --no_intrinsify
|
|||
string_trimlr_test/02: RuntimeError # Issue 29060
|
||||
iterable_to_set_test: RuntimeError # is-checks do not implement strong mode type system
|
||||
|
||||
|
||||
[ $compiler == precompiler || $compiler == app_jit ]
|
||||
string_trimlr_test/02: RuntimeError # Issue 29060
|
||||
|
||||
|
@ -464,6 +460,7 @@ string_case_test/01: RuntimeError
|
|||
|
||||
[ $runtime == vm || $runtime == dart_precompiled ]
|
||||
string_split_test: RuntimeError # does not return List<String>
|
||||
list_test/*: RuntimeError # VM doesn't implement strong mode covariance checks
|
||||
|
||||
[ $compiler == dart2js && $dart2js_with_kernel && $host_checked ]
|
||||
apply2_test: Crash
|
||||
|
|
|
@ -165,20 +165,4 @@ void testConcurrentModification() {
|
|||
l.addAll(ci);
|
||||
Expect.listEquals(new List.generate(500, (x) => x), l, "cm6");
|
||||
}
|
||||
|
||||
{
|
||||
// Adding to yourself.
|
||||
var l = [1];
|
||||
Expect.throws(() {
|
||||
l.addAll(l);
|
||||
}, (e) => e is ConcurrentModificationError, "cm7");
|
||||
}
|
||||
|
||||
{
|
||||
// Adding to yourself.
|
||||
var l = [1, 2, 3];
|
||||
Expect.throws(() {
|
||||
l.addAll(l);
|
||||
}, (e) => e is ConcurrentModificationError, "cm8");
|
||||
}
|
||||
}
|
||||
|
|
100
tests/corelib_2/list_concurrent_modify_test.dart
Normal file
100
tests/corelib_2/list_concurrent_modify_test.dart
Normal file
|
@ -0,0 +1,100 @@
|
|||
// 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.
|
||||
|
||||
import "dart:collection";
|
||||
import "dart:typed_data";
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
void main() {
|
||||
// Growable lists. Initial length 0.
|
||||
testConcurrentModification(new List());
|
||||
testConcurrentModification(new List<int>().toList());
|
||||
testConcurrentModification(new List<int>(0).toList());
|
||||
testConcurrentModification(new List.filled(0, null, growable: true));
|
||||
testConcurrentModification([]);
|
||||
testConcurrentModification(new List.from(const []));
|
||||
testConcurrentModification(new MyList([]));
|
||||
testConcurrentModification(new MyList<int>([]).toList());
|
||||
|
||||
testConcurrentModification(new Uint8List(0).toList());
|
||||
testConcurrentModification(new Int8List(0).toList());
|
||||
testConcurrentModification(new Uint16List(0).toList());
|
||||
testConcurrentModification(new Int16List(0).toList());
|
||||
testConcurrentModification(new Uint32List(0).toList());
|
||||
testConcurrentModification(new Int32List(0).toList());
|
||||
|
||||
testConcurrentAddSelf([]);
|
||||
testConcurrentAddSelf([1, 2, 3]);
|
||||
}
|
||||
|
||||
void testConcurrentModification(List<int> list) {
|
||||
// add, removeLast.
|
||||
list.clear();
|
||||
list.addAll([1, 2, 3, 2, 7, 9, 9, 7, 2, 3, 2, 1]);
|
||||
|
||||
// Operations that change the length cause ConcurrentModificationError.
|
||||
void testModification(action()) {
|
||||
testIterator(int when) {
|
||||
list.length = 4;
|
||||
list.setAll(0, [0, 1, 2, 3]);
|
||||
Expect.throws(() {
|
||||
for (var element in list) {
|
||||
if (element == when) action();
|
||||
}
|
||||
}, (e) => e is ConcurrentModificationError);
|
||||
}
|
||||
|
||||
testForEach(int when) {
|
||||
list.length = 4;
|
||||
list.setAll(0, [0, 1, 2, 3]);
|
||||
Expect.throws(() {
|
||||
list.forEach((var element) {
|
||||
if (element == when) action();
|
||||
});
|
||||
}, (e) => e is ConcurrentModificationError);
|
||||
}
|
||||
|
||||
// Test the change at different points of the iteration.
|
||||
testIterator(0);
|
||||
testIterator(1);
|
||||
testIterator(3);
|
||||
testForEach(0);
|
||||
testForEach(1);
|
||||
testForEach(3);
|
||||
}
|
||||
|
||||
testModification(() => list.add(5));
|
||||
testModification(() => list.addAll([5, 6]));
|
||||
testModification(() => list.removeLast());
|
||||
for (int i = 0; i < 4; i++) {
|
||||
testModification(() => list.remove(i));
|
||||
testModification(() => list.removeAt(i));
|
||||
testModification(() => list.removeWhere((x) => x == i));
|
||||
testModification(() => list.retainWhere((x) => x != i));
|
||||
testModification(() => list.insert(i, 5));
|
||||
testModification(() => list.insertAll(i, [5, 6]));
|
||||
testModification(() => list.removeRange(i, i + 1));
|
||||
testModification(() => list.replaceRange(i, i + 1, [5, 6]));
|
||||
}
|
||||
}
|
||||
|
||||
testConcurrentAddSelf(List list) {
|
||||
Expect.throws(() {
|
||||
list.addAll(list);
|
||||
}, (e) => e is ConcurrentModificationError, "testConcurrentAddSelf($list)");
|
||||
}
|
||||
|
||||
class MyList<E> extends ListBase<E> {
|
||||
List<E> _source;
|
||||
MyList(this._source);
|
||||
int get length => _source.length;
|
||||
void set length(int length) {
|
||||
_source.length = length;
|
||||
}
|
||||
|
||||
E operator [](int index) => _source[index];
|
||||
void operator []=(int index, E value) {
|
||||
_source[index] = value;
|
||||
}
|
||||
}
|
|
@ -22,22 +22,22 @@ void main() {
|
|||
testTypedList(new Int32List(4).toList(growable: false));
|
||||
|
||||
// Fixed length lists, length 4.
|
||||
testFixedLengthList(new List(4));
|
||||
testFixedLengthList(new List(4).toList(growable: false));
|
||||
testFixedLengthList((new List()..length = 4).toList(growable: false));
|
||||
testFixedLengthList(<T>() => new List(4));
|
||||
testFixedLengthList(<T>() => new List<T>(4).toList(growable: false));
|
||||
testFixedLengthList(<T>() => (new List<T>()..length = 4).toList(growable: false));
|
||||
// ListBase implementation of List.
|
||||
testFixedLengthList(new MyFixedList(new List(4)));
|
||||
testFixedLengthList(new MyFixedList(new List(4)).toList(growable: false));
|
||||
testFixedLengthList(<T>() => new MyFixedList(new List(4)));
|
||||
testFixedLengthList(<T>() => new MyFixedList<T>(new List(4)).toList(growable: false));
|
||||
|
||||
// Growable lists. Initial length 0.
|
||||
testGrowableList(new List());
|
||||
testGrowableList(new List().toList());
|
||||
testGrowableList(new List(0).toList());
|
||||
testGrowableList(new List.filled(0, null, growable: true));
|
||||
testGrowableList([]);
|
||||
testGrowableList((const []).toList());
|
||||
testGrowableList(new MyList([]));
|
||||
testGrowableList(new MyList([]).toList());
|
||||
testGrowableList(<T>() => new List());
|
||||
testGrowableList(<T>() => new List<T>().toList());
|
||||
testGrowableList(<T>() => new List<T>(0).toList());
|
||||
testGrowableList(<T>() => new List.filled(0, null, growable: true));
|
||||
testGrowableList(<T>() => []);
|
||||
testGrowableList(<T>() => new List.from(const []));
|
||||
testGrowableList(<T>() => new MyList([]));
|
||||
testGrowableList(<T>() => new MyList<T>([]).toList());
|
||||
|
||||
testTypedGrowableList(new Uint8List(0).toList());
|
||||
testTypedGrowableList(new Int8List(0).toList());
|
||||
|
@ -140,7 +140,7 @@ void testLength(int length, List list) {
|
|||
(length != 0 ? Expect.isTrue : Expect.isFalse)(list.isNotEmpty);
|
||||
}
|
||||
|
||||
void testTypedLengthInvariantOperations(List list) {
|
||||
void testTypedLengthInvariantOperations(List<int> list) {
|
||||
// length
|
||||
Expect.equals(list.length, 4);
|
||||
// operators [], []=.
|
||||
|
@ -257,8 +257,7 @@ void testTypedLengthInvariantOperations(List list) {
|
|||
// so it's moved to the method below for now.
|
||||
}
|
||||
|
||||
void testLengthInvariantOperations(List list) {
|
||||
testTypedLengthInvariantOperations(list);
|
||||
void testUntypedListTests(List list) {
|
||||
// Tests that need untyped lists.
|
||||
list.setAll(0, [0, 1, 2, 3]);
|
||||
Expect.equals(-1, list.indexOf(100));
|
||||
|
@ -275,6 +274,14 @@ void testLengthInvariantOperations(List list) {
|
|||
list[3] = 3;
|
||||
Expect.equals(-1, list.indexOf(100));
|
||||
Expect.equals(-1, list.lastIndexOf(100));
|
||||
}
|
||||
|
||||
void testLengthInvariantOperations(List<int> list) {
|
||||
testTypedLengthInvariantOperations(list);
|
||||
|
||||
Expect.throws(() {
|
||||
testUntypedListTests(list);
|
||||
}, (e) => e is TypeError, 'List<int> cannot store non-ints');
|
||||
|
||||
// Argument errors on bad indices. List is still [0, 1, 2, 3].
|
||||
testArgumentError(action()) {
|
||||
|
@ -311,21 +318,22 @@ void testLengthInvariantOperations(List list) {
|
|||
testArgumentError(() => list.fillRange(4, 2));
|
||||
}
|
||||
|
||||
void testTypedList(List list) {
|
||||
void testTypedList(List<int> list) {
|
||||
testTypedLengthInvariantOperations(list);
|
||||
testCannotChangeLength(list);
|
||||
}
|
||||
|
||||
void testFixedLengthList(List list) {
|
||||
testLengthInvariantOperations(list);
|
||||
testCannotChangeLength(list);
|
||||
void testFixedLengthList(List<T> Function<T>() createList) {
|
||||
testLengthInvariantOperations(createList());
|
||||
testCannotChangeLength(createList());
|
||||
testUntypedListTests(createList());
|
||||
}
|
||||
|
||||
void testCannotChangeLength(List list) {
|
||||
void testCannotChangeLength(List<int> list) {
|
||||
isUnsupported(action()) {
|
||||
Expect.throws(action, (e) => e is UnsupportedError);
|
||||
}
|
||||
|
||||
list.setAll(0, [0, 1, 2, 3]);
|
||||
isUnsupported(() => list.add(0));
|
||||
isUnsupported(() => list.addAll([0]));
|
||||
isUnsupported(() => list.removeLast());
|
||||
|
@ -338,7 +346,7 @@ void testCannotChangeLength(List list) {
|
|||
isUnsupported(() => list.replaceRange(0, 1, []));
|
||||
}
|
||||
|
||||
void testTypedGrowableList(List list) {
|
||||
void testTypedGrowableList(List<int> list) {
|
||||
testLength(0, list);
|
||||
// set length.
|
||||
list.length = 4;
|
||||
|
@ -349,18 +357,24 @@ void testTypedGrowableList(List list) {
|
|||
testGrowableListOperations(list);
|
||||
}
|
||||
|
||||
void testGrowableList(List list) {
|
||||
void testGrowableList(List<T> Function<T>() createList) {
|
||||
List<int> list = createList();
|
||||
testLength(0, list);
|
||||
// set length.
|
||||
list.length = 4;
|
||||
testLength(4, list);
|
||||
|
||||
testLengthInvariantOperations(list);
|
||||
|
||||
testGrowableListOperations(list);
|
||||
|
||||
List listDynamic = createList();
|
||||
testLength(0, listDynamic);
|
||||
listDynamic.length = 4;
|
||||
testLength(4, listDynamic);
|
||||
|
||||
testUntypedListTests(listDynamic);
|
||||
}
|
||||
|
||||
void testGrowableListOperations(List list) {
|
||||
void testGrowableListOperations(List<int> list) {
|
||||
// add, removeLast.
|
||||
list.clear();
|
||||
testLength(0, list);
|
||||
|
@ -475,51 +489,6 @@ void testGrowableListOperations(List list) {
|
|||
list.replaceRange(6, 8, []);
|
||||
Expect.listEquals([1, 2, 6, 6, 5, 0, 2, 3, 2, 1], list);
|
||||
|
||||
// Operations that change the length cause ConcurrentModificationError.
|
||||
void testConcurrentModification(action()) {
|
||||
testIterator(int when) {
|
||||
list.length = 4;
|
||||
list.setAll(0, [0, 1, 2, 3]);
|
||||
Expect.throws(() {
|
||||
for (var element in list) {
|
||||
if (element == when) action();
|
||||
}
|
||||
}, (e) => e is ConcurrentModificationError);
|
||||
}
|
||||
|
||||
testForEach(int when) {
|
||||
list.length = 4;
|
||||
list.setAll(0, [0, 1, 2, 3]);
|
||||
Expect.throws(() {
|
||||
list.forEach((var element) {
|
||||
if (element == when) action();
|
||||
});
|
||||
}, (e) => e is ConcurrentModificationError);
|
||||
}
|
||||
|
||||
// Test the change at different points of the iteration.
|
||||
testIterator(0);
|
||||
testIterator(1);
|
||||
testIterator(3);
|
||||
testForEach(0);
|
||||
testForEach(1);
|
||||
testForEach(3);
|
||||
}
|
||||
|
||||
testConcurrentModification(() => list.add(5));
|
||||
testConcurrentModification(() => list.addAll([5, 6]));
|
||||
testConcurrentModification(() => list.removeLast());
|
||||
for (int i = 0; i < 4; i++) {
|
||||
testConcurrentModification(() => list.remove(i));
|
||||
testConcurrentModification(() => list.removeAt(i));
|
||||
testConcurrentModification(() => list.removeWhere((x) => x == i));
|
||||
testConcurrentModification(() => list.retainWhere((x) => x != i));
|
||||
testConcurrentModification(() => list.insert(i, 5));
|
||||
testConcurrentModification(() => list.insertAll(i, [5, 6]));
|
||||
testConcurrentModification(() => list.removeRange(i, i + 1));
|
||||
testConcurrentModification(() => list.replaceRange(i, i + 1, [5, 6]));
|
||||
}
|
||||
|
||||
// Any operation that doesn't change the length should be safe for iteration.
|
||||
testSafeConcurrentModification(action()) {
|
||||
list.length = 4;
|
||||
|
|
|
@ -710,7 +710,6 @@ issue23244_test: RuntimeError # Issue 29920
|
|||
lazy_static3_test: RuntimeError # Issue 29920
|
||||
left_shift_test: RuntimeError # Issue 29920
|
||||
list_is_test: RuntimeError # Issue 29920
|
||||
list_literal3_test: RuntimeError # Issue 29920
|
||||
main_test/03: MissingRuntimeError # Issue 29920
|
||||
map_literal10_test: RuntimeError # Issue 29920
|
||||
map_literal7_test: RuntimeError # Issue 29920
|
||||
|
|
|
@ -271,8 +271,6 @@ mirrors/library_enumeration_deferred_loading_test: RuntimeError # Issue 29922
|
|||
mirrors/library_metadata_test: RuntimeError # Issue 29922
|
||||
mirrors/library_uri_io_test: RuntimeError # Issue 29922
|
||||
mirrors/library_uri_package_test: RuntimeError # Issue 29922
|
||||
mirrors/list_constructor_test/01: RuntimeError # Issue 29922
|
||||
mirrors/list_constructor_test/none: RuntimeError # Issue 29922
|
||||
mirrors/local_function_is_static_test: RuntimeError # Issue 29922
|
||||
mirrors/local_isolate_test: RuntimeError # Issue 29922
|
||||
mirrors/metadata_constructed_constant_test: RuntimeError # Issue 29922
|
||||
|
|
Loading…
Reference in a new issue