patch 9.1.1684: min()/max() does not handle float data types

Commit: 
https://github.com/vim/vim/commit/3b3b9361257c6659abb79586712886d8636387c5
Author: LemonBoy <[email protected]>
Date:   Sun Aug 24 13:09:04 2025 +0200

    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 <[email protected]>
    Signed-off-by: Christian Brabandt <[email protected]>

diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index 32cb40f1b..418bc47e5 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 b82071757..7e18266d7 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 91c7ca04e..13f1823d3 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 138648d3c..1ba029548 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 d30cdedc1..05283a173 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 9dd960181..9d66985d6 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 c6d8e819a..1d87fe119 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 e95506407..087208190 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<number>')
     assert_fails('N = l', 'E1012: Type mismatch; expected number but got 
list<number>')
     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<A>')
     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<number>')
     assert_fails('var [X2: number, Y: number] = [1, l]', 'E1012: Type 
mismatch; expected number but got list<number>')
     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<A>')
     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<number>')
     assert_fails('IntArg(l)', 'E1013: Argument 1: type mismatch, expected 
number but got list<number>')
     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 8e7bd6139..aac831794 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<func(list<number>): number> = [function('min')]
-  assert_equal('list<func(list<number>): number>', typename(l))
+  var l: list<func(list<number>): any> = [function('min')]
+  assert_equal('list<func(list<number>): any>', typename(l))
 enddef
 
 def Test_undofile()
diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim
index 810939584..f5e23e8eb 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<any>): number
+    var Fn: func(list<any>): any
     Fn = function('min')
     assert_equal(2, Fn([4, 2]))
   END
diff --git a/src/tuple.c b/src/tuple.c
index 9ca1f3409..84dcf342c 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;
-
-    n = tv_get_number_chk(TUPLE_ITEM(tuple, 0), error);
-    if (*error)
-       return n; // type error; errmsg already given
+       return NULL;
 
-    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 db439cbd6..b4ee7ec63 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 4f3912aed..712a3e637 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,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/vim_dev/E1uq8gh-00Gkan-OU%40256bit.org.

Raspunde prin e-mail lui