Skip to content

Commit

Permalink
Avoid setRange with potentially incompatible types (dart-archive/coll…
Browse files Browse the repository at this point in the history
…ection#320)

Fixes dart-lang/collection#317

Use `sublist` on the input to get a list with the same runtime generic
as the input instead of constructing a new list with the static generic.
  • Loading branch information
natebosch authored Nov 21, 2023
1 parent 347817c commit b8c9297
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 2 deletions.
2 changes: 2 additions & 0 deletions pkgs/collection/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

- Adds `shuffled` to `IterableExtension`.
- Shuffle `IterableExtension.sample` results.
- Fix `mergeSort` when the runtime iterable generic is a subtype of the static
generic.
- Require Dart `^3.1.0`
- Mark "mixin" classes as `mixin`.

Expand Down
4 changes: 2 additions & 2 deletions pkgs/collection/lib/src/algorithms.dart
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ void mergeSort<E>(List<E> elements,
var middle = start + firstLength;
var secondLength = end - middle;
// secondLength is always the same as firstLength, or one greater.
var scratchSpace = List<E>.filled(secondLength, elements[start]);
var scratchSpace = elements.sublist(0, secondLength);
_mergeSort(elements, identity<E>, compare, middle, end, scratchSpace, 0);
var firstTarget = end - firstLength;
_mergeSort(
Expand Down Expand Up @@ -268,7 +268,7 @@ void mergeSortBy<E, K>(List<E> elements, K Function(E element) keyOf,
var firstLength = middle - start;
var secondLength = end - middle;
// secondLength is always the same as firstLength, or one greater.
var scratchSpace = List<E>.filled(secondLength, elements[start]);
var scratchSpace = elements.sublist(0, secondLength);
_mergeSort(elements, keyOf, compare, middle, end, scratchSpace, 0);
var firstTarget = end - firstLength;
_mergeSort(elements, keyOf, compare, start, middle, elements, firstTarget);
Expand Down
13 changes: 13 additions & 0 deletions pkgs/collection/test/algorithms_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,19 @@ void main() {
reverse(l, 0, 6);
expect(l, equals([2, 1, 4, 3, 6, 5]));
});

test('mergeSort works when runtime generic is a subtype of the static type',
() {
// Regression test for https://github.com/dart-lang/collection/issues/317
final length = 1000; // Larger than _mergeSortLimit
// Out of order list, with first half guaranteed to empty first during
// merge.
final list = [
for (var i = 0; i < length / 2; i++) -i,
for (var i = 0; i < length / 2; i++) i + length,
];
expect(() => mergeSort<num>(list), returnsNormally);
});
}

class C {
Expand Down

0 comments on commit b8c9297

Please sign in to comment.