diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart index 1d7790c69e8..b78c49f8563 100644 --- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart +++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart @@ -26,12 +26,14 @@ class InvocationImpl extends Invocation { namedArguments = _namedArgsToSymbols(namedArguments), typeArguments = typeArguments == null ? const [] - : typeArguments.map(wrapType).toList(); + : new List.unmodifiable(typeArguments.map(wrapType)); static Map _namedArgsToSymbols(namedArgs) { - if (namedArgs == null) return {}; - return new Map.fromIterable(getOwnPropertyNames(namedArgs), - key: _dartSymbol, value: (k) => JS('', '#[#]', namedArgs, k)); + if (namedArgs == null) return const {}; + return new Map.unmodifiable(new Map.fromIterable( + getOwnPropertyNames(namedArgs), + key: _dartSymbol, + value: (k) => JS('', '#[#]', namedArgs, k))); } } @@ -206,7 +208,7 @@ _toDisplayName(name) => JS('', '''(() => { // Names starting with _ are escaped names used to disambiguate Dart and // JS names. if ($name[0] === '_') { - // Inverse of + // Inverse of switch($name) { case '_get': return '[]'; @@ -293,7 +295,7 @@ _checkAndCall(f, ftype, obj, typeArgs, args, name) => JS('', '''(() => { // Apply type arguments if ($ftype instanceof $GenericFunctionType) { let formalCount = $ftype.formalCount; - + if ($typeArgs == null) { $typeArgs = $ftype.instantiateDefaultBounds(); } else if ($typeArgs.length != formalCount) { diff --git a/pkg/dev_compiler/tool/input_sdk/private/js_array.dart b/pkg/dev_compiler/tool/input_sdk/private/js_array.dart index 714ad2a08f2..69c90ff0f0d 100644 --- a/pkg/dev_compiler/tool/input_sdk/private/js_array.dart +++ b/pkg/dev_compiler/tool/input_sdk/private/js_array.dart @@ -598,17 +598,10 @@ class JSArray implements List, JSIndexable { Type get runtimeType => dart.wrapType(JS('', '#(#)', dart.getGenericClass(List), E)); - Iterable followedBy(Iterable other) sync* { - yield* this; - yield* other; - } + Iterable followedBy(Iterable other) => + new FollowedByIterable.firstEfficient(this, other); - Iterable whereType() sync* { - for (var i = 0; i < this.length; i++) { - var element = this[i]; - if (element is T) yield element; - } - } + Iterable whereType() => new WhereTypeIterable(this); List operator +(List other) { int totalLength = this.length + other.length; diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/bench_vector.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/bench_vector.dart.expect index aa44be514f3..b23ebd2e5e0 100644 --- a/pkg/vm/testcases/transformations/type_flow/transformer/bench_vector.dart.expect +++ b/pkg/vm/testcases/transformations/type_flow/transformer/bench_vector.dart.expect @@ -20,7 +20,7 @@ class _Vector extends core::Object { } operator *([@vm.inferred-type.metadata=#lib::_Vector] self::_Vector a) → core::double { core::double result = 0.0; - for (core::int i = 0; [@vm.direct-call.metadata=dart.core::_IntegerImplementation:: args) → dynamic { core::Stopwatch timer = let final core::Stopwatch #t1 = new core::Stopwatch::•() in let final dynamic #t2 = [@vm.direct-call.metadata=dart.core::Stopwatch::start] #t1.{core::Stopwatch::start}() in #t1; - for (core::int i = 0; [@vm.direct-call.metadata=dart.core::_IntegerImplementation:: implements Map { final _ImmutableList _kvPairs; const _ImmutableMap._create(_ImmutableList keyValuePairs) : _kvPairs = keyValuePairs; + Map cast() { + Map self = this; + return (self is Map) ? self : this.retype(); + } + + Map retype() => Map.castFrom(this); + V operator [](Object key) { // To preserve the key-value order of the map literal, the keys are // not sorted. Need to do linear search or implement an additional @@ -69,6 +78,10 @@ class _ImmutableMap implements Map { throw new UnsupportedError("Cannot set value in unmodifiable Map"); } + void addAll(Map other) { + throw new UnsupportedError("Cannot set value in unmodifiable Map"); + } + V putIfAbsent(K key, V ifAbsent()) { throw new UnsupportedError("Cannot set value in unmodifiable Map"); } diff --git a/runtime/lib/typed_data_patch.dart b/runtime/lib/typed_data_patch.dart index 5e2312c4229..4d6161c75e4 100644 --- a/runtime/lib/typed_data_patch.dart +++ b/runtime/lib/typed_data_patch.dart @@ -12,6 +12,7 @@ import "dart:_internal" ClassID, CodeUnits, ExpandIterable, + FollowedByIterable, IterableElementError, ListMapView, Lists, @@ -23,6 +24,7 @@ import "dart:_internal" SubListIterable, TakeWhileIterable, WhereIterable, + WhereTypeIterable, patch; import "dart:collection" show ListBase; @@ -112,6 +114,11 @@ abstract class _IntListMixin implements List { List _createList(int length); + Iterable whereType() => new WhereTypeIterable(this); + + Iterable followedBy(Iterable other) => + new FollowedByIterable.firstEfficient(this, other); + List cast() { List self = this; return self is List ? self : List.castFrom(this); @@ -466,6 +473,11 @@ abstract class _DoubleListMixin implements List { List _createList(int length); + Iterable whereType() => new WhereTypeIterable(this); + + Iterable followedBy(Iterable other) => + new FollowedByIterable.firstEfficient(this, other); + List cast() { List self = this; return self is List ? self : List.castFrom(this); @@ -823,6 +835,11 @@ abstract class _Float32x4ListMixin implements List { List _createList(int length); + Iterable whereType() => new WhereTypeIterable(this); + + Iterable followedBy(Iterable other) => + new FollowedByIterable.firstEfficient(this, other); + List cast() { List self = this; return self is List ? self : List.castFrom(this); @@ -1184,6 +1201,11 @@ abstract class _Int32x4ListMixin implements List { List _createList(int length); + Iterable whereType() => new WhereTypeIterable(this); + + Iterable followedBy(Iterable other) => + new FollowedByIterable.firstEfficient(this, other); + List cast() { List self = this; return self is List ? self : List.castFrom(this); @@ -1544,6 +1566,11 @@ abstract class _Float64x2ListMixin implements List { List _createList(int length); + Iterable whereType() => new WhereTypeIterable(this); + + Iterable followedBy(Iterable other) => + new FollowedByIterable.firstEfficient(this, other); + List cast() { List self = this; return self is List ? self : List.castFrom(this); diff --git a/sdk/lib/_internal/js_runtime/lib/js_array.dart b/sdk/lib/_internal/js_runtime/lib/js_array.dart index e8dbab75942..563297a03db 100644 --- a/sdk/lib/_internal/js_runtime/lib/js_array.dart +++ b/sdk/lib/_internal/js_runtime/lib/js_array.dart @@ -635,17 +635,10 @@ class JSArray extends Interceptor implements List, JSIndexable { return new ListMapView(this); } - Iterable followedBy(Iterable other) sync* { - yield* this; - yield* other; - } + Iterable followedBy(Iterable other) => + new FollowedByIterable.firstEfficient(this, other); - Iterable whereType() sync* { - for (var i = 0; i < this.length; i++) { - var element = this[i]; - if (element is T) yield element; - } - } + Iterable whereType() => new WhereTypeIterable(this); List operator +(List other) { int totalLength = this.length + other.length; diff --git a/sdk/lib/collection/iterable.dart b/sdk/lib/collection/iterable.dart index 7d028a4d88d..67bfdd8b836 100644 --- a/sdk/lib/collection/iterable.dart +++ b/sdk/lib/collection/iterable.dart @@ -26,18 +26,19 @@ abstract class IterableMixin implements Iterable { Iterable where(bool f(E element)) => new WhereIterable(this, f); - Iterable whereType() sync* { - for (Object element in this) if (element is T) yield element; - } + Iterable whereType() => new WhereTypeIterable(this); Iterable expand(Iterable f(E element)) => new ExpandIterable(this, f); - Iterable followedBy(Iterable other) sync* { - // TODO(lrn): Optimize this (some operations can be more efficient, - // and the concatenation has efficient length if the source iterables do). - yield* this; - yield* other; + Iterable followedBy(Iterable other) { + // Type workaround because IterableMixin doesn't promote + // to EfficientLengthIterable. + Iterable self = this; + if (self is EfficientLengthIterable) { + return new FollowedByIterable.firstEfficient(self, other); + } + return new FollowedByIterable(this, other); } bool contains(Object element) { diff --git a/sdk/lib/collection/list.dart b/sdk/lib/collection/list.dart index 57e5ef4c4fb..2a5792dbfa8 100644 --- a/sdk/lib/collection/list.dart +++ b/sdk/lib/collection/list.dart @@ -59,12 +59,8 @@ abstract class ListMixin implements List { E elementAt(int index) => this[index]; - Iterable followedBy(Iterable other) sync* { - for (var i = 0; i < length; i++) { - yield this[i]; - } - yield* other; - } + Iterable followedBy(Iterable other) => + new FollowedByIterable.firstEfficient(this, other); void forEach(void action(E element)) { int length = this.length; @@ -195,9 +191,7 @@ abstract class ListMixin implements List { Iterable where(bool test(E element)) => new WhereIterable(this, test); - Iterable whereType() sync* { - for (var element in this) if (element is T) yield (element as T); - } + Iterable whereType() => new WhereTypeIterable(this); Iterable map(T f(E element)) => new MappedListIterable(this, f); diff --git a/sdk/lib/collection/set.dart b/sdk/lib/collection/set.dart index 5d51dffe04a..71bf718fd7a 100644 --- a/sdk/lib/collection/set.dart +++ b/sdk/lib/collection/set.dart @@ -58,16 +58,10 @@ abstract class SetMixin implements Set { Set retype() => Set.castFrom(this); - Iterable followedBy(Iterable other) sync* { - // TODO(lrn): Optimize this (some operations can be more efficient, - // and the concatenation has efficient length if the source iterables do). - yield* this; - yield* other; - } + Iterable followedBy(Iterable other) => + new FollowedByIterable.firstEfficient(this, other); - Iterable whereType() sync* { - for (Object element in this) if (element is T) yield element; - } + Iterable whereType() => new WhereTypeIterable(this); void clear() { removeAll(toList()); diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart index d3cc85b52dd..410b57d8dcd 100644 --- a/sdk/lib/core/iterable.dart +++ b/sdk/lib/core/iterable.dart @@ -186,11 +186,11 @@ abstract class Iterable { * and, after that, the elements of [other], in the same order as in the * original iterables. */ - Iterable followedBy(Iterable other) sync* { - // TODO(lrn): Optimize this (some operations can be more efficient, - // and the concatenation has efficient length if the source iterables do). - yield* this; - yield* other; + Iterable followedBy(Iterable other) { + if (this is EfficientLengthIterable) { + return new FollowedByIterable.firstEfficient(this, other); + } + return new FollowedByIterable(this, other); } /** @@ -236,9 +236,7 @@ abstract class Iterable { * the returned [Iterable] may yield different results, * if the underlying elements change between iterations. */ - Iterable whereType() sync* { - for (var element in this) if (element is T) yield (element as T); - } + Iterable whereType() => new WhereTypeIterable(this); /** * Expands each element of this [Iterable] into zero or more elements. diff --git a/sdk/lib/internal/iterable.dart b/sdk/lib/internal/iterable.dart index d8941c9f2bb..1c11e53caa7 100644 --- a/sdk/lib/internal/iterable.dart +++ b/sdk/lib/internal/iterable.dart @@ -767,6 +767,125 @@ class EmptyIterator implements Iterator { E get current => null; } +class FollowedByIterable extends Iterable { + final Iterable _first; + final Iterable _second; + FollowedByIterable(this._first, this._second); + + factory FollowedByIterable.firstEfficient( + EfficientLengthIterable first, Iterable second) { + if (second is EfficientLengthIterable) { + return new EfficientLengthFollowedByIterable(first, second); + } + return new FollowedByIterable(first, second); + } + + Iterator get iterator => new FollowedByIterator(_first, _second); + + int get length => _first.length + _second.length; + bool get isEmpty => _first.isEmpty && _second.isEmpty; + bool get isNotEmpty => _first.isNotEmpty || _second.isNotEmpty; + + // May be more efficient if either iterable is a Set. + bool contains(Object value) => + _first.contains(value) || _second.contains(value); + + E get first { + var iterator = _first.iterator; + if (iterator.moveNext()) return iterator.current; + return _second.first; + } + + E get last { + var iterator = _second.iterator; + if (iterator.moveNext()) { + E last = iterator.current; + while (iterator.moveNext()) last = iterator.current; + return last; + } + return _first.last; + } + + // If linear sequences of `followedBy` becomes an issue, we can flatten + // into a list of iterables instead of a tree or spine. +} + +class EfficientLengthFollowedByIterable extends FollowedByIterable + implements EfficientLengthIterable { + EfficientLengthFollowedByIterable( + EfficientLengthIterable first, EfficientLengthIterable second) + : super(first, second); + + Iterable skip(int count) { + int firstLength = _first.length; + if (count >= firstLength) return _second.skip(count - firstLength); + return new EfficientLengthFollowedByIterable( + _first.skip(count), _second); + } + + Iterable take(int count) { + int firstLength = _first.length; + if (count <= firstLength) return _first.take(count); + return new EfficientLengthFollowedByIterable( + _first, _second.take(count - firstLength)); + } + + E elementAt(int index) { + int firstLength = _first.length; + if (index < firstLength) return _first.elementAt(index); + return _second.elementAt(index - firstLength); + } + + E get first { + if (_first.isNotEmpty) return _first.first; + return _second.first; + } + + E get last { + if (_second.isNotEmpty) return _second.last; + return _first.last; + } +} + +class FollowedByIterator implements Iterator { + Iterator _currentIterator; + Iterable _nextIterable; + + FollowedByIterator(Iterable first, this._nextIterable) + : _currentIterator = first.iterator; + + bool moveNext() { + if (_currentIterator.moveNext()) return true; + if (_nextIterable != null) { + _currentIterator = _nextIterable.iterator; + _nextIterable = null; + return _currentIterator.moveNext(); + } + return false; + } + + E get current => _currentIterator.current; +} + +class WhereTypeIterable extends Iterable { + final Iterable _source; + WhereTypeIterable(this._source); + Iterator get iterator => new WhereTypeIterator(_source.iterator); +} + +class WhereTypeIterator implements Iterator { + final Iterator _source; + WhereTypeIterator(this._source); + bool moveNext() { + while (_source.moveNext()) { + if (_source.current is T) return true; + } + return false; + } + + T get current => _source.current; +} + /** * Creates errors throw by [Iterable] when the element count is wrong. */ diff --git a/tests/compiler/dart2js/old_frontend/analyze_api_test.dart b/tests/compiler/dart2js/old_frontend/analyze_api_test.dart index c74aee2273b..458824ef121 100644 --- a/tests/compiler/dart2js/old_frontend/analyze_api_test.dart +++ b/tests/compiler/dart2js/old_frontend/analyze_api_test.dart @@ -18,25 +18,7 @@ import 'package:async_helper/async_helper.dart'; * the error/warning message in the list of white-listings for each file. */ // TODO(johnniwinther): Support canonical URIs as keys. -const Map> WHITE_LIST = const { - "sdk/lib/_internal/js_runtime/lib/js_array.dart": const [ - "Method type variables do not have a runtime value.", - ], - "sdk/lib/collection/iterable.dart": const [ - "Method type variables do not have a runtime value.", - ], - "sdk/lib/collection/list.dart": const [ - "Method type variables do not have a runtime value.", - "Method type variables are treated as `dynamic` in `as` expressions.", - ], - "sdk/lib/collection/set.dart": const [ - "Method type variables do not have a runtime value.", - ], - "sdk/lib/core/iterable.dart": const [ - "Method type variables do not have a runtime value.", - "Method type variables are treated as `dynamic` in `as` expressions.", - ], -}; +const Map> WHITE_LIST = const {}; void main() { var uriList = new List(); diff --git a/tests/compiler/dart2js/old_frontend/diagnose_ambiguous_test.dart b/tests/compiler/dart2js/old_frontend/diagnose_ambiguous_test.dart index 8af9a960d57..53538ed95f1 100644 --- a/tests/compiler/dart2js/old_frontend/diagnose_ambiguous_test.dart +++ b/tests/compiler/dart2js/old_frontend/diagnose_ambiguous_test.dart @@ -28,12 +28,6 @@ void main() { "memory:library.dart:41:47:'hest' is defined here.:info", "MessageKind.DUPLICATE_IMPORT:" "memory:main.dart:86:92:Duplicate import of 'hest'.:warning", - "MessageKind.HIDDEN_WARNINGS:" - "null:null:null:1 warning(s) suppressed in dart:_interceptors.:hint", - "MessageKind.HIDDEN_WARNINGS_HINTS:" - "null:null:null:1 warning(s) and 1 hint(s) suppressed in dart:core.:hint", - "MessageKind.HIDDEN_WARNINGS_HINTS:" - "null:null:null:3 warning(s) and 1 hint(s) suppressed in dart:collection.:hint", "MessageKind.IMPORTED_HERE:" "memory:main.dart:0:22:'hest' is imported here.:info", "MessageKind.IMPORTED_HERE:" diff --git a/tests/compiler/dart2js/old_frontend/duplicate_library_test.dart b/tests/compiler/dart2js/old_frontend/duplicate_library_test.dart index 44c81c897e6..0f10f25f398 100644 --- a/tests/compiler/dart2js/old_frontend/duplicate_library_test.dart +++ b/tests/compiler/dart2js/old_frontend/duplicate_library_test.dart @@ -14,7 +14,7 @@ import '../memory_compiler.dart'; void check(String kind, Iterable messages, List expectedMessageKinds) { - Expect.equals(messages.length, expectedMessageKinds.length, + Expect.equals(expectedMessageKinds.length, messages.length, "Unexpected $kind count: $messages"); int i = 0; messages.forEach((CollectedMessage message) { @@ -56,11 +56,7 @@ library lib.foo; """ }, warnings: [ MessageKind.DUPLICATED_LIBRARY_RESOURCE - ], hints: [ - MessageKind.HIDDEN_WARNINGS, - MessageKind.HIDDEN_WARNINGS_HINTS, - MessageKind.HIDDEN_WARNINGS_HINTS, - ]); + ], hints: []); await test({ 'main.dart': """ @@ -79,11 +75,7 @@ library lib.bar; """ }, warnings: [ MessageKind.DUPLICATED_LIBRARY_RESOURCE - ], hints: [ - MessageKind.HIDDEN_WARNINGS, - MessageKind.HIDDEN_WARNINGS_HINTS, - MessageKind.HIDDEN_WARNINGS_HINTS, - ]); + ], hints: []); await test({ 'main.dart': """ @@ -102,11 +94,7 @@ library lib.baz; """ }, warnings: [ MessageKind.DUPLICATED_LIBRARY_RESOURCE - ], hints: [ - MessageKind.HIDDEN_WARNINGS, - MessageKind.HIDDEN_WARNINGS_HINTS, - MessageKind.HIDDEN_WARNINGS_HINTS, - ]); + ], hints: []); await test({ 'main.dart': """ @@ -130,11 +118,7 @@ library lib.boz; """ }, warnings: [ MessageKind.DUPLICATED_LIBRARY_RESOURCE - ], hints: [ - MessageKind.HIDDEN_WARNINGS, - MessageKind.HIDDEN_WARNINGS_HINTS, - MessageKind.HIDDEN_WARNINGS_HINTS, - ]); + ], hints: []); await test({ 'main.dart': """ @@ -148,9 +132,6 @@ import 'pkg/lib/qux.dart'; """ }, hints: [ MessageKind.DUPLICATED_RESOURCE, - MessageKind.HIDDEN_WARNINGS, - MessageKind.HIDDEN_WARNINGS_HINTS, - MessageKind.HIDDEN_WARNINGS_HINTS, ]); await test({ @@ -169,9 +150,5 @@ library lib; }, warnings: [ MessageKind.DUPLICATED_LIBRARY_NAME, MessageKind.DUPLICATED_LIBRARY_NAME - ], hints: [ - MessageKind.HIDDEN_WARNINGS, - MessageKind.HIDDEN_WARNINGS_HINTS, - MessageKind.HIDDEN_WARNINGS_HINTS, - ]); + ], hints: []); } diff --git a/tests/corelib_2/corelib_2.status b/tests/corelib_2/corelib_2.status index e0bcaf19206..dfcae0f1c24 100644 --- a/tests/corelib_2/corelib_2.status +++ b/tests/corelib_2/corelib_2.status @@ -8,6 +8,9 @@ int_parse_radix_bad_handler_test: MissingCompileTimeError iterable_element_at_test/static: Pass num_sign_test: Crash, Pass # Issue 31768 +[ $compiler == dart2js ] +iterable_where_type_test: RuntimeError # issue 31718 + [ $compiler != dartdevc ] error_stack_trace_test/static: MissingCompileTimeError diff --git a/tests/corelib_2/iterable_followed_by_test.dart b/tests/corelib_2/iterable_followed_by_test.dart new file mode 100644 index 00000000000..5edf0e3e223 --- /dev/null +++ b/tests/corelib_2/iterable_followed_by_test.dart @@ -0,0 +1,102 @@ +// Copyright (c) 2018, 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" show Queue; +import "dart:typed_data" show Int32List; + +import "package:expect/expect.dart"; + +// Tests behavior of result of an operation on a followedBy iterable. +test(List expects, Iterable iterable, [String name]) { + try { + Expect.isFalse(iterable is List, "$name is! List"); + Expect.isFalse(iterable is Set, "$name is! Set"); + Expect.isFalse(iterable is Queue, "$name is! Queue"); + if (expects.isNotEmpty) { + Expect.equals(expects.first, iterable.first, "$name: first"); + Expect.equals(expects.last, iterable.last, "$name: last"); + } else { + Expect.throwsStateError(() => iterable.first, "$name: first"); + Expect.throwsStateError(() => iterable.last, "$name: last"); + } + var it = iterable.iterator; + for (int index = 0; index < expects.length; index++) { + Expect.isTrue(it.moveNext(), "$name: has element $index"); + var expect = expects[index]; + Expect.equals(expect, it.current, "$name at $index"); + Expect.equals( + expect, iterable.elementAt(index), "$name: elementAt($index)"); + Expect.isTrue(iterable.contains(expect), "$name:contains $index"); + } + Expect.isFalse(it.moveNext(), + "$name: extra element at ${expects.length}: ${it.current}"); + } on Error { + print("Failed during: $name"); + rethrow; + } +} + +// Tests various operations on the a followedBy iterable. +tests(List expects, Iterable follow, [String name]) { + int length = expects.length; + test(expects, follow, name); + for (int i = 0; i <= length; i++) { + test(expects.sublist(i), follow.skip(i), "$name.skip($i)"); + } + for (int i = 0; i <= length; i++) { + test(expects.sublist(0, i), follow.take(i), "$name.take($i)"); + } + for (int i = 0; i <= length; i++) { + for (int j = 0; j <= length - i; j++) { + test(expects.sublist(i, i + j), follow.skip(i).take(j), + "$name.skiptake($i,${i+j})"); + test(expects.sublist(i, i + j), follow.take(i + j).skip(i), + "$name.takeskip($i,${i+j})"); + } + } +} + +// Tests various different types of iterables as first and second operand. +types(List expects, List first, List second, [String name]) { + var conversions = Function(List)>{ + "const": toConst, + "list": toList, + "unmod": toUnmodifiable, + "set": toSet, + "queue": toQueue, + "eff-len-iter": toELIter, + "non-eff-iter": toNEIter, + "typed": toTyped, + "keys": toKeys, + "values": toValues, + }; + conversions.forEach((n1, c1) { + conversions.forEach((n2, c2) { + tests(expects, c1(first).followedBy(c2(second)), "$name:$n1/$n2"); + }); + }); +} + +List toConst(List elements) => elements; +List toList(List elements) => elements.toList(); +List toUnmodifiable(List elements) => + new List.unmodifiable(elements); +Set toSet(List elements) => elements.toSet(); +Queue toQueue(List elements) => new Queue.from(elements); +// Creates an efficient-length iterable. +Iterable toELIter(List elements) => elements.map((x) => x); +// Creates a non-efficient-length iterable. +Iterable toNEIter(List elements) => elements.where((x) => true); +List toTyped(List elements) => new Int32List.fromList(elements); +Iterable toKeys(List elements) => + new Map.fromIterables(elements, elements).keys; +Iterable toValues(List elements) => + new Map.fromIterables(elements, elements).values; + +main() { + types([], const [], const [], "0+0"); + types([1, 2, 3, 4], const [], const [1, 2, 3, 4], "0+4"); + types([1, 2, 3, 4], const [1, 2], const [3, 4], "2+2"); + types([1, 2, 3, 4], const [1, 2, 3, 4], const [], "4+0"); +} diff --git a/tests/corelib_2/iterable_where_type_test.dart b/tests/corelib_2/iterable_where_type_test.dart new file mode 100644 index 00000000000..8715149f049 --- /dev/null +++ b/tests/corelib_2/iterable_where_type_test.dart @@ -0,0 +1,105 @@ +// Copyright (c) 2018, 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" show Queue; +import "dart:typed_data" show Int32List; + +import "package:expect/expect.dart"; + +// Tests behavior of result of an operation on a followedBy iterable. +test(List expects, Iterable iterable, [String name]) { + try { + Expect.isFalse(iterable is List, "$name is! List"); + Expect.isFalse(iterable is Set, "$name is! Set"); + Expect.isFalse(iterable is Queue, "$name is! Queue"); + if (expects.isNotEmpty) { + Expect.equals(expects.first, iterable.first, "$name: first"); + Expect.equals(expects.last, iterable.last, "$name: last"); + } else { + Expect.throwsStateError(() => iterable.first, "$name: first"); + Expect.throwsStateError(() => iterable.last, "$name: last"); + } + var it = iterable.iterator; + for (int index = 0; index < expects.length; index++) { + Expect.isTrue(it.moveNext(), "$name: has element $index"); + var expect = expects[index]; + Expect.equals(expect, it.current, "$name at $index"); + Expect.equals( + expect, iterable.elementAt(index), "$name: elementAt($index)"); + Expect.isTrue(iterable.contains(expect), "$name:contains $index"); + } + Expect.isFalse(it.moveNext(), + "$name: extra element at ${expects.length}: ${it.current}"); + } on Error { + print("Failed during: $name"); + rethrow; + } +} + +main() { + var conversions = Function(List)>{ + "const": toConst, + "list": toList, + "unmod": toUnmodifiable, + "set": toSet, + "queue": toQueue, + "eff-len-iter": toELIter, + "non-eff-iter": toNEIter, + "typed": toTyped, + "keys": toKeys, + "values": toValues, + }; + for (var data in [ + const [], + const [1], + const [1, 2, 3] + ]) { + conversions.forEach((name, c) { + test(data, c(data).whereType(), "$name#${data.length}.wt"); + test(data, c(data).whereType(), "$name#${data.length}.wt"); + test([], c(data).whereType(), "$name#${data.length}.wt"); + }); + } + + test([1, 0.1], ["a", 1, new Object(), 0.1, null].whereType(), "mixed"); + + var o = new Object(); + var a = new A(); + var b = new B(); + var c = new C(); + var d = new D(); + var n = null; + test([o, a, b, c, d, n], [o, a, b, c, d, n].whereType(), "Object"); + test([a, b, c, d], [o, a, b, c, d, n].whereType(), "A"); + test([b, d], [o, a, b, c, d, n].whereType(), "B"); + test([c, d], [o, a, b, c, d, n].whereType(), "C"); + test([d], [o, a, b, c, d, n].whereType(), "D"); + test([n], [o, a, b, c, d, n].whereType(), "Null"); + + test([d], [d].whereType(), "Unrelated"); +} + +class A {} + +class B implements A {} + +class C implements A {} + +class D implements B, C {} + +List toConst(List elements) => elements; // Argument is const. +List toList(List elements) => elements.toList(); +List toUnmodifiable(List elements) => + new List.unmodifiable(elements); +Set toSet(List elements) => elements.toSet(); +Queue toQueue(List elements) => new Queue.from(elements); +// Creates an efficient-length iterable. +Iterable toELIter(List elements) => elements.map((x) => x); +// Creates a non-efficient-length iterable. +Iterable toNEIter(List elements) => elements.where((x) => true); +List toTyped(List elements) => new Int32List.fromList(elements); +Iterable toKeys(List elements) => + new Map.fromIterables(elements, elements).keys; +Iterable toValues(List elements) => + new Map.fromIterables(elements, elements).values; diff --git a/tests/corelib_2/map_unmodifiable_cast_test.dart b/tests/corelib_2/map_unmodifiable_cast_test.dart index 9c1e19bcb53..3091337d528 100644 --- a/tests/corelib_2/map_unmodifiable_cast_test.dart +++ b/tests/corelib_2/map_unmodifiable_cast_test.dart @@ -8,45 +8,76 @@ import "package:expect/expect.dart"; import 'dart:collection'; void main() { - test(const {1: 37}); - test(new UnmodifiableMapView({1: 37})); + testNum(const {1: 37}, "const"); + testNum(const {1: 37}.cast(), "const.cast"); + testNum(const {1: 37}.retype(), "const.retype"); - test(new UnmodifiableMapView({1: 37})); - test(new UnmodifiableMapView({1: 37})); + testNum(new UnmodifiableMapView({1: 37}), "unmod"); + testNum(new UnmodifiableMapView({1: 37}), "unmod.cast"); + testNum(new UnmodifiableMapView({1: 37}), "unmod.retype"); - test(new UnmodifiableMapView({1: 37}).cast()); - test(new UnmodifiableMapView({1: 37}).cast()); - test(new UnmodifiableMapView({1: 37}) - .cast()); - test(new UnmodifiableMapView({1: 37}) - .cast()); + testNum(new UnmodifiableMapView({1: 37}).cast(), + "unmodView.cast"); + testNum(new UnmodifiableMapView({1: 37}).cast(), + "unmodView.cast"); + testNum( + new UnmodifiableMapView({1: 37}) + .cast(), + "unmodView(num).cast"); + testNum( + new UnmodifiableMapView({1: 37}) + .cast(), + "unmodView(int).cast"); - test(new UnmodifiableMapView({1: 37}).retype()); - test(new UnmodifiableMapView({1: 37}).retype()); - test(new UnmodifiableMapView({1: 37}) - .retype()); - test(new UnmodifiableMapView({1: 37}) - .retype()); + testNum( + new UnmodifiableMapView({1: 37}).retype(), + "unmodView(num).retype"); + testNum( + new UnmodifiableMapView({1: 37}).retype(), + "unmodView(int).retype"); + testNum( + new UnmodifiableMapView({1: 37}) + .retype(), + "unmodView(num).retype"); + testNum( + new UnmodifiableMapView({1: 37}) + .retype(), + "unmodView(int).retype"); var m2 = new Map.unmodifiable({1: 37}); - test(m2); - test(m2.cast()); + testNum(m2, "Map.unmod"); + testNum(m2.cast(), "Map.unmod.cast"); + + Map nsm = new NsmMap().foo(a: 0); + test(nsm, #a, 0, "nsm"); + test(nsm.cast(), #a, 0, "nsm.cast"); + test(nsm.retype(), #a, 0, "nsm.retype"); } -void test(Map map) { - Expect.isTrue(map.containsKey(1)); - Expect.equals(1, map.length); - Expect.equals(1, map.keys.first); - Expect.equals(37, map.values.first); - - Expect.throws(map.clear); - Expect.throws(() { - map.remove(1); - }); - Expect.throws(() { - map[2] = 42; - }); - Expect.throws(() { - map.addAll({2: 42}); - }); +void testNum(Map map, String name) { + test(map, 1, 37, name); +} + +void test( + Map map, Object firstKey, Object firstValue, String name) { + Expect.isTrue(map.containsKey(firstKey), "$name.containsKey"); + Expect.equals(1, map.length, "$name.length"); + Expect.equals(firstKey, map.keys.first, "$name.keys.first"); + Expect.equals(firstValue, map.values.first, "$name.values.first"); + + Expect.throwsUnsupportedError(map.clear, "$name.clear"); + Expect.throwsUnsupportedError(() { + map.remove(firstKey); + }, "$name.remove"); + Expect.throwsUnsupportedError(() { + map[null] = null; + }, "$name[]="); + Expect.throwsUnsupportedError(() { + map.addAll({null: null}); + }, "$name.addAll"); +} + +class NsmMap { + noSuchMethod(i) => i.namedArguments; + foo({a, b, c, d}); }