diff --git a/CHANGELOG.md b/CHANGELOG.md index 91ac0114b37..4b0fabd4676 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,7 +21,9 @@ - **Breaking Change**: Non-`mixin` classes in the platform libraries can no longer be mixed in, unless they are explicitly marked as `mixin class`. The following existing classes have been made mixin classes: - * `IterableMixin` + * `Iterable` + * `IterableMixin` (now alias for `Iterable`) + * `IterableBase` (now alias for `Iterable`) * `ListMixin` * `SetMixin` * `MapMixin` diff --git a/pkg/front_end/testcases/general/constants/const_collections.dart.strong.expect b/pkg/front_end/testcases/general/constants/const_collections.dart.strong.expect index b8db0312f1d..0a1f2fb7260 100644 --- a/pkg/front_end/testcases/general/constants/const_collections.dart.strong.expect +++ b/pkg/front_end/testcases/general/constants/const_collections.dart.strong.expect @@ -180,14 +180,14 @@ library /*isNonNullableByDefault*/; // ^ // import self as self; -import "dart:collection" as col; import "dart:core" as core; +import "dart:collection" as col; import "dart:collection"; -class ConstIterable extends col::IterableBase /*hasConstConstructor*/ { +class ConstIterable extends core::Iterable /*hasConstConstructor*/ { const constructor •() → self::ConstIterable - : super col::IterableBase::•() + : super core::Iterable::•() ; get iterator() → core::Iterator return [].{core::Iterable::iterator}{core::Iterator}; @@ -201,9 +201,9 @@ class WithEquals extends core::Object /*hasConstConstructor*/ { return o is{ForNonNullableByDefault} self::WithEquals && (o{self::WithEquals} as{ForNonNullableByDefault} self::WithEquals).{self::WithEquals::i}{core::int} =={core::num::==}{(core::Object) → core::bool} this.{self::WithEquals::i}{core::int}; } } -class CustomIterable extends col::IterableBase /*hasConstConstructor*/ { +class CustomIterable extends core::Iterable /*hasConstConstructor*/ { const constructor •() → self::CustomIterable - : super col::IterableBase::•() + : super core::Iterable::•() ; get iterator() → core::Iterator return [].{core::Iterable::iterator}{core::Iterator}; @@ -383,7 +383,6 @@ constants { Constructor coverage from constants: org-dartlang-testcase:///const_collections.dart: - CustomIterable. (from org-dartlang-testcase:///const_collections.dart:79:9) -- IterableBase. (from org-dartlang-sdk:///sdk/lib/collection/iterable.dart) - Iterable. (from org-dartlang-sdk:///sdk/lib/core/iterable.dart) - Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart) - WithEquals. (from org-dartlang-testcase:///const_collections.dart:72:9) diff --git a/pkg/front_end/testcases/general/constants/const_collections.dart.strong.transformed.expect b/pkg/front_end/testcases/general/constants/const_collections.dart.strong.transformed.expect index cc9846de7b2..dfe7623c243 100644 --- a/pkg/front_end/testcases/general/constants/const_collections.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/general/constants/const_collections.dart.strong.transformed.expect @@ -180,14 +180,14 @@ library /*isNonNullableByDefault*/; // ^ // import self as self; -import "dart:collection" as col; import "dart:core" as core; +import "dart:collection" as col; import "dart:collection"; -class ConstIterable extends col::IterableBase /*hasConstConstructor*/ { +class ConstIterable extends core::Iterable /*hasConstConstructor*/ { const constructor •() → self::ConstIterable - : super col::IterableBase::•() + : super core::Iterable::•() ; get iterator() → core::Iterator return core::_GrowableList::•(0).{core::Iterable::iterator}{core::Iterator}; @@ -201,9 +201,9 @@ class WithEquals extends core::Object /*hasConstConstructor*/ { return o is{ForNonNullableByDefault} self::WithEquals && o{self::WithEquals}.{self::WithEquals::i}{core::int} =={core::num::==}{(core::Object) → core::bool} this.{self::WithEquals::i}{core::int}; } } -class CustomIterable extends col::IterableBase /*hasConstConstructor*/ { +class CustomIterable extends core::Iterable /*hasConstConstructor*/ { const constructor •() → self::CustomIterable - : super col::IterableBase::•() + : super core::Iterable::•() ; get iterator() → core::Iterator return core::_GrowableList::•(0).{core::Iterable::iterator}{core::Iterator}; @@ -383,7 +383,6 @@ constants { Constructor coverage from constants: org-dartlang-testcase:///const_collections.dart: - CustomIterable. (from org-dartlang-testcase:///const_collections.dart:79:9) -- IterableBase. (from org-dartlang-sdk:///sdk/lib/collection/iterable.dart) - Iterable. (from org-dartlang-sdk:///sdk/lib/core/iterable.dart) - Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart) - WithEquals. (from org-dartlang-testcase:///const_collections.dart:72:9) diff --git a/pkg/front_end/testcases/general/constants/const_collections.dart.weak.expect b/pkg/front_end/testcases/general/constants/const_collections.dart.weak.expect index fbd2858f4a1..6e718b8677e 100644 --- a/pkg/front_end/testcases/general/constants/const_collections.dart.weak.expect +++ b/pkg/front_end/testcases/general/constants/const_collections.dart.weak.expect @@ -180,14 +180,14 @@ library /*isNonNullableByDefault*/; // ^ // import self as self; -import "dart:collection" as col; import "dart:core" as core; +import "dart:collection" as col; import "dart:collection"; -class ConstIterable extends col::IterableBase /*hasConstConstructor*/ { +class ConstIterable extends core::Iterable /*hasConstConstructor*/ { const constructor •() → self::ConstIterable - : super col::IterableBase::•() + : super core::Iterable::•() ; get iterator() → core::Iterator return [].{core::Iterable::iterator}{core::Iterator}; @@ -201,9 +201,9 @@ class WithEquals extends core::Object /*hasConstConstructor*/ { return o is{ForNonNullableByDefault} self::WithEquals && (o{self::WithEquals} as{ForNonNullableByDefault} self::WithEquals).{self::WithEquals::i}{core::int} =={core::num::==}{(core::Object) → core::bool} this.{self::WithEquals::i}{core::int}; } } -class CustomIterable extends col::IterableBase /*hasConstConstructor*/ { +class CustomIterable extends core::Iterable /*hasConstConstructor*/ { const constructor •() → self::CustomIterable - : super col::IterableBase::•() + : super core::Iterable::•() ; get iterator() → core::Iterator return [].{core::Iterable::iterator}{core::Iterator}; @@ -383,7 +383,6 @@ constants { Constructor coverage from constants: org-dartlang-testcase:///const_collections.dart: - CustomIterable. (from org-dartlang-testcase:///const_collections.dart:79:9) -- IterableBase. (from org-dartlang-sdk:///sdk/lib/collection/iterable.dart) - Iterable. (from org-dartlang-sdk:///sdk/lib/core/iterable.dart) - Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart) - WithEquals. (from org-dartlang-testcase:///const_collections.dart:72:9) diff --git a/pkg/front_end/testcases/general/constants/const_collections.dart.weak.modular.expect b/pkg/front_end/testcases/general/constants/const_collections.dart.weak.modular.expect index fbd2858f4a1..6e718b8677e 100644 --- a/pkg/front_end/testcases/general/constants/const_collections.dart.weak.modular.expect +++ b/pkg/front_end/testcases/general/constants/const_collections.dart.weak.modular.expect @@ -180,14 +180,14 @@ library /*isNonNullableByDefault*/; // ^ // import self as self; -import "dart:collection" as col; import "dart:core" as core; +import "dart:collection" as col; import "dart:collection"; -class ConstIterable extends col::IterableBase /*hasConstConstructor*/ { +class ConstIterable extends core::Iterable /*hasConstConstructor*/ { const constructor •() → self::ConstIterable - : super col::IterableBase::•() + : super core::Iterable::•() ; get iterator() → core::Iterator return [].{core::Iterable::iterator}{core::Iterator}; @@ -201,9 +201,9 @@ class WithEquals extends core::Object /*hasConstConstructor*/ { return o is{ForNonNullableByDefault} self::WithEquals && (o{self::WithEquals} as{ForNonNullableByDefault} self::WithEquals).{self::WithEquals::i}{core::int} =={core::num::==}{(core::Object) → core::bool} this.{self::WithEquals::i}{core::int}; } } -class CustomIterable extends col::IterableBase /*hasConstConstructor*/ { +class CustomIterable extends core::Iterable /*hasConstConstructor*/ { const constructor •() → self::CustomIterable - : super col::IterableBase::•() + : super core::Iterable::•() ; get iterator() → core::Iterator return [].{core::Iterable::iterator}{core::Iterator}; @@ -383,7 +383,6 @@ constants { Constructor coverage from constants: org-dartlang-testcase:///const_collections.dart: - CustomIterable. (from org-dartlang-testcase:///const_collections.dart:79:9) -- IterableBase. (from org-dartlang-sdk:///sdk/lib/collection/iterable.dart) - Iterable. (from org-dartlang-sdk:///sdk/lib/core/iterable.dart) - Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart) - WithEquals. (from org-dartlang-testcase:///const_collections.dart:72:9) diff --git a/pkg/front_end/testcases/general/constants/const_collections.dart.weak.outline.expect b/pkg/front_end/testcases/general/constants/const_collections.dart.weak.outline.expect index c83eee41f4e..0bb7aa2d881 100644 --- a/pkg/front_end/testcases/general/constants/const_collections.dart.weak.outline.expect +++ b/pkg/front_end/testcases/general/constants/const_collections.dart.weak.outline.expect @@ -37,14 +37,13 @@ library /*isNonNullableByDefault*/; // ^ // import self as self; -import "dart:collection" as col; import "dart:core" as core; import "dart:collection"; -class ConstIterable extends col::IterableBase /*hasConstConstructor*/ { +class ConstIterable extends core::Iterable /*hasConstConstructor*/ { const constructor •() → self::ConstIterable - : super col::IterableBase::•() + : super core::Iterable::•() ; get iterator() → core::Iterator ; @@ -57,9 +56,9 @@ class WithEquals extends core::Object /*hasConstConstructor*/ { operator ==(core::Object o) → core::bool ; } -class CustomIterable extends col::IterableBase /*hasConstConstructor*/ { +class CustomIterable extends core::Iterable /*hasConstConstructor*/ { const constructor •() → self::CustomIterable - : super col::IterableBase::•() + : super core::Iterable::•() ; get iterator() → core::Iterator ; diff --git a/pkg/front_end/testcases/general/constants/const_collections.dart.weak.transformed.expect b/pkg/front_end/testcases/general/constants/const_collections.dart.weak.transformed.expect index 454355d1f3a..9b315897e80 100644 --- a/pkg/front_end/testcases/general/constants/const_collections.dart.weak.transformed.expect +++ b/pkg/front_end/testcases/general/constants/const_collections.dart.weak.transformed.expect @@ -180,14 +180,14 @@ library /*isNonNullableByDefault*/; // ^ // import self as self; -import "dart:collection" as col; import "dart:core" as core; +import "dart:collection" as col; import "dart:collection"; -class ConstIterable extends col::IterableBase /*hasConstConstructor*/ { +class ConstIterable extends core::Iterable /*hasConstConstructor*/ { const constructor •() → self::ConstIterable - : super col::IterableBase::•() + : super core::Iterable::•() ; get iterator() → core::Iterator return core::_GrowableList::•(0).{core::Iterable::iterator}{core::Iterator}; @@ -201,9 +201,9 @@ class WithEquals extends core::Object /*hasConstConstructor*/ { return o is{ForNonNullableByDefault} self::WithEquals && o{self::WithEquals}.{self::WithEquals::i}{core::int} =={core::num::==}{(core::Object) → core::bool} this.{self::WithEquals::i}{core::int}; } } -class CustomIterable extends col::IterableBase /*hasConstConstructor*/ { +class CustomIterable extends core::Iterable /*hasConstConstructor*/ { const constructor •() → self::CustomIterable - : super col::IterableBase::•() + : super core::Iterable::•() ; get iterator() → core::Iterator return core::_GrowableList::•(0).{core::Iterable::iterator}{core::Iterator}; @@ -383,7 +383,6 @@ constants { Constructor coverage from constants: org-dartlang-testcase:///const_collections.dart: - CustomIterable. (from org-dartlang-testcase:///const_collections.dart:79:9) -- IterableBase. (from org-dartlang-sdk:///sdk/lib/collection/iterable.dart) - Iterable. (from org-dartlang-sdk:///sdk/lib/core/iterable.dart) - Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart) - WithEquals. (from org-dartlang-testcase:///const_collections.dart:72:9) diff --git a/pkg/front_end/testcases/general/sdk_diagnostic.dart.strong.expect b/pkg/front_end/testcases/general/sdk_diagnostic.dart.strong.expect index 20c715f6dc8..78eea88887e 100644 --- a/pkg/front_end/testcases/general/sdk_diagnostic.dart.strong.expect +++ b/pkg/front_end/testcases/general/sdk_diagnostic.dart.strong.expect @@ -12,7 +12,7 @@ library /*isNonNullableByDefault*/; // // class C extends Iterable { // ^ -// sdk/lib/core/iterable.dart:148:19: Context: 'Iterable.iterator' is defined here. +// sdk/lib/core/iterable.dart:169:19: Context: 'Iterable.iterator' is defined here. // Iterator get iterator; // ^^^^^^^^ // diff --git a/pkg/front_end/testcases/general/sdk_diagnostic.dart.strong.transformed.expect b/pkg/front_end/testcases/general/sdk_diagnostic.dart.strong.transformed.expect index 20c715f6dc8..78eea88887e 100644 --- a/pkg/front_end/testcases/general/sdk_diagnostic.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/general/sdk_diagnostic.dart.strong.transformed.expect @@ -12,7 +12,7 @@ library /*isNonNullableByDefault*/; // // class C extends Iterable { // ^ -// sdk/lib/core/iterable.dart:148:19: Context: 'Iterable.iterator' is defined here. +// sdk/lib/core/iterable.dart:169:19: Context: 'Iterable.iterator' is defined here. // Iterator get iterator; // ^^^^^^^^ // diff --git a/pkg/front_end/testcases/general/sdk_diagnostic.dart.weak.expect b/pkg/front_end/testcases/general/sdk_diagnostic.dart.weak.expect index 20c715f6dc8..78eea88887e 100644 --- a/pkg/front_end/testcases/general/sdk_diagnostic.dart.weak.expect +++ b/pkg/front_end/testcases/general/sdk_diagnostic.dart.weak.expect @@ -12,7 +12,7 @@ library /*isNonNullableByDefault*/; // // class C extends Iterable { // ^ -// sdk/lib/core/iterable.dart:148:19: Context: 'Iterable.iterator' is defined here. +// sdk/lib/core/iterable.dart:169:19: Context: 'Iterable.iterator' is defined here. // Iterator get iterator; // ^^^^^^^^ // diff --git a/pkg/front_end/testcases/general/sdk_diagnostic.dart.weak.modular.expect b/pkg/front_end/testcases/general/sdk_diagnostic.dart.weak.modular.expect index 20c715f6dc8..78eea88887e 100644 --- a/pkg/front_end/testcases/general/sdk_diagnostic.dart.weak.modular.expect +++ b/pkg/front_end/testcases/general/sdk_diagnostic.dart.weak.modular.expect @@ -12,7 +12,7 @@ library /*isNonNullableByDefault*/; // // class C extends Iterable { // ^ -// sdk/lib/core/iterable.dart:148:19: Context: 'Iterable.iterator' is defined here. +// sdk/lib/core/iterable.dart:169:19: Context: 'Iterable.iterator' is defined here. // Iterator get iterator; // ^^^^^^^^ // diff --git a/pkg/front_end/testcases/general/sdk_diagnostic.dart.weak.outline.expect b/pkg/front_end/testcases/general/sdk_diagnostic.dart.weak.outline.expect index b08de4bc13c..e081d7b3323 100644 --- a/pkg/front_end/testcases/general/sdk_diagnostic.dart.weak.outline.expect +++ b/pkg/front_end/testcases/general/sdk_diagnostic.dart.weak.outline.expect @@ -12,7 +12,7 @@ library /*isNonNullableByDefault*/; // // class C extends Iterable { // ^ -// sdk/lib/core/iterable.dart:148:19: Context: 'Iterable.iterator' is defined here. +// sdk/lib/core/iterable.dart:169:19: Context: 'Iterable.iterator' is defined here. // Iterator get iterator; // ^^^^^^^^ // diff --git a/pkg/front_end/testcases/general/sdk_diagnostic.dart.weak.transformed.expect b/pkg/front_end/testcases/general/sdk_diagnostic.dart.weak.transformed.expect index 20c715f6dc8..78eea88887e 100644 --- a/pkg/front_end/testcases/general/sdk_diagnostic.dart.weak.transformed.expect +++ b/pkg/front_end/testcases/general/sdk_diagnostic.dart.weak.transformed.expect @@ -12,7 +12,7 @@ library /*isNonNullableByDefault*/; // // class C extends Iterable { // ^ -// sdk/lib/core/iterable.dart:148:19: Context: 'Iterable.iterator' is defined here. +// sdk/lib/core/iterable.dart:169:19: Context: 'Iterable.iterator' is defined here. // Iterator get iterator; // ^^^^^^^^ // diff --git a/pkg/front_end/testcases/incremental/no_outline_change_22.yaml.world.1.expect b/pkg/front_end/testcases/incremental/no_outline_change_22.yaml.world.1.expect index 47243c0fa0d..3ee33183297 100644 --- a/pkg/front_end/testcases/incremental/no_outline_change_22.yaml.world.1.expect +++ b/pkg/front_end/testcases/incremental/no_outline_change_22.yaml.world.1.expect @@ -514,7 +514,7 @@ library from "org-dartlang-test:///main.dart" as main { return dart.core::Comparable::compare(a as{ForNonNullableByDefault} dart.core::Comparable, b as{ForNonNullableByDefault} dart.core::Comparable); } static method /* from org-dartlang-sdk:///sdk/lib/collection/list.dart */ listToString(dart.core::List list) → dart.core::String - return dart.collection::IterableBase::iterableToFullString(list, "[", "]"); + return dart.core::Iterable::iterableToFullString(list, "[", "]"); } class WithListMixin extends main::_WithListMixin&Object&ListMixin { field dart.core::int length = 2; diff --git a/pkg/front_end/testcases/incremental/no_outline_change_22.yaml.world.2.expect b/pkg/front_end/testcases/incremental/no_outline_change_22.yaml.world.2.expect index 47243c0fa0d..3ee33183297 100644 --- a/pkg/front_end/testcases/incremental/no_outline_change_22.yaml.world.2.expect +++ b/pkg/front_end/testcases/incremental/no_outline_change_22.yaml.world.2.expect @@ -514,7 +514,7 @@ library from "org-dartlang-test:///main.dart" as main { return dart.core::Comparable::compare(a as{ForNonNullableByDefault} dart.core::Comparable, b as{ForNonNullableByDefault} dart.core::Comparable); } static method /* from org-dartlang-sdk:///sdk/lib/collection/list.dart */ listToString(dart.core::List list) → dart.core::String - return dart.collection::IterableBase::iterableToFullString(list, "[", "]"); + return dart.core::Iterable::iterableToFullString(list, "[", "]"); } class WithListMixin extends main::_WithListMixin&Object&ListMixin { field dart.core::int length = 2; diff --git a/pkg/front_end/testcases/patterns/cache_lookups.dart.strong.transformed.expect b/pkg/front_end/testcases/patterns/cache_lookups.dart.strong.transformed.expect index d4fb3999cc6..90964c775e9 100644 --- a/pkg/front_end/testcases/patterns/cache_lookups.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/patterns/cache_lookups.dart.strong.transformed.expect @@ -589,7 +589,7 @@ abstract class _CustomList&Object&ListMixin e return core::Comparable::compare(a as{ForNonNullableByDefault} core::Comparable, b as{ForNonNullableByDefault} core::Comparable); } static method /* from org-dartlang-sdk:///sdk/lib/collection/list.dart */ listToString(core::List list) → core::String - return col::IterableBase::iterableToFullString(list, "[", "]"); + return core::Iterable::iterableToFullString(list, "[", "]"); } class CustomList extends cac::_CustomList&Object&ListMixin { final field core::List list; diff --git a/pkg/front_end/testcases/patterns/cache_lookups.dart.weak.transformed.expect b/pkg/front_end/testcases/patterns/cache_lookups.dart.weak.transformed.expect index f7b2c9ab3ab..0ce369f137d 100644 --- a/pkg/front_end/testcases/patterns/cache_lookups.dart.weak.transformed.expect +++ b/pkg/front_end/testcases/patterns/cache_lookups.dart.weak.transformed.expect @@ -589,7 +589,7 @@ abstract class _CustomList&Object&ListMixin e return core::Comparable::compare(a as{ForNonNullableByDefault} core::Comparable, b as{ForNonNullableByDefault} core::Comparable); } static method /* from org-dartlang-sdk:///sdk/lib/collection/list.dart */ listToString(core::List list) → core::String - return col::IterableBase::iterableToFullString(list, "[", "]"); + return core::Iterable::iterableToFullString(list, "[", "]"); } class CustomList extends cac::_CustomList&Object&ListMixin { final field core::List list; diff --git a/pkg/front_end/testcases/patterns/caching_constants.dart.strong.transformed.expect b/pkg/front_end/testcases/patterns/caching_constants.dart.strong.transformed.expect index 392d1ca5b24..f19c8b42bde 100644 --- a/pkg/front_end/testcases/patterns/caching_constants.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/patterns/caching_constants.dart.strong.transformed.expect @@ -2,6 +2,7 @@ library /*isNonNullableByDefault*/; import self as self; import "dart:core" as core; import "dart:collection" as col; +import "dart:_internal" as _in; import "dart:collection"; @@ -134,12 +135,12 @@ abstract class _MyMap&Object&MapMixin m) → core::String { - if(col::_isToStringVisiting(m)) { + if(_in::isToStringVisiting(m)) { return "{...}"; } core::StringBuffer result = new core::StringBuffer::•(); try { - col::_toStringVisiting.{core::List::add}(m){(core::Object) → void}; + _in::toStringVisiting.{core::List::add}(m){(core::Object) → void}; result.{core::StringBuffer::write}("{"){(core::Object?) → void}; core::bool first = true; m.{core::Map::forEach}((core::Object? k, core::Object? v) → void { @@ -154,8 +155,8 @@ abstract class _MyMap&Object&MapMixin m) → core::String { - if(col::_isToStringVisiting(m)) { + if(_in::isToStringVisiting(m)) { return "{...}"; } core::StringBuffer result = new core::StringBuffer::•(); try { - col::_toStringVisiting.{core::List::add}(m){(core::Object) → void}; + _in::toStringVisiting.{core::List::add}(m){(core::Object) → void}; result.{core::StringBuffer::write}("{"){(core::Object?) → void}; core::bool first = true; m.{core::Map::forEach}((core::Object? k, core::Object? v) → void { @@ -154,8 +155,8 @@ abstract class _MyMap&Object&MapMixin, b as{ForNonNullableByDefault} core::Comparable); } static method /* from org-dartlang-sdk:///sdk/lib/collection/list.dart */ listToString(core::List list) → core::String - return col::IterableBase::iterableToFullString(list, "[", "]"); + return core::Iterable::iterableToFullString(list, "[", "]"); } class A extends self::_A&Object&ListMixin { field core::int count = 0; diff --git a/pkg/front_end/testcases/patterns/matching_and_capturing_accesses_list_element_once.dart.weak.transformed.expect b/pkg/front_end/testcases/patterns/matching_and_capturing_accesses_list_element_once.dart.weak.transformed.expect index 30337eaa12e..04e05873c55 100644 --- a/pkg/front_end/testcases/patterns/matching_and_capturing_accesses_list_element_once.dart.weak.transformed.expect +++ b/pkg/front_end/testcases/patterns/matching_and_capturing_accesses_list_element_once.dart.weak.transformed.expect @@ -518,7 +518,7 @@ abstract class _A&Object&ListMixin extends core::Object implements col::ListBase return core::Comparable::compare(a as{ForNonNullableByDefault} core::Comparable, b as{ForNonNullableByDefault} core::Comparable); } static method /* from org-dartlang-sdk:///sdk/lib/collection/list.dart */ listToString(core::List list) → core::String - return col::IterableBase::iterableToFullString(list, "[", "]"); + return core::Iterable::iterableToFullString(list, "[", "]"); } class A extends self::_A&Object&ListMixin { field core::int count = 0; diff --git a/pkg/front_end/testcases/patterns/negative_length.dart.strong.transformed.expect b/pkg/front_end/testcases/patterns/negative_length.dart.strong.transformed.expect index 4b6d539a5cf..c7aaf2be0ce 100644 --- a/pkg/front_end/testcases/patterns/negative_length.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/patterns/negative_length.dart.strong.transformed.expect @@ -518,7 +518,7 @@ abstract class _NegativeLengthList&Object&ListMixin, b as{ForNonNullableByDefault} core::Comparable); } static method /* from org-dartlang-sdk:///sdk/lib/collection/list.dart */ listToString(core::List list) → core::String - return col::IterableBase::iterableToFullString(list, "[", "]"); + return core::Iterable::iterableToFullString(list, "[", "]"); } class NegativeLengthList extends self::_NegativeLengthList&Object&ListMixin { final field core::List _list; diff --git a/pkg/front_end/testcases/patterns/negative_length.dart.weak.transformed.expect b/pkg/front_end/testcases/patterns/negative_length.dart.weak.transformed.expect index e297255e10f..d3c97a86829 100644 --- a/pkg/front_end/testcases/patterns/negative_length.dart.weak.transformed.expect +++ b/pkg/front_end/testcases/patterns/negative_length.dart.weak.transformed.expect @@ -518,7 +518,7 @@ abstract class _NegativeLengthList&Object&ListMixin, b as{ForNonNullableByDefault} core::Comparable); } static method /* from org-dartlang-sdk:///sdk/lib/collection/list.dart */ listToString(core::List list) → core::String - return col::IterableBase::iterableToFullString(list, "[", "]"); + return core::Iterable::iterableToFullString(list, "[", "]"); } class NegativeLengthList extends self::_NegativeLengthList&Object&ListMixin { final field core::List _list; diff --git a/runtime/observatory/tests/service/sdk_break_with_mixin_test.dart b/runtime/observatory/tests/service/sdk_break_with_mixin_test.dart index eaaa0568700..785e0ddf16a 100644 --- a/runtime/observatory/tests/service/sdk_break_with_mixin_test.dart +++ b/runtime/observatory/tests/service/sdk_break_with_mixin_test.dart @@ -36,7 +36,7 @@ List stops = []; // THIS TEST DEPENDS ON SPECIFIC LINE NUMBERS IN UNRELATED PLATFORM LIBRARIES // STAYING FIXED. VERY FRAGILE. SHOULD BE FIXED OR REMOVED. List expected = [ - "set.dart:142:23 (sdk_break_with_mixin_test.dart:20:5)", + "set.dart:142:21 (sdk_break_with_mixin_test.dart:20:5)", ]; var tests = [ diff --git a/runtime/observatory_2/tests/service_2/sdk_break_with_mixin_test.dart b/runtime/observatory_2/tests/service_2/sdk_break_with_mixin_test.dart index d7b87cae42f..a5ab4496efd 100644 --- a/runtime/observatory_2/tests/service_2/sdk_break_with_mixin_test.dart +++ b/runtime/observatory_2/tests/service_2/sdk_break_with_mixin_test.dart @@ -35,7 +35,7 @@ class MySet extends Object with SetMixin { List stops = []; List expected = [ - "set.dart:142:23 (sdk_break_with_mixin_test.dart:21:5)", + "set.dart:142:21 (sdk_break_with_mixin_test.dart:21:5)", ]; var tests = [ diff --git a/sdk/lib/_internal/js_dev_runtime/private/js_helper.dart b/sdk/lib/_internal/js_dev_runtime/private/js_helper.dart index 344b247a4b0..e303cd9febb 100644 --- a/sdk/lib/_internal/js_dev_runtime/private/js_helper.dart +++ b/sdk/lib/_internal/js_dev_runtime/private/js_helper.dart @@ -53,7 +53,7 @@ class DartIterator implements Iterator { } /// Used to compile `sync*`. -class SyncIterable extends IterableBase { +class SyncIterable extends Iterable { final Function() _initGenerator; SyncIterable(this._initGenerator); diff --git a/sdk/lib/_internal/js_dev_runtime/private/regexp_helper.dart b/sdk/lib/_internal/js_dev_runtime/private/regexp_helper.dart index 64af42d3763..15f05b56e06 100644 --- a/sdk/lib/_internal/js_dev_runtime/private/regexp_helper.dart +++ b/sdk/lib/_internal/js_dev_runtime/private/regexp_helper.dart @@ -230,7 +230,7 @@ class _MatchImplementation implements RegExpMatch { } } -class _AllMatchesIterable extends IterableBase { +class _AllMatchesIterable extends Iterable { final JSSyntaxRegExp _re; final String _string; final int _start; diff --git a/sdk/lib/_internal/js_runtime/lib/async_patch.dart b/sdk/lib/_internal/js_runtime/lib/async_patch.dart index b2fcf453979..e731cb4897f 100644 --- a/sdk/lib/_internal/js_runtime/lib/async_patch.dart +++ b/sdk/lib/_internal/js_runtime/lib/async_patch.dart @@ -18,8 +18,6 @@ import 'dart:_foreign_helper' show JS, JS_GET_FLAG; import 'dart:_async_await_error_codes' as async_error_codes; -import "dart:collection" show IterableBase; - @patch class _AsyncRun { @patch @@ -686,7 +684,7 @@ _SyncStarIterable _makeSyncStarIterable(body) { /// An Iterable corresponding to a sync* method. /// /// Each invocation of a sync* method will return a new instance of this class. -class _SyncStarIterable extends IterableBase { +class _SyncStarIterable extends Iterable { // This is a function that will return a helper function that does the // iteration of the sync*. // diff --git a/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart b/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart index 4ba4ae51859..ef52926cc69 100644 --- a/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart +++ b/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart @@ -230,7 +230,7 @@ class _MatchImplementation implements RegExpMatch { } } -class _AllMatchesIterable extends IterableBase { +class _AllMatchesIterable extends Iterable { final JSSyntaxRegExp _re; final String _string; final int _start; diff --git a/sdk/lib/_internal/vm/lib/core_patch.dart b/sdk/lib/_internal/vm/lib/core_patch.dart index 7833080335d..0bc6e082354 100644 --- a/sdk/lib/_internal/vm/lib/core_patch.dart +++ b/sdk/lib/_internal/vm/lib/core_patch.dart @@ -42,7 +42,6 @@ import "dart:async" show Completer, DeferredLoadException, Future, Timer, Zone; import "dart:collection" show HashMap, - IterableBase, LinkedHashMap, LinkedList, LinkedListEntry, diff --git a/sdk/lib/_internal/vm/lib/regexp_patch.dart b/sdk/lib/_internal/vm/lib/regexp_patch.dart index d906954d7c8..cc25bcf9aea 100644 --- a/sdk/lib/_internal/vm/lib/regexp_patch.dart +++ b/sdk/lib/_internal/vm/lib/regexp_patch.dart @@ -323,7 +323,7 @@ class _RegExp implements RegExp { Int32List(_initialBacktrackingStackSize); } -class _AllMatchesIterable extends IterableBase { +class _AllMatchesIterable extends Iterable { final _RegExp _re; final String _str; final int _start; diff --git a/sdk/lib/_internal/wasm/lib/core_patch.dart b/sdk/lib/_internal/wasm/lib/core_patch.dart index 19784e4598a..4f95ee3a80b 100644 --- a/sdk/lib/_internal/wasm/lib/core_patch.dart +++ b/sdk/lib/_internal/wasm/lib/core_patch.dart @@ -35,7 +35,6 @@ import 'dart:_js_helper' show JS, JSSyntaxRegExp, quoteStringForRegExp; import "dart:collection" show HashMap, - IterableBase, LinkedHashMap, LinkedList, LinkedListEntry, diff --git a/sdk/lib/_internal/wasm/lib/regexp_helper.dart b/sdk/lib/_internal/wasm/lib/regexp_helper.dart index 89e4922ba27..11a7b57f29a 100644 --- a/sdk/lib/_internal/wasm/lib/regexp_helper.dart +++ b/sdk/lib/_internal/wasm/lib/regexp_helper.dart @@ -219,7 +219,7 @@ class _MatchImplementation implements RegExpMatch { } } -class _AllMatchesIterable extends IterableBase { +class _AllMatchesIterable extends Iterable { final JSSyntaxRegExp _re; final String _string; final int _start; diff --git a/sdk/lib/collection/iterable.dart b/sdk/lib/collection/iterable.dart index 340c093bebf..d062dd60ca4 100644 --- a/sdk/lib/collection/iterable.dart +++ b/sdk/lib/collection/iterable.dart @@ -7,396 +7,12 @@ part of dart.collection; /// This [Iterable] mixin implements all [Iterable] members except `iterator`. /// /// All other methods are implemented in terms of `iterator`. -abstract mixin class IterableMixin implements Iterable { - // This class has methods copied verbatim into: - // - IterableBase - // - SetMixin - // If changing a method here, also change the other copies. - - Iterable cast() => Iterable.castFrom(this); - Iterable map(T toElement(E element)) => - MappedIterable(this, toElement); - - Iterable where(bool test(E element)) => WhereIterable(this, test); - - Iterable whereType() => WhereTypeIterable(this); - - Iterable expand(Iterable toElements(E element)) => - ExpandIterable(this, toElements); - - Iterable followedBy(Iterable other) { - // Type workaround because IterableMixin doesn't promote - // to EfficientLengthIterable. - Iterable self = this; - if (self is EfficientLengthIterable) { - return FollowedByIterable.firstEfficient(self, other); - } - return FollowedByIterable(this, other); - } - - bool contains(Object? element) { - for (E e in this) { - if (e == element) return true; - } - return false; - } - - void forEach(void action(E element)) { - for (E element in this) action(element); - } - - E reduce(E combine(E value, E element)) { - Iterator iterator = this.iterator; - if (!iterator.moveNext()) { - throw IterableElementError.noElement(); - } - E value = iterator.current; - while (iterator.moveNext()) { - value = combine(value, iterator.current); - } - return value; - } - - T fold(T initialValue, T combine(T previousValue, E element)) { - var value = initialValue; - for (E element in this) value = combine(value, element); - return value; - } - - bool every(bool test(E element)) { - for (E element in this) { - if (!test(element)) return false; - } - return true; - } - - String join([String separator = ""]) { - Iterator iterator = this.iterator; - if (!iterator.moveNext()) return ""; - StringBuffer buffer = StringBuffer(); - if (separator == null || separator == "") { - do { - buffer.write("${iterator.current}"); - } while (iterator.moveNext()); - } else { - buffer.write("${iterator.current}"); - while (iterator.moveNext()) { - buffer.write(separator); - buffer.write("${iterator.current}"); - } - } - return buffer.toString(); - } - - bool any(bool test(E element)) { - for (E element in this) { - if (test(element)) return true; - } - return false; - } - - List toList({bool growable = true}) => - List.from(this, growable: growable); - - Set toSet() => Set.from(this); - - int get length { - assert(this is! EfficientLengthIterable); - int count = 0; - Iterator it = iterator; - while (it.moveNext()) { - count++; - } - return count; - } - - bool get isEmpty => !iterator.moveNext(); - - bool get isNotEmpty => !isEmpty; - - Iterable take(int count) { - return TakeIterable(this, count); - } - - Iterable takeWhile(bool test(E value)) { - return TakeWhileIterable(this, test); - } - - Iterable skip(int count) { - return SkipIterable(this, count); - } - - Iterable skipWhile(bool test(E value)) { - return SkipWhileIterable(this, test); - } - - E get first { - Iterator it = iterator; - if (!it.moveNext()) { - throw IterableElementError.noElement(); - } - return it.current; - } - - E get last { - Iterator it = iterator; - if (!it.moveNext()) { - throw IterableElementError.noElement(); - } - E result; - do { - result = it.current; - } while (it.moveNext()); - return result; - } - - E get single { - Iterator it = iterator; - if (!it.moveNext()) throw IterableElementError.noElement(); - E result = it.current; - if (it.moveNext()) throw IterableElementError.tooMany(); - return result; - } - - E firstWhere(bool test(E value), {E Function()? orElse}) { - for (E element in this) { - if (test(element)) return element; - } - if (orElse != null) return orElse(); - throw IterableElementError.noElement(); - } - - E lastWhere(bool test(E value), {E Function()? orElse}) { - late E result; - bool foundMatching = false; - for (E element in this) { - if (test(element)) { - result = element; - foundMatching = true; - } - } - if (foundMatching) return result; - if (orElse != null) return orElse(); - throw IterableElementError.noElement(); - } - - E singleWhere(bool test(E element), {E Function()? orElse}) { - late E result; - bool foundMatching = false; - for (E element in this) { - if (test(element)) { - if (foundMatching) { - throw IterableElementError.tooMany(); - } - result = element; - foundMatching = true; - } - } - if (foundMatching) return result; - if (orElse != null) return orElse(); - throw IterableElementError.noElement(); - } - - E elementAt(int index) { - checkNotNullable(index, "index"); - RangeError.checkNotNegative(index, "index"); - int elementIndex = 0; - for (E element in this) { - if (index == elementIndex) return element; - elementIndex++; - } - throw IndexError.withLength(index, elementIndex, - indexable: this, name: "index"); - } - - String toString() => IterableBase.iterableToShortString(this, '(', ')'); -} +// @Deprecated("Use Iterable instead") +typedef IterableMixin = Iterable; /// Base class for implementing [Iterable]. /// /// This class implements all methods of [Iterable], except [Iterable.iterator], /// in terms of `iterator`. -abstract class IterableBase extends Iterable { - const IterableBase(); - - /// Convert an `Iterable` to a string like [IterableBase.toString]. - /// - /// Allows using other delimiters than '(' and ')'. - /// - /// Handles circular references where converting one of the elements - /// to a string ends up converting [iterable] to a string again. - static String iterableToShortString(Iterable iterable, - [String leftDelimiter = '(', String rightDelimiter = ')']) { - if (_isToStringVisiting(iterable)) { - if (leftDelimiter == "(" && rightDelimiter == ")") { - // Avoid creating a new string in the "common" case. - return "(...)"; - } - return "$leftDelimiter...$rightDelimiter"; - } - List parts = []; - _toStringVisiting.add(iterable); - try { - _iterablePartsToStrings(iterable, parts); - } finally { - assert(identical(_toStringVisiting.last, iterable)); - _toStringVisiting.removeLast(); - } - return (StringBuffer(leftDelimiter) - ..writeAll(parts, ", ") - ..write(rightDelimiter)) - .toString(); - } - - /// Converts an `Iterable` to a string. - /// - /// Converts each elements to a string, and separates the results by ", ". - /// Then wraps the result in [leftDelimiter] and [rightDelimiter]. - /// - /// Unlike [iterableToShortString], this conversion doesn't omit any - /// elements or puts any limit on the size of the result. - /// - /// Handles circular references where converting one of the elements - /// to a string ends up converting [iterable] to a string again. - static String iterableToFullString(Iterable iterable, - [String leftDelimiter = '(', String rightDelimiter = ')']) { - if (_isToStringVisiting(iterable)) { - return "$leftDelimiter...$rightDelimiter"; - } - StringBuffer buffer = StringBuffer(leftDelimiter); - _toStringVisiting.add(iterable); - try { - buffer.writeAll(iterable, ", "); - } finally { - assert(identical(_toStringVisiting.last, iterable)); - _toStringVisiting.removeLast(); - } - buffer.write(rightDelimiter); - return buffer.toString(); - } -} - -/// A collection used to identify cyclic lists during toString() calls. -final List _toStringVisiting = []; - -/// Check if we are currently visiting `o` in a toString call. -bool _isToStringVisiting(Object o) { - for (int i = 0; i < _toStringVisiting.length; i++) { - if (identical(o, _toStringVisiting[i])) return true; - } - return false; -} - -/// Convert elements of [iterable] to strings and store them in [parts]. -void _iterablePartsToStrings(Iterable iterable, List parts) { - /* - * This is the complicated part of [iterableToShortString]. - * It is extracted as a separate function to avoid having too much code - * inside the try/finally. - */ - /// Try to stay below this many characters. - const int lengthLimit = 80; - - /// Always at least this many elements at the start. - const int headCount = 3; - - /// Always at least this many elements at the end. - const int tailCount = 2; - - /// Stop iterating after this many elements. Iterables can be infinite. - const int maxCount = 100; - // Per entry length overhead. It's for ", " for all after the first entry, - // and for "(" and ")" for the initial entry. By pure luck, that's the same - // number. - const int overhead = 2; - const int ellipsisSize = 3; // "...".length. - - int length = 0; - int count = 0; - Iterator it = iterable.iterator; - // Initial run of elements, at least headCount, and then continue until - // passing at most lengthLimit characters. - while (length < lengthLimit || count < headCount) { - if (!it.moveNext()) return; - String next = "${it.current}"; - parts.add(next); - length += next.length + overhead; - count++; - } - - String penultimateString; - String ultimateString; - - // Find last two elements. One or more of them may already be in the - // parts array. Include their length in `length`. - if (!it.moveNext()) { - if (count <= headCount + tailCount) return; - ultimateString = parts.removeLast(); - penultimateString = parts.removeLast(); - } else { - Object? penultimate = it.current; - count++; - if (!it.moveNext()) { - if (count <= headCount + 1) { - parts.add("$penultimate"); - return; - } - ultimateString = "$penultimate"; - penultimateString = parts.removeLast(); - length += ultimateString.length + overhead; - } else { - Object? ultimate = it.current; - count++; - // Then keep looping, keeping the last two elements in variables. - assert(count < maxCount); - while (it.moveNext()) { - penultimate = ultimate; - ultimate = it.current; - count++; - if (count > maxCount) { - // If we haven't found the end before maxCount, give up. - // This cannot happen in the code above because each entry - // increases length by at least two, so there is no way to - // visit more than ~40 elements before this loop. - - // Remove any surplus elements until length, including ", ...)", - // is at most lengthLimit. - while (length > lengthLimit - ellipsisSize - overhead && - count > headCount) { - length -= parts.removeLast().length + overhead; - count--; - } - parts.add("..."); - return; - } - } - penultimateString = "$penultimate"; - ultimateString = "$ultimate"; - length += ultimateString.length + penultimateString.length + 2 * overhead; - } - } - - // If there is a gap between the initial run and the last two, - // prepare to add an ellipsis. - String? elision; - if (count > parts.length + tailCount) { - elision = "..."; - length += ellipsisSize + overhead; - } - - // If the last two elements were very long, and we have more than - // headCount elements in the initial run, drop some to make room for - // the last two. - while (length > lengthLimit && parts.length > headCount) { - length -= parts.removeLast().length + overhead; - if (elision == null) { - elision = "..."; - length += ellipsisSize + overhead; - } - } - if (elision != null) { - parts.add(elision); - } - parts.add(penultimateString); - parts.add(ultimateString); -} +// @Deprecated("Use Iterable instead") +typedef IterableBase = Iterable; diff --git a/sdk/lib/collection/maps.dart b/sdk/lib/collection/maps.dart index 793e11e5ea4..b217e2d07e2 100644 --- a/sdk/lib/collection/maps.dart +++ b/sdk/lib/collection/maps.dart @@ -109,14 +109,14 @@ abstract mixin class MapBase implements Map { String toString() => mapToString(this); static String mapToString(Map m) { - // Reuses the list in IterableBase for detecting toString cycles. - if (_isToStringVisiting(m)) { + // Reuses the list used by Iterable for detecting toString cycles. + if (isToStringVisiting(m)) { return '{...}'; } var result = StringBuffer(); try { - _toStringVisiting.add(m); + toStringVisiting.add(m); result.write('{'); bool first = true; m.forEach((Object? k, Object? v) { @@ -130,8 +130,8 @@ abstract mixin class MapBase implements Map { }); result.write('}'); } finally { - assert(identical(_toStringVisiting.last, m)); - _toStringVisiting.removeLast(); + assert(identical(toStringVisiting.last, m)); + toStringVisiting.removeLast(); } return result.toString(); diff --git a/sdk/lib/collection/queue.dart b/sdk/lib/collection/queue.dart index a55b8ff4ff4..8a0e3b4aee3 100644 --- a/sdk/lib/collection/queue.dart +++ b/sdk/lib/collection/queue.dart @@ -483,7 +483,7 @@ final class DoubleLinkedQueue extends Iterable implements Queue { return _DoubleLinkedQueueIterator(this); } - String toString() => IterableBase.iterableToFullString(this, '{', '}'); + String toString() => Iterable.iterableToFullString(this, '{', '}'); } class _DoubleLinkedQueueIterator implements Iterator { @@ -803,7 +803,7 @@ final class ListQueue extends ListIterable implements Queue { } } - String toString() => IterableBase.iterableToFullString(this, "{", "}"); + String toString() => Iterable.iterableToFullString(this, "{", "}"); // Queue interface. diff --git a/sdk/lib/collection/set.dart b/sdk/lib/collection/set.dart index 4baf1aaf754..5742cdcded5 100644 --- a/sdk/lib/collection/set.dart +++ b/sdk/lib/collection/set.dart @@ -133,6 +133,7 @@ abstract mixin class SetBase implements Set { // Copied from Iterable. // Should be inherited if we had multi-level mixins. + Iterable where(bool f(E element)) => WhereIterable(this, f); Iterable expand(Iterable f(E element)) => @@ -170,17 +171,20 @@ abstract mixin class SetBase implements Set { String join([String separator = ""]) { Iterator iterator = this.iterator; if (!iterator.moveNext()) return ""; - StringBuffer buffer = StringBuffer(); - if (separator == null || separator == "") { + var first = iterator.current.toString(); + if (!iterator.moveNext()) return first; + var buffer = StringBuffer(first); + // TODO(51681): Drop null check when de-supporting pre-2.12 code. + if (separator == null || separator.isEmpty) { do { buffer.write(iterator.current); } while (iterator.moveNext()); } else { - buffer.write(iterator.current); - while (iterator.moveNext()) { - buffer.write(separator); - buffer.write(iterator.current); - } + do { + buffer + ..write(separator) + ..write(iterator.current); + } while (iterator.moveNext()); } return buffer.toString(); } @@ -237,45 +241,47 @@ abstract mixin class SetBase implements Set { } E lastWhere(bool test(E value), {E Function()? orElse}) { - late E result; - bool foundMatching = false; - for (E element in this) { - if (test(element)) { - result = element; - foundMatching = true; + var iterator = this.iterator; + E result; + do { + if (!iterator.moveNext()) { + if (orElse != null) return orElse(); + throw IterableElementError.noElement(); } + result = iterator.current; + } while (!test(result)); + while (iterator.moveNext()) { + var current = iterator.current; + if (test(current)) result = current; } - if (foundMatching) return result; - if (orElse != null) return orElse(); - throw IterableElementError.noElement(); + return result; } E singleWhere(bool test(E value), {E Function()? orElse}) { - late E result; - bool foundMatching = false; - for (E element in this) { - if (test(element)) { - if (foundMatching) { - throw IterableElementError.tooMany(); - } - result = element; - foundMatching = true; + var iterator = this.iterator; + E result; + do { + if (!iterator.moveNext()) { + if (orElse != null) return orElse(); + throw IterableElementError.noElement(); } + result = iterator.current; + } while (!test(result)); + while (iterator.moveNext()) { + if (test(iterator.current)) throw IterableElementError.tooMany(); } - if (foundMatching) return result; - if (orElse != null) return orElse(); - throw IterableElementError.noElement(); + return result; } E elementAt(int index) { - checkNotNullable(index, "index"); RangeError.checkNotNegative(index, "index"); - int elementIndex = 0; - for (E element in this) { - if (index == elementIndex) return element; - elementIndex++; + var iterator = this.iterator; + var skipCount = index; + while (iterator.moveNext()) { + if (skipCount == 0) return iterator.current; + skipCount--; } - throw IndexError.withLength(index, elementIndex, + throw IndexError.withLength(index, index - skipCount, indexable: this, name: "index"); } diff --git a/sdk/lib/collection/splay_tree.dart b/sdk/lib/collection/splay_tree.dart index 54627b72148..8c6df2dad9b 100644 --- a/sdk/lib/collection/splay_tree.dart +++ b/sdk/lib/collection/splay_tree.dart @@ -947,7 +947,7 @@ class _SplayTreeMapEntryIterator /// * [HashSet] the order of the objects in the iterations is not guaranteed. /// * [LinkedHashSet] objects stored based on insertion order. final class SplayTreeSet extends _SplayTree> - with IterableMixin, SetMixin { + with Iterable, SetMixin { _SplayTreeSetNode? _root; Comparator _compare; @@ -1188,5 +1188,5 @@ final class SplayTreeSet extends _SplayTree> Set toSet() => _clone(); - String toString() => IterableBase.iterableToFullString(this, '{', '}'); + String toString() => Iterable.iterableToFullString(this, '{', '}'); } diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart index be894489a1d..474e1fb1da3 100644 --- a/sdk/lib/core/iterable.dart +++ b/sdk/lib/core/iterable.dart @@ -81,9 +81,19 @@ part of dart.core; /// For methods like [map] and [where], the returned iterable will execute the /// argument function on every iteration, so those functions should also not /// have side effects. -abstract class Iterable { - // TODO(lrn): When we allow forwarding const constructors through - // mixin applications, make this class implement [IterableMixin]. +/// +/// The `Iterable` declaration provides a default implementation, +/// which can be extended or mixed in to implement the `Iterable` interface. +/// It implements every member other than the [iterator] getter, +/// using the [Iterator] provided by [iterator]. +/// An implementation of the `Iterable` interface should +/// provide a more efficient implementation of the members of `Iterable` +/// when it can do so. +abstract mixin class Iterable { + // This class has methods copied verbatim into: + // - SetMixin + // If changing a method here, also change other copies. + const Iterable(); /// Creates an `Iterable` which generates its elements dynamically. @@ -100,7 +110,19 @@ abstract class Iterable { /// As an `Iterable`, `Iterable.generate(n, generator))` is equivalent to /// `const [0, ..., n - 1].map(generator)`. factory Iterable.generate(int count, [E generator(int index)?]) { + // Always OK to omit generator when count is zero. if (count <= 0) return EmptyIterable(); + if (generator == null) { + // If generator is omitted, we generate integers. + // If `E` does not allow integers, it's an error. + Function id = _GeneratorIterable._id; + if (id is! E Function(int)) { + throw ArgumentError( + "Generator must be supplied or element type must allow integers", + "generator"); + } + generator = id; + } return _GeneratorIterable(count, generator); } @@ -119,8 +141,7 @@ abstract class Iterable { static Iterable castFrom(Iterable source) => CastIterable(source); - /// Returns a new `Iterator` that allows iterating the elements of this - /// `Iterable`. + /// A new `Iterator` that allows iterating the elements of this `Iterable`. /// /// Iterable classes may specify the iteration order of their elements /// (for example [List] always iterate in index order), @@ -147,7 +168,7 @@ abstract class Iterable { /// break iteration. Iterator get iterator; - /// Provides a view of this iterable as an iterable of [R] instances. + /// A view of this iterable as an iterable of [R] instances. /// /// If this iterable only contains instances of [R], all operations /// will work correctly. If any operation tries to access an element @@ -155,9 +176,9 @@ abstract class Iterable { /// /// When the returned iterable creates a new object that depends on /// the type [R], e.g., from [toList], it will have exactly the type [R]. - Iterable cast() => Iterable.castFrom(this); + Iterable cast() => CastIterable(this); - /// Returns the lazy concatenation of this iterable and [other]. + /// Creates the lazy concatenation of this iterable and [other]. /// /// The returned iterable will provide the same elements as this iterable, /// and, after that, the elements of [other], in the same order as in the @@ -216,7 +237,7 @@ abstract class Iterable { /// ``` Iterable map(T toElement(E e)) => MappedIterable(this, toElement); - /// Returns a new lazy [Iterable] with all elements that satisfy the + /// Creates a new lazy [Iterable] with all elements that satisfy the /// predicate [test]. /// /// The matching elements have the same order in the returned iterable @@ -238,7 +259,7 @@ abstract class Iterable { /// ``` Iterable where(bool test(E element)) => WhereIterable(this, test); - /// Returns a new lazy [Iterable] with all elements that have type [T]. + /// Creates a new lazy [Iterable] with all elements that have type [T]. /// /// The matching elements have the same order in the returned iterable /// as they have in [iterator]. @@ -421,17 +442,20 @@ abstract class Iterable { String join([String separator = ""]) { Iterator iterator = this.iterator; if (!iterator.moveNext()) return ""; - StringBuffer buffer = StringBuffer(); - if (separator == null || separator == "") { + var first = iterator.current.toString(); + if (!iterator.moveNext()) return first; + var buffer = StringBuffer(first); + // TODO(51681): Drop null check when de-supporting pre-2.12 code. + if (separator == null || separator.isEmpty) { do { buffer.write(iterator.current.toString()); } while (iterator.moveNext()); } else { - buffer.write(iterator.current.toString()); - while (iterator.moveNext()) { - buffer.write(separator); - buffer.write(iterator.current.toString()); - } + do { + buffer + ..write(separator) + ..write(iterator.current.toString()); + } while (iterator.moveNext()); } return buffer.toString(); } @@ -466,9 +490,8 @@ abstract class Iterable { /// final valuesList = /// planets.values.toList(growable: false); // [Mercury, Venus, Mars] /// ``` - List toList({bool growable = true}) { - return List.of(this, growable: growable); - } + List toList({bool growable = true}) => + List.of(this, growable: growable); /// Creates a [Set] containing the same elements as this iterable. /// @@ -485,15 +508,16 @@ abstract class Iterable { /// ``` Set toSet() => Set.of(this); - /// Returns the number of elements in [this]. + /// The number of elements in [this]. /// /// Counting all elements may involve iterating through all elements and can /// therefore be slow. /// Some iterables have a more efficient way to find the number of elements. + /// These *must* override the default implementation of `length`. int get length { assert(this is! EfficientLengthIterable); int count = 0; - Iterator it = iterator; + Iterator it = iterator; while (it.moveNext()) { count++; } @@ -524,7 +548,7 @@ abstract class Iterable { /// ``` bool get isNotEmpty => !isEmpty; - /// Returns a lazy iterable of the [count] first elements of this iterable. + /// Creates a lazy iterable of the [count] first elements of this iterable. /// /// The returned `Iterable` may contain fewer than `count` elements, if `this` /// contains fewer than `count` elements. @@ -540,11 +564,9 @@ abstract class Iterable { /// final result = numbers.take(4); // (1, 2, 3, 5) /// final takeAll = numbers.take(100); // (1, 2, 3, 5, 6, 7) /// ``` - Iterable take(int count) { - return TakeIterable(this, count); - } + Iterable take(int count) => TakeIterable(this, count); - /// Returns a lazy iterable of the leading elements satisfying [test]. + /// Creates a lazy iterable of the leading elements satisfying [test]. /// /// The filtering happens lazily. Every new iterator of the returned /// iterable starts iterating over the elements of `this`. @@ -561,11 +583,9 @@ abstract class Iterable { /// result = numbers.takeWhile((x) => x != 4); // (1, 2, 3, 5, 6, 7) /// result = numbers.takeWhile((x) => x.isOdd); // (1) /// ``` - Iterable takeWhile(bool test(E value)) { - return TakeWhileIterable(this, test); - } + Iterable takeWhile(bool test(E value)) => TakeWhileIterable(this, test); - /// Returns an [Iterable] that provides all but the first [count] elements. + /// Creates an [Iterable] that provides all but the first [count] elements. /// /// When the returned iterable is iterated, it starts iterating over `this`, /// first skipping past the initial [count] elements. @@ -586,11 +606,9 @@ abstract class Iterable { /// ``` /// /// The [count] must not be negative. - Iterable skip(int count) { - return SkipIterable(this, count); - } + Iterable skip(int count) => SkipIterable(this, count); - /// Returns an `Iterable` that skips leading elements while [test] is satisfied. + /// Creates an `Iterable` that skips leading elements while [test] is satisfied. /// /// The filtering happens lazily. Every new [Iterator] of the returned /// iterable iterates over all elements of `this`. @@ -609,11 +627,9 @@ abstract class Iterable { /// result = numbers.skipWhile((x) => x != 4); // () /// result = numbers.skipWhile((x) => x.isOdd); // (2, 3, 5, 6, 7) /// ``` - Iterable skipWhile(bool test(E value)) { - return SkipWhileIterable(this, test); - } + Iterable skipWhile(bool test(E value)) => SkipWhileIterable(this, test); - /// Returns the first element. + /// The first element. /// /// Throws a [StateError] if `this` is empty. /// Otherwise returns the first element in the iteration order, @@ -626,7 +642,7 @@ abstract class Iterable { return it.current; } - /// Returns the last element. + /// The last element. /// /// Throws a [StateError] if `this` is empty. /// Otherwise may iterate through the elements and returns the last one @@ -657,7 +673,7 @@ abstract class Iterable { return result; } - /// Returns the first element that satisfies the given predicate [test]. + /// The first element that satisfies the given predicate [test]. /// /// Iterates through elements and returns the first to satisfy [test]. /// @@ -681,7 +697,7 @@ abstract class Iterable { throw IterableElementError.noElement(); } - /// Returns the last element that satisfies the given predicate [test]. + /// The last element that satisfies the given predicate [test]. /// /// An iterable that can access its elements directly may check its /// elements in any order (for example a list starts by checking the @@ -703,20 +719,25 @@ abstract class Iterable { /// function is returned. /// If [orElse] is omitted, it defaults to throwing a [StateError]. E lastWhere(bool test(E element), {E orElse()?}) { - late E result; - bool foundMatching = false; - for (E element in this) { - if (test(element)) { - result = element; - foundMatching = true; + var iterator = this.iterator; + // Potential result during first loop. + E result; + do { + if (!iterator.moveNext()) { + if (orElse != null) return orElse(); + throw IterableElementError.noElement(); } + result = iterator.current; + } while (!test(result)); + // Now `result` is actual result, unless a later one is found. + while (iterator.moveNext()) { + var current = iterator.current; + if (test(current)) result = current; } - if (foundMatching) return result; - if (orElse != null) return orElse(); - throw IterableElementError.noElement(); + return result; } - /// Returns the single element that satisfies [test]. + /// The single element that satisfies [test]. /// /// Checks elements to see if `test(element)` returns true. /// If exactly one element satisfies [test], that element is returned. @@ -740,20 +761,19 @@ abstract class Iterable { /// result = numbers.singleWhere((element) => element == 2); // Throws Error. /// ``` E singleWhere(bool test(E element), {E orElse()?}) { - late E result; - bool foundMatching = false; - for (E element in this) { - if (test(element)) { - if (foundMatching) { - throw IterableElementError.tooMany(); - } - result = element; - foundMatching = true; + var iterator = this.iterator; + E result; + do { + if (!iterator.moveNext()) { + if (orElse != null) return orElse(); + throw IterableElementError.noElement(); } + result = iterator.current; + } while (!test(result)); + while (iterator.moveNext()) { + if (test(iterator.current)) throw IterableElementError.tooMany(); } - if (foundMatching) return result; - if (orElse != null) return orElse(); - throw IterableElementError.noElement(); + return result; } /// Returns the [index]th element. @@ -773,12 +793,13 @@ abstract class Iterable { /// ``` E elementAt(int index) { RangeError.checkNotNegative(index, "index"); - int elementIndex = 0; - for (E element in this) { - if (index == elementIndex) return element; - elementIndex++; + var iterator = this.iterator; + var skipCount = index; + while (iterator.moveNext()) { + if (skipCount == 0) return iterator.current; + skipCount--; } - throw IndexError.withLength(index, elementIndex, + throw IndexError.withLength(index, index - skipCount, indexable: this, name: "index"); } @@ -796,10 +817,69 @@ abstract class Iterable { /// The conversion may omit calling `toString` on some elements if they /// are known to not occur in the output, and it may stop iterating after /// a hundred elements. - String toString() => IterableBase.iterableToShortString(this, '(', ')'); + String toString() => iterableToShortString(this, '(', ')'); + + /// Convert an `Iterable` to a string like [Iterable.toString]. + /// + /// Allows using other delimiters than '(' and ')'. + /// + /// Handles circular references where converting one of the elements + /// to a string ends up converting [iterable] to a string again. + static String iterableToShortString(Iterable iterable, + [String leftDelimiter = '(', String rightDelimiter = ')']) { + if (isToStringVisiting(iterable)) { + if (leftDelimiter == "(" && rightDelimiter == ")") { + // Avoid creating a new string in the "common" case. + return "(...)"; + } + return "$leftDelimiter...$rightDelimiter"; + } + List parts = []; + toStringVisiting.add(iterable); + try { + _iterablePartsToStrings(iterable, parts); + } finally { + assert(identical(toStringVisiting.last, iterable)); + toStringVisiting.removeLast(); + } + return (StringBuffer(leftDelimiter) + ..writeAll(parts, ", ") + ..write(rightDelimiter)) + .toString(); + } + + /// Converts an `Iterable` to a string. + /// + /// Converts each elements to a string, and separates the results by ", ". + /// Then wraps the result in [leftDelimiter] and [rightDelimiter]. + /// + /// Unlike [iterableToShortString], this conversion doesn't omit any + /// elements or puts any limit on the size of the result. + /// + /// Handles circular references where converting one of the elements + /// to a string ends up converting [iterable] to a string again. + static String iterableToFullString(Iterable iterable, + [String leftDelimiter = '(', String rightDelimiter = ')']) { + if (isToStringVisiting(iterable)) { + return "$leftDelimiter...$rightDelimiter"; + } + StringBuffer buffer = StringBuffer(leftDelimiter); + toStringVisiting.add(iterable); + try { + buffer.writeAll(iterable, ", "); + } finally { + assert(identical(toStringVisiting.last, iterable)); + toStringVisiting.removeLast(); + } + buffer.write(rightDelimiter); + return buffer.toString(); + } } class _GeneratorIterable extends ListIterable { + // Methods have efficient implementations from `ListIterable`, + // based on `length` and `elementAt`. + /// The length of the generated iterable. final int length; @@ -807,12 +887,7 @@ class _GeneratorIterable extends ListIterable { final E Function(int) _generator; /// Creates the generated iterable. - /// - /// If [generator] is `null`, it is checked that `int` is assignable to [E]. - _GeneratorIterable(this.length, E generator(int index)?) - : // The `as` below is used as check to make sure that `int` is assignable - // to [E]. - _generator = generator ?? (_id as E Function(int)); + _GeneratorIterable(this.length, this._generator); E elementAt(int index) { IndexError.check(index, length, indexable: this); @@ -822,3 +897,116 @@ class _GeneratorIterable extends ListIterable { /// Helper function used as default _generator function. static int _id(int n) => n; } + +/// Convert elements of [iterable] to strings and store them in [parts]. +void _iterablePartsToStrings(Iterable iterable, List parts) { + // This is the complicated part of [iterableToShortString]. + // It is extracted as a separate function to avoid having too much code + // inside the try/finally. + + // Try to stay below this many characters. + const int lengthLimit = 80; + + // Always at least this many elements at the start. + const int headCount = 3; + + // Always at least this many elements at the end. + const int tailCount = 2; + + // Stop iterating after this many elements. Iterables can be infinite. + const int maxCount = 100; + // Per entry length overhead. It's for ", " for all after the first entry, + // and for "(" and ")" for the initial entry. By pure luck, that's the same + // number. + const int overhead = 2; + const int ellipsisSize = 3; // "...".length. + + int length = 0; + int count = 0; + Iterator it = iterable.iterator; + // Initial run of elements, at least headCount, and then continue until + // passing at most lengthLimit characters. + while (length < lengthLimit || count < headCount) { + if (!it.moveNext()) return; + String next = "${it.current}"; + parts.add(next); + length += next.length + overhead; + count++; + } + + String penultimateString; + String ultimateString; + + // Find last two elements. One or more of them may already be in the + // parts array. Include their length in `length`. + if (!it.moveNext()) { + if (count <= headCount + tailCount) return; + ultimateString = parts.removeLast(); + penultimateString = parts.removeLast(); + } else { + Object? penultimate = it.current; + count++; + if (!it.moveNext()) { + if (count <= headCount + 1) { + parts.add("$penultimate"); + return; + } + ultimateString = "$penultimate"; + penultimateString = parts.removeLast(); + length += ultimateString.length + overhead; + } else { + Object? ultimate = it.current; + count++; + // Then keep looping, keeping the last two elements in variables. + assert(count < maxCount); + while (it.moveNext()) { + penultimate = ultimate; + ultimate = it.current; + count++; + if (count > maxCount) { + // If we haven't found the end before maxCount, give up. + // This cannot happen in the code above because each entry + // increases length by at least two, so there is no way to + // visit more than ~40 elements before this loop. + + // Remove any surplus elements until length, including ", ...)", + // is at most lengthLimit. + while (length > lengthLimit - ellipsisSize - overhead && + count > headCount) { + length -= parts.removeLast().length + overhead; + count--; + } + parts.add("..."); + return; + } + } + penultimateString = "$penultimate"; + ultimateString = "$ultimate"; + length += ultimateString.length + penultimateString.length + 2 * overhead; + } + } + + // If there is a gap between the initial run and the last two, + // prepare to add an ellipsis. + String? elision; + if (count > parts.length + tailCount) { + elision = "..."; + length += ellipsisSize + overhead; + } + + // If the last two elements were very long, and we have more than + // headCount elements in the initial run, drop some to make room for + // the last two. + while (length > lengthLimit && parts.length > headCount) { + length -= parts.removeLast().length + overhead; + if (elision == null) { + elision = "..."; + length += ellipsisSize + overhead; + } + } + if (elision != null) { + parts.add(elision); + } + parts.add(penultimateString); + parts.add(ultimateString); +} diff --git a/sdk/lib/internal/internal.dart b/sdk/lib/internal/internal.dart index 0ad7fb33d9b..f7f4c08c625 100644 --- a/sdk/lib/internal/internal.dart +++ b/sdk/lib/internal/internal.dart @@ -1040,3 +1040,16 @@ class DoubleLinkedQueueEntry { /// through scheduled events or timers, which would put the object into /// an inconsistent state if simply being copied. const vmIsolateUnsendable = pragma("vm:isolate-unsendable"); + +// Helpers used to detect cycles in collection `toString`s. + +/// A collection used to identify cyclic lists during `toString` calls. +final List toStringVisiting = []; + +/// Check if we are currently visiting [object] in a `toString` call. +bool isToStringVisiting(Object object) { + for (int i = 0; i < toStringVisiting.length; i++) { + if (identical(object, toStringVisiting[i])) return true; + } + return false; +} diff --git a/sdk/lib/internal/linked_list.dart b/sdk/lib/internal/linked_list.dart index ddb0331fec3..598f583a17d 100644 --- a/sdk/lib/internal/linked_list.dart +++ b/sdk/lib/internal/linked_list.dart @@ -5,7 +5,7 @@ part of dart._internal; /// A rudimentary linked list. -class LinkedList> extends IterableBase { +class LinkedList> extends Iterable { T get first => _first as T; T? _first; diff --git a/sdk/lib/vmservice/named_lookup.dart b/sdk/lib/vmservice/named_lookup.dart index 8431ccff9df..43c18f80988 100644 --- a/sdk/lib/vmservice/named_lookup.dart +++ b/sdk/lib/vmservice/named_lookup.dart @@ -5,7 +5,7 @@ part of dart._vmservice; /// Set like contains which automatically generated String ids for its items -class NamedLookup extends Object with IterableMixin { +class NamedLookup extends Iterable { final IdGenerator _generator; final _elements = {}; final _ids = {};