From 3b3b9361257c6659abb79586712886d8636387c5 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sun, 24 Aug 2025 13:09:04 +0200 Subject: [PATCH] patch 9.1.1684: min()/max() does not handle float data types Problem: min()/max() does not handle float data types (ubaldot) Solution: Extend min() and max() to every comparable type (LemonBoy) Re-use the logic used for plain old comparison operators, this way we gain support for float values and unify the logic handling the comparisons. fixes: #18052 closes: 18055 Signed-off-by: LemonBoy Signed-off-by: Christian Brabandt --- runtime/doc/builtin.txt | 6 +- runtime/doc/version9.txt | 3 +- src/evalfunc.c | 93 +++++++++++++++++++---------- src/proto/tuple.pro | 2 +- src/proto/typval.pro | 1 + src/testdir/test_functions.vim | 34 +++++++++-- src/testdir/test_tuple.vim | 25 +------- src/testdir/test_vim9_assign.vim | 6 +- src/testdir/test_vim9_builtin.vim | 4 +- src/testdir/test_vim9_script.vim | 2 +- src/tuple.c | 35 +++++------ src/typval.c | 99 +++++++++++++------------------ src/version.c | 2 + 13 files changed, 167 insertions(+), 145 deletions(-) diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index 32cb40f1b7..418bc47e51 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -1,4 +1,4 @@ -*builtin.txt* For Vim version 9.1. Last change: 2025 Aug 23 +*builtin.txt* For Vim version 9.1. Last change: 2025 Aug 24 VIM REFERENCE MANUAL by Bram Moolenaar @@ -7626,7 +7626,7 @@ max({expr}) *max()* Can also be used as a |method|: > mylist->max() < - Return type: |Number| + Return type: any, depending on {expr} menu_info({name} [, {mode}]) *menu_info()* @@ -7718,7 +7718,7 @@ min({expr}) *min()* Can also be used as a |method|: > mylist->min() < - Return type: |Number| + Return type: any, depending on {expr} mkdir({name} [, {flags} [, {prot}]]) *mkdir()* *E739* diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt index b820717577..7e18266d7b 100644 --- a/runtime/doc/version9.txt +++ b/runtime/doc/version9.txt @@ -1,4 +1,4 @@ -*version9.txt* For Vim version 9.1. Last change: 2025 Aug 23 +*version9.txt* For Vim version 9.1. Last change: 2025 Aug 24 VIM REFERENCE MANUAL by Bram Moolenaar @@ -41752,6 +41752,7 @@ Others: ~ feature, see |socketserver-clientserver|. - |CmdlineLeave| sets |v:char| to the character that caused exiting the Command-line. +- |min()|/|max()| can handle all comparable data types. Platform specific ~ - MS-Winodws: Paths like "\Windows" and "/Windows" are now considered to be diff --git a/src/evalfunc.c b/src/evalfunc.c index 91c7ca04e0..13f1823d3b 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -1799,6 +1799,30 @@ ret_remove(int argcount, return &t_any; } + static type_T * +ret_max_min(int argcount, + type2_T *argtypes, + type_T **decl_type) +{ + if (argcount > 0) + { + type_T *t = argtypes[0].type_decl; + if (t->tt_type == VAR_LIST || t->tt_type == VAR_DICT) + t = t->tt_member; + else + t = &t_any; + *decl_type = t; + + t = argtypes[0].type_curr; + if (t->tt_type == VAR_LIST || t->tt_type == VAR_DICT) + t = t->tt_member; + else + t = &t_any; + return t; + } + return &t_any; +} + static type_T * ret_getreg(int argcount, type2_T *argtypes UNUSED, @@ -2541,7 +2565,7 @@ static funcentry_T global_functions[] = {"matchstrpos", 2, 4, FEARG_1, arg24_match_func, ret_list_any, f_matchstrpos}, {"max", 1, 1, FEARG_1, arg1_list_or_tuple_or_dict, - ret_number, f_max}, + ret_max_min, f_max}, {"menu_info", 1, 2, FEARG_1, arg2_string, ret_dict_any, #ifdef FEAT_MENU @@ -2551,7 +2575,7 @@ static funcentry_T global_functions[] = #endif }, {"min", 1, 1, FEARG_1, arg1_list_or_tuple_or_dict, - ret_number, f_min}, + ret_max_min, f_min}, {"mkdir", 1, 3, FEARG_1, arg3_string_string_number, ret_number_bool, f_mkdir}, {"mode", 0, 1, FEARG_1, arg1_bool, @@ -9535,17 +9559,18 @@ f_matchstrpos(typval_T *argvars, typval_T *rettv) max_min(typval_T *argvars, typval_T *rettv, int domax) { varnumber_T n = 0; - varnumber_T i; - int error = FALSE; if (in_vim9script() && check_for_list_or_tuple_or_dict_arg(argvars, 0) == FAIL) return; + rettv->vval.v_number = 0; + if (argvars[0].v_type == VAR_LIST) { list_T *l; listitem_T *li; + typval_T *tv = NULL; l = argvars[0].vval.v_list; if (l != NULL && l->lv_len > 0) @@ -9557,42 +9582,44 @@ max_min(typval_T *argvars, typval_T *rettv, int domax) else n = l->lv_u.nonmat.lv_start + ((varnumber_T)l->lv_len - 1) * l->lv_u.nonmat.lv_stride; + rettv->vval.v_number = n; } else { - li = l->lv_first; - if (li != NULL) + FOR_ALL_LIST_ITEMS(l, li) { - n = tv_get_number_chk(&li->li_tv, &error); - if (error) - return; // type error; errmsg already given - for (;;) + if (tv == NULL) + tv = &li->li_tv; + else { - li = li->li_next; - if (li == NULL) - break; - i = tv_get_number_chk(&li->li_tv, &error); - if (error) - return; // type error; errmsg already given - if (domax ? i > n : i < n) - n = i; + int res; + if (typval_compare2(&li->li_tv, tv, + domax ? EXPR_GREATER : EXPR_SMALLER, FALSE, &res) == FAIL) + return; + if (res == OK) + tv = &li->li_tv; } } + + if (tv != NULL) + copy_tv(tv, rettv); } } } else if (argvars[0].v_type == VAR_TUPLE) { - n = tuple_max_min(argvars[0].vval.v_tuple, domax, &error); - if (error) - return; + typval_T *tv; + + tv = tuple_max_min(argvars[0].vval.v_tuple, domax); + if (tv != NULL) + copy_tv(tv, rettv); } else if (argvars[0].v_type == VAR_DICT) { dict_T *d; - int first = TRUE; hashitem_T *hi; int todo; + typval_T *tv = NULL; d = argvars[0].vval.v_dict; if (d != NULL) @@ -9603,24 +9630,26 @@ max_min(typval_T *argvars, typval_T *rettv, int domax) if (!HASHITEM_EMPTY(hi)) { --todo; - i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error); - if (error) - return; // type error; errmsg already given - if (first) + if (tv == NULL) + tv = &HI2DI(hi)->di_tv; + else { - n = i; - first = FALSE; + int res; + if (typval_compare2(&HI2DI(hi)->di_tv, tv, + domax ? EXPR_GREATER : EXPR_SMALLER, FALSE, &res) == FAIL) + return; + if (res == OK) + tv = &HI2DI(hi)->di_tv; } - else if (domax ? i > n : i < n) - n = i; } } } + + if (tv != NULL) + copy_tv(tv, rettv); } else semsg(_(e_argument_of_str_must_be_list_or_dictionary), domax ? "max()" : "min()"); - - rettv->vval.v_number = n; } /* diff --git a/src/proto/tuple.pro b/src/proto/tuple.pro index 138648d3c5..1ba0295486 100644 --- a/src/proto/tuple.pro +++ b/src/proto/tuple.pro @@ -26,7 +26,7 @@ long tuple_count(tuple_T *tuple, typval_T *needle, long idx, int ic); void tuple2items(typval_T *argvars, typval_T *rettv); int index_tuple(tuple_T *tuple, typval_T *tv, int start_idx, int ic); int indexof_tuple(tuple_T *tuple, long startidx, typval_T *expr); -varnumber_T tuple_max_min(tuple_T *tuple, int domax, int *error); +typval_T *tuple_max_min(tuple_T *tuple, int domax); void tuple_repeat(tuple_T *tuple, int n, typval_T *rettv); void tuple_reverse(tuple_T *tuple, typval_T *rettv); void tuple_reduce(typval_T *argvars, typval_T *expr, typval_T *rettv); diff --git a/src/proto/typval.pro b/src/proto/typval.pro index d30cdedc18..05283a1732 100644 --- a/src/proto/typval.pro +++ b/src/proto/typval.pro @@ -68,6 +68,7 @@ char_u *tv_stringify(typval_T *varp, char_u *buf); int tv_check_lock(typval_T *tv, char_u *name, int use_gettext); void copy_tv(typval_T *from, typval_T *to); int typval_compare(typval_T *tv1, typval_T *tv2, exprtype_T type, int ic); +int typval_compare2(typval_T *tv1, typval_T *tv2, exprtype_T type, int ic, int *res); int typval_compare_list(typval_T *tv1, typval_T *tv2, exprtype_T type, int ic, int *res); int typval_compare_tuple(typval_T *tv1, typval_T *tv2, exprtype_T type, int ic, int *res); int typval_compare_null(typval_T *tv1, typval_T *tv2); diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index 9dd9601810..9d66985d6c 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -133,35 +133,57 @@ func Test_max() call assert_equal(0, max([])) call assert_equal(2, max([2])) call assert_equal(2, max([1, 2])) + call assert_equal(3, max([1.0, 2, 3])) + call assert_equal(3.0, max([1, 2, 3.0])) call assert_equal(2, max([1, 2, v:null])) + call assert_equal(0, max(())) + call assert_equal(2, max((2, ))) + call assert_equal(2, max((1, 2))) + call assert_equal(3, max((1.0, 2, 3))) + call assert_equal(3.0, max((1, 2, 3.0))) + call assert_equal(2, max((1, 2, v:null))) + call assert_equal(0, max({})) call assert_equal(2, max({'a':1, 'b':2})) + call assert_equal('abz', max(['abc', 'aba', 'abz'])) + call assert_fails('call max(1)', 'E712:') call assert_fails('call max(v:none)', 'E712:') " check we only get one error - call assert_fails('call max([#{}, [1]])', ['E728:', 'E728:']) - call assert_fails('call max(#{a: {}, b: [1]})', ['E728:', 'E728:']) + call assert_fails('call max([#{}, [1]])', ['E691:', 'E691:']) + call assert_fails('call max(#{a: {}, b: [1]})', ['E691:', 'E691:']) endfunc func Test_min() call assert_equal(0, min([])) call assert_equal(2, min([2])) call assert_equal(1, min([1, 2])) - call assert_equal(0, min([1, 2, v:null])) + call assert_equal(1, min([1, 2, 3.0])) + call assert_equal(1.0, min([1.0, 2])) + call assert_equal(v:null, min([1, 2, v:null])) + + call assert_equal(0, min(())) + call assert_equal(2, min((2, ))) + call assert_equal(1, min((1, 2))) + call assert_equal(1, min((1, 2, 3.0))) + call assert_equal(1.0, min((1.0, 2))) + call assert_equal(v:null, min((1, 2, v:null))) call assert_equal(0, min({})) call assert_equal(1, min({'a':1, 'b':2})) + call assert_equal('aba', min(['abc', 'aba', 'abz'])) + call assert_fails('call min(1)', 'E712:') call assert_fails('call min(v:none)', 'E712:') - call assert_fails('call min([1, {}])', 'E728:') + call assert_fails('call min([1, {}])', 'E735:') " check we only get one error - call assert_fails('call min([[1], #{}])', ['E745:', 'E745:']) - call assert_fails('call min(#{a: [1], b: #{}})', ['E745:', 'E745:']) + call assert_fails('call min([[1], #{}])', ['E691:', 'E691:']) + call assert_fails('call min(#{a: [1], b: #{}})', ['E691:', 'E691:']) endfunc func Test_strwidth() diff --git a/src/testdir/test_tuple.vim b/src/testdir/test_tuple.vim index c6d8e819ac..1d87fe1194 100644 --- a/src/testdir/test_tuple.vim +++ b/src/testdir/test_tuple.vim @@ -1994,22 +1994,13 @@ func Test_tuple_max() END call v9.CheckSourceFailure(lines, 'E1030: Using a String as a Number: "b"') - let lines =<< trim END - vim9script - def Fn() - var x = max(('a', 'b')) - enddef - Fn() - END - call v9.CheckSourceFailure(lines, 'E1030: Using a String as a Number: "a"') - let lines =<< trim END echo max([('a', 'b'), 20]) END call v9.CheckSourceLegacyAndVim9Failure(lines, [ - \ 'E1520: Using a Tuple as a Number', - \ 'E1520: Using a Tuple as a Number', - \ 'E1520: Using a Tuple as a Number']) + \ 'E1517: Can only compare Tuple with Tuple', + \ 'E1517: Can only compare Tuple with Tuple', + \ 'E1517: Can only compare Tuple with Tuple']) endfunc " Test for min() @@ -2035,16 +2026,6 @@ func Test_tuple_min() var x = min((1, 'b')) END call v9.CheckSourceFailure(lines, 'E1030: Using a String as a Number: "b"') - - - let lines =<< trim END - vim9script - def Fn() - var x = min(('a', 'b')) - enddef - Fn() - END - call v9.CheckSourceFailure(lines, 'E1030: Using a String as a Number: "a"') endfunc " Test for reduce() diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim index e955064074..0872081902 100644 --- a/src/testdir/test_vim9_assign.vim +++ b/src/testdir/test_vim9_assign.vim @@ -3229,7 +3229,7 @@ def Test_type_check() assert_fails('N = d', 'E1012: Type mismatch; expected number but got dict') assert_fails('N = l', 'E1012: Type mismatch; expected number but got list') assert_fails('N = b', 'E1012: Type mismatch; expected number but got blob') - assert_fails('N = Fn', 'E1012: Type mismatch; expected number but got func([unknown]): number') + assert_fails('N = Fn', 'E1012: Type mismatch; expected number but got func([unknown]): any') assert_fails('N = A', 'E1405: Class "A" cannot be used as a value') assert_fails('N = o', 'E1012: Type mismatch; expected number but got object') assert_fails('N = T', 'E1403: Type alias "T" cannot be used as a value') @@ -3247,7 +3247,7 @@ def Test_type_check() assert_fails('var [X1: number, Y: number] = [1, d]', 'E1012: Type mismatch; expected number but got dict') assert_fails('var [X2: number, Y: number] = [1, l]', 'E1012: Type mismatch; expected number but got list') assert_fails('var [X3: number, Y: number] = [1, b]', 'E1012: Type mismatch; expected number but got blob') - assert_fails('var [X4: number, Y: number] = [1, Fn]', 'E1012: Type mismatch; expected number but got func([unknown]): number') + assert_fails('var [X4: number, Y: number] = [1, Fn]', 'E1012: Type mismatch; expected number but got func([unknown]): any') assert_fails('var [X7: number, Y: number] = [1, A]', 'E1405: Class "A" cannot be used as a value') assert_fails('var [X8: number, Y: number] = [1, o]', 'E1012: Type mismatch; expected number but got object') assert_fails('var [X8: number, Y: number] = [1, T]', 'E1403: Type alias "T" cannot be used as a value') @@ -3345,7 +3345,7 @@ def Test_func_argtype_check() assert_fails('IntArg(d)', 'E1013: Argument 1: type mismatch, expected number but got dict') assert_fails('IntArg(l)', 'E1013: Argument 1: type mismatch, expected number but got list') assert_fails('IntArg(b)', 'E1013: Argument 1: type mismatch, expected number but got blob') - assert_fails('IntArg(Fn)', 'E1013: Argument 1: type mismatch, expected number but got func([unknown]): number') + assert_fails('IntArg(Fn)', 'E1013: Argument 1: type mismatch, expected number but got func([unknown]): any') if has('channel') var j: job = test_null_job() var ch: channel = test_null_channel() diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index 8e7bd61392..aac831794f 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -4910,8 +4910,8 @@ def Test_typename() if has('channel') assert_equal('channel', test_null_channel()->typename()) endif - var l: list): number> = [function('min')] - assert_equal('list): number>', typename(l)) + var l: list): any> = [function('min')] + assert_equal('list): any>', typename(l)) enddef def Test_undofile() diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 8109395849..f5e23e8eb7 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -4111,7 +4111,7 @@ enddef def Test_source_func_script_var() var lines =<< trim END vim9script noclear - var Fn: func(list): number + var Fn: func(list): any Fn = function('min') assert_equal(2, Fn([4, 2])) END diff --git a/src/tuple.c b/src/tuple.c index 9ca1f34092..84dcf342c6 100644 --- a/src/tuple.c +++ b/src/tuple.c @@ -951,31 +951,32 @@ indexof_tuple(tuple_T *tuple, long startidx, typval_T *expr) /* * Return the max or min of the items in tuple "tuple". - * If a tuple item is not a number, then "error" is set to TRUE. + * If an error occurs NULL is returned instead. */ - varnumber_T -tuple_max_min(tuple_T *tuple, int domax, int *error) + typval_T * +tuple_max_min(tuple_T *tuple, int domax) { - varnumber_T n = 0; - varnumber_T v; + typval_T *tv = NULL; + int res; if (tuple == NULL || TUPLE_LEN(tuple) == 0) - return 0; + return NULL; - n = tv_get_number_chk(TUPLE_ITEM(tuple, 0), error); - if (*error) - return n; // type error; errmsg already given - - for (int idx = 1; idx < TUPLE_LEN(tuple); idx++) + for (int idx = 0; idx < TUPLE_LEN(tuple); idx++) { - v = tv_get_number_chk(TUPLE_ITEM(tuple, idx), error); - if (*error) - return n; // type error; errmsg already given - if (domax ? v > n : v < n) - n = v; + if (tv == NULL) + tv = TUPLE_ITEM(tuple, idx); + else + { + if (typval_compare2(TUPLE_ITEM(tuple, idx), tv, + domax ? EXPR_GREATER : EXPR_SMALLER, FALSE, &res) == FAIL) + return NULL; + if (res == OK) + tv = TUPLE_ITEM(tuple, idx); + } } - return n; + return tv; } /* diff --git a/src/typval.c b/src/typval.c index db439cbd61..b4ee7ec63f 100644 --- a/src/typval.c +++ b/src/typval.c @@ -1475,30 +1475,26 @@ copy_tv(typval_T *from, typval_T *to) /* * Compare "tv1" and "tv2". - * Put the result in "tv1". Caller should clear "tv2". */ int -typval_compare( +typval_compare2( typval_T *tv1, // first operand typval_T *tv2, // second operand - exprtype_T type, // operator - int ic) // ignore case + exprtype_T type, // operator + int ic, // ignore case + int *res) // comparison result { varnumber_T n1, n2; - int res = 0; int type_is = type == EXPR_IS || type == EXPR_ISNOT; if (check_typval_is_value(tv1) == FAIL || check_typval_is_value(tv2) == FAIL) - { - clear_tv(tv1); return FAIL; - } else if (type_is && tv1->v_type != tv2->v_type) { // For "is" a different type always means FALSE, for "isnot" // it means TRUE. - n1 = (type == EXPR_ISNOT); + *res = (type == EXPR_ISNOT); } else if (((tv1->v_type == VAR_SPECIAL && tv1->vval.v_number == VVAL_NULL) || (tv2->v_type == VAR_SPECIAL @@ -1508,67 +1504,41 @@ typval_compare( { n1 = typval_compare_null(tv1, tv2); if (n1 == MAYBE) - { - clear_tv(tv1); return FAIL; - } if (type == EXPR_NEQUAL) n1 = !n1; + *res = n1; } else if (tv1->v_type == VAR_BLOB || tv2->v_type == VAR_BLOB) { - if (typval_compare_blob(tv1, tv2, type, &res) == FAIL) - { - clear_tv(tv1); + if (typval_compare_blob(tv1, tv2, type, res) == FAIL) return FAIL; - } - n1 = res; } else if (tv1->v_type == VAR_LIST || tv2->v_type == VAR_LIST) { - if (typval_compare_list(tv1, tv2, type, ic, &res) == FAIL) - { - clear_tv(tv1); + if (typval_compare_list(tv1, tv2, type, ic, res) == FAIL) return FAIL; - } - n1 = res; } else if (tv1->v_type == VAR_TUPLE || tv2->v_type == VAR_TUPLE) { - if (typval_compare_tuple(tv1, tv2, type, ic, &res) == FAIL) - { - clear_tv(tv1); + if (typval_compare_tuple(tv1, tv2, type, ic, res) == FAIL) return FAIL; - } - n1 = res; } else if (tv1->v_type == VAR_OBJECT || tv2->v_type == VAR_OBJECT) { - if (typval_compare_object(tv1, tv2, type, ic, &res) == FAIL) - { - clear_tv(tv1); + if (typval_compare_object(tv1, tv2, type, ic, res) == FAIL) return FAIL; - } - n1 = res; } else if (tv1->v_type == VAR_DICT || tv2->v_type == VAR_DICT) { - if (typval_compare_dict(tv1, tv2, type, ic, &res) == FAIL) - { - clear_tv(tv1); + if (typval_compare_dict(tv1, tv2, type, ic, res) == FAIL) return FAIL; - } - n1 = res; } else if (tv1->v_type == VAR_FUNC || tv2->v_type == VAR_FUNC || tv1->v_type == VAR_PARTIAL || tv2->v_type == VAR_PARTIAL) { - if (typval_compare_func(tv1, tv2, type, ic, &res) == FAIL) - { - clear_tv(tv1); + if (typval_compare_func(tv1, tv2, type, ic, res) == FAIL) return FAIL; - } - n1 = res; } // If one of the two variables is a float, compare as a float. @@ -1583,10 +1553,7 @@ typval_compare( if (!error) f2 = tv_get_float_chk(tv2, &error); if (error) - { - clear_tv(tv1); return FAIL; - } n1 = FALSE; switch (type) { @@ -1602,6 +1569,7 @@ typval_compare( case EXPR_MATCH: default: break; // avoid gcc warning } + *res = n1; } // If one of the two variables is a number, compare as a number. @@ -1615,10 +1583,7 @@ typval_compare( if (!error) n2 = tv_get_number_chk(tv2, &error); if (error) - { - clear_tv(tv1); return FAIL; - } switch (type) { case EXPR_IS: @@ -1633,6 +1598,7 @@ typval_compare( case EXPR_MATCH: default: break; // avoid gcc warning } + *res = n1; } else if (in_vim9script() && (tv1->v_type == VAR_BOOL || tv2->v_type == VAR_BOOL @@ -1643,7 +1609,6 @@ typval_compare( { semsg(_(e_cannot_compare_str_with_str), vartype_name(tv1->v_type), vartype_name(tv2->v_type)); - clear_tv(tv1); return FAIL; } n1 = tv1->vval.v_number; @@ -1657,9 +1622,9 @@ typval_compare( default: semsg(_(e_invalid_operation_for_str), vartype_name(tv1->v_type)); - clear_tv(tv1); return FAIL; } + *res = n1; } #ifdef FEAT_JOB_CHANNEL else if (tv1->v_type == tv2->v_type @@ -1672,27 +1637,47 @@ typval_compare( n1 = tv1->vval.v_job == tv2->vval.v_job; if (type == EXPR_NEQUAL) n1 = !n1; + *res = n1; } #endif else { - if (typval_compare_string(tv1, tv2, type, ic, &res) == FAIL) - { - clear_tv(tv1); + if (typval_compare_string(tv1, tv2, type, ic, res) == FAIL) return FAIL; - } - n1 = res; } + + return OK; +} + +/* + * Compare "tv1" and "tv2". + * Put the result in "tv1". Caller should clear "tv2". + */ + int +typval_compare( + typval_T *tv1, // first operand + typval_T *tv2, // second operand + exprtype_T type, // operator + int ic) // ignore case +{ + int res; + + if (typval_compare2(tv1, tv2, type, ic, &res) == FAIL) + { + clear_tv(tv1); + return FAIL; + } + clear_tv(tv1); if (in_vim9script()) { tv1->v_type = VAR_BOOL; - tv1->vval.v_number = n1 ? VVAL_TRUE : VVAL_FALSE; + tv1->vval.v_number = res ? VVAL_TRUE : VVAL_FALSE; } else { tv1->v_type = VAR_NUMBER; - tv1->vval.v_number = n1; + tv1->vval.v_number = res; } return OK; diff --git a/src/version.c b/src/version.c index 4f3912aedd..712a3e637c 100644 --- a/src/version.c +++ b/src/version.c @@ -724,6 +724,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1684, /**/ 1683, /**/