diff --git a/lib/std/sort/insertionsort.c3 b/lib/std/sort/insertionsort.c3 index c705afeec..ab1c6b371 100644 --- a/lib/std/sort/insertionsort.c3 +++ b/lib/std/sort/insertionsort.c3 @@ -6,10 +6,15 @@ Sort list using the quick sort algorithm. @require @is_sortable(list) "The list must be indexable and support .len or .len()" @require @is_valid_cmp_fn(cmp, list, context) "Expected a comparison function which compares values" *> -macro insertionsort(list, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin +macro insertionsort(list, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin @safemacro { - usz len = sort::len_from_list(list); - is::isort(<$typeof(list), $typeof(cmp), $typeof(context)>)(list, 0, (isz)len, cmp, context); + $if @typekind(list) == POINTER &&& (@typekind(*list) == ARRAY || @typekind(*list) == VECTOR): + $typeof((*list)[0])[] list2 = list; + is::isort(<$typeof(list2), $typeof(cmp), $typeof(context)>)(list2, 0, list.len, cmp, context); + $else + usz len = sort::len_from_list(list); + is::isort(<$typeof(list), $typeof(cmp), $typeof(context)>)(list, 0, (isz)len, cmp, context); + $endif } module std::sort::is(); diff --git a/lib/std/sort/quicksort.c3 b/lib/std/sort/quicksort.c3 index 1568b8921..156d6a2f6 100644 --- a/lib/std/sort/quicksort.c3 +++ b/lib/std/sort/quicksort.c3 @@ -9,8 +9,13 @@ Sort list using the quick sort algorithm. *> macro quicksort(list, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin { - usz len = sort::len_from_list(list); - qs::qsort(<$typeof(list), $typeof(cmp), $typeof(context)>)(list, 0, (isz)len - 1, cmp, context); + $if @typekind(list) == POINTER &&& (@typekind(*list) == ARRAY || @typekind(*list) == VECTOR): + $typeof((*list)[0])[] list2 = list; + qs::qsort(<$typeof(list2), $typeof(cmp), $typeof(context)>)(list2, 0, (isz)list.len - 1, cmp, context); + $else + usz len = sort::len_from_list(list); + qs::qsort(<$typeof(list), $typeof(cmp), $typeof(context)>)(list, 0, (isz)len - 1, cmp, context); + $endif } <* diff --git a/lib/std/sort/sort.c3 b/lib/std/sort/sort.c3 index 948645039..f4f7dfbd6 100644 --- a/lib/std/sort/sort.c3 +++ b/lib/std/sort/sort.c3 @@ -21,6 +21,8 @@ macro bool @is_sortable(#list) return false; $case !$defined(#list.len): return false; + $case @typekind(#list) == VECTOR || @typekind(#list) == ARRAY: + return false; $case $defined(&#list[0]) &&& !types::is_same($typeof(&#list[0]), $typeof(#list[0])*): return false; $default: diff --git a/releasenotes.md b/releasenotes.md index 00265e3ce..11790d998 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -215,6 +215,7 @@ - Taking the $typeof of a wildcard optional returns `void!`. - Fix bug with enums with jump tables #1840. - Enum associated declarations accidentally allowed declaration in function style. #1841 +- Quicksort and insertsort incorrectly allowing arrays and vectors by value. #1845. ### Stdlib changes - Remove unintended print of `char[]` as String diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 23fd8a829..bc3d47d47 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -9558,18 +9558,22 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr, case EXPR_TYPECALL: RETURN_SEMA_ERROR(expr, "Expected '()' after this."); case EXPR_OTHER_CONTEXT: + { + bool in_no_eval = context->call_env.in_no_eval; context = expr->expr_other_context.context; expr_replace(expr, expr->expr_other_context.inner); if (expr->resolve_status == RESOLVE_DONE) return expr_ok(expr); ASSERT_SPAN(expr, expr->resolve_status == RESOLVE_NOT_DONE); expr->resolve_status = RESOLVE_RUNNING; - { - bool in_other = context->call_env.in_other; - context->call_env.in_other = true; - bool success = sema_analyse_expr_dispatch(context, expr, check); - context->call_env.in_other = in_other; - return success; - } + bool in_other = context->call_env.in_other; + bool was_in_no_eval = context->call_env.in_no_eval; + context->call_env.in_other = true; + context->call_env.in_no_eval = in_no_eval; + bool success = sema_analyse_expr_dispatch(context, expr, check); + context->call_env.in_other = in_other; + context->call_env.in_no_eval = was_in_no_eval; + return success; + } case EXPR_CT_CASTABLE: return sema_expr_analyse_castable(context, expr); case EXPR_EMBED: diff --git a/test/unit/stdlib/sort/insertionsort.c3 b/test/unit/stdlib/sort/insertionsort.c3 index f8191548c..44725df1e 100644 --- a/test/unit/stdlib/sort/insertionsort.c3 +++ b/test/unit/stdlib/sort/insertionsort.c3 @@ -54,6 +54,13 @@ fn void insertionsort_with_value() } } +fn void insertionsort_with_array() +{ + int[*] a = { 4, 8, 100, 1, 2 }; + sort::insertionsort(&a); + assert(a == { 1, 2, 4, 8, 100 }); +} + fn void insertionsort_with_lambda() { int[][] tcases = { diff --git a/test/unit/stdlib/sort/quicksort.c3 b/test/unit/stdlib/sort/quicksort.c3 index c4ae10c10..b56f6985b 100644 --- a/test/unit/stdlib/sort/quicksort.c3 +++ b/test/unit/stdlib/sort/quicksort.c3 @@ -37,6 +37,13 @@ fn void quicksort_with_ref() } } +fn void quicksort_with_array() +{ + int[*] a = { 4, 8, 100, 1, 2 }; + sort::quicksort(&a); + assert(a == { 1, 2, 4, 8, 100 }); +} + fn void quicksort_with_value() { int[][] tcases = {