Skip to content

bug: arrays.sort_asc, sort_desc and is_sorted give wrong results for arrays of i8, i16, i32, u8, u16, u32 and f32 #2781

Description

@SchoolyB

Description

The spec describes sort_asc and sort_desc as sorting "in place" for a comparable T, and is_sorted as true when each element is <= the next. They work for int, i64, u64, uint, float, byte, char and string. They do not work for the other sized numeric types.

The codegen dispatch for sort_asc/sort_desc (codegen.c, near the gray_arrays_sort_* emit) only has variants for float, string, byte, char, wide ints and enums. Every other element type falls through to the int64 variant, which calls qsort with cmp_i64_asc. That comparator reads 8 bytes at each element pointer, but the elements of these arrays are 1, 2 or 4 bytes wide (the runtime already has cmp_u8 and cmp_i32 comparators, and none for i8, i16, u16, u32 or f32). The comparison is made on 8 bytes of unrelated neighbouring elements, so the result is an arbitrary permutation. For the last elements it also reads up to 7 bytes past the end of the array. is_sorted gets the same wrong answer, so is_sorted reports false for an array that is already sorted.

The elements are moved as whole elements, so no values are lost or changed. They just end up in the wrong order.

Expected

The array is sorted ascending (sort_asc) or descending (sort_desc), and is_sorted returns true for an ascending array.

Actual

Call Result
mut a [i32] = {5, 3, 9, 1}; arrays.sort_asc(a) a is {9, 5, 1, 3}
mut a [i8] = {94, 15, 26, -70, -66, -84, 45, 95, -35}; arrays.sort_desc(a) {-66, 26, 15, -70, 94, -84, 45, 95, -35}
mut b [u8] = {5, 3, 9, 1}; arrays.sort_desc(b) unchanged: {5, 3, 9, 1}
sort_asc / sort_desc on nine random values in [i16], [u16], [u32], [f32] not sorted in either direction
arrays.is_sorted(a) where a is the ascending [i32] {-50000, 1, 2, 90000} false
same for [i8], [i16], [u8], [u16], [u32], [f32] false
same calls on [i64], [uint], [u64], [float], [byte], [char], [string] correct

arrays.binary_search, min_index, max_index, index_of and count give the right answers on these sized arrays.

Minimal reproduction

import @arrays

do main() {
    mut a [i32] = {5, 3, 9, 1}
    arrays.sort_asc(a)
    println(a)
    println(arrays.is_sorted(a))
}

Prints {9, 5, 1, 3} and false. Expected: {1, 3, 5, 9} and true.

import @arrays

do main() {
    mut a [u8] = {1, 2, 3, 200}
    println(arrays.is_sorted(a))
}

Prints false. Expected: true.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingstdlibGeneral standard library issues

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions