From b8c9297e6d552af50d158165f358c22c915901e4 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Mon, 20 Nov 2023 16:44:02 -0800 Subject: [PATCH] Avoid setRange with potentially incompatible types (dart-lang/collection#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. --- pkgs/collection/CHANGELOG.md | 2 ++ pkgs/collection/lib/src/algorithms.dart | 4 ++-- pkgs/collection/test/algorithms_test.dart | 13 +++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/pkgs/collection/CHANGELOG.md b/pkgs/collection/CHANGELOG.md index 05b08995..e38e1a8c 100644 --- a/pkgs/collection/CHANGELOG.md +++ b/pkgs/collection/CHANGELOG.md @@ -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`. diff --git a/pkgs/collection/lib/src/algorithms.dart b/pkgs/collection/lib/src/algorithms.dart index 5833bbd1..f5ea8d3d 100644 --- a/pkgs/collection/lib/src/algorithms.dart +++ b/pkgs/collection/lib/src/algorithms.dart @@ -232,7 +232,7 @@ void mergeSort(List elements, var middle = start + firstLength; var secondLength = end - middle; // secondLength is always the same as firstLength, or one greater. - var scratchSpace = List.filled(secondLength, elements[start]); + var scratchSpace = elements.sublist(0, secondLength); _mergeSort(elements, identity, compare, middle, end, scratchSpace, 0); var firstTarget = end - firstLength; _mergeSort( @@ -268,7 +268,7 @@ void mergeSortBy(List 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.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); diff --git a/pkgs/collection/test/algorithms_test.dart b/pkgs/collection/test/algorithms_test.dart index 41603dd8..4bc1d54b 100644 --- a/pkgs/collection/test/algorithms_test.dart +++ b/pkgs/collection/test/algorithms_test.dart @@ -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(list), returnsNormally); + }); } class C {