]> granicus.if.org Git - vim/commitdiff
patch 8.2.4529: Vim9: comparing partial with function fails v8.2.4529
authorBram Moolenaar <Bram@vim.org>
Tue, 8 Mar 2022 19:43:55 +0000 (19:43 +0000)
committerBram Moolenaar <Bram@vim.org>
Tue, 8 Mar 2022 19:43:55 +0000 (19:43 +0000)
Problem:    Vim9: comparing partial with function fails.
Solution:   Support this comparison.  Avoid a crash. (closes #9909)
            Add more test cases.

src/testdir/test_vim9_builtin.vim
src/testdir/test_vim9_expr.vim
src/testdir/test_vim9_func.vim
src/testdir/test_vimscript.vim
src/userfunc.c
src/version.c
src/vim9instr.c
src/vim9type.c

index 7577aecd2a18fd3448f7becd4053dd89de57a86d..8b9dbd605123e9083fb37a940bc29e597f50ba22 100644 (file)
@@ -1687,6 +1687,7 @@ def Test_getenv()
   endif
   $SOMEENVVAR = 'some'
   assert_equal('some', getenv('SOMEENVVAR'))
+  assert_notequal(null, getenv('SOMEENVVAR'))
   unlet $SOMEENVVAR
   getenv('')->assert_equal(v:null)
 enddef
@@ -4398,7 +4399,7 @@ def Test_typename()
   if has('float')
     assert_equal('func([unknown], [unknown]): float', typename(function('pow')))
   endif
-  assert_equal('func', test_null_partial()->typename())
+  assert_equal('func(...): unknown', test_null_partial()->typename())
   assert_equal('list<unknown>', test_null_list()->typename())
   assert_equal('dict<unknown>', test_null_dict()->typename())
   if has('job')
index a38254f7dc5856382d57d0df2f87557574bbe07a..4a3803a8f1178fc6999f555eed72cc95eed02593 100644 (file)
@@ -717,21 +717,33 @@ def Test_expr4_compare_null()
   g:not_null_list = []
   var lines =<< trim END
       assert_true(test_null_blob() == v:null)
+      assert_true(null_blob == null)
       assert_true(v:null == test_null_blob())
+      assert_true(null == null_blob)
       assert_false(test_null_blob() != v:null)
+      assert_false(null_blob != null)
       assert_false(v:null != test_null_blob())
+      assert_false(null != null_blob)
 
       if has('channel')
         assert_true(test_null_channel() == v:null)
+        assert_true(null_channel == null)
         assert_true(v:null == test_null_channel())
+        assert_true(null == null_channel)
         assert_false(test_null_channel() != v:null)
+        assert_false(null_channel != null)
         assert_false(v:null != test_null_channel())
+        assert_false(null != null_channel)
       endif
 
       assert_true(test_null_dict() == v:null)
+      assert_true(null_dict == null)
       assert_true(v:null == test_null_dict())
+      assert_true(null == null_dict)
       assert_false(test_null_dict() != v:null)
+      assert_false(null_dict != null)
       assert_false(v:null != test_null_dict())
+      assert_false(null != null_dict)
 
       assert_true(g:null_dict == v:null)
       assert_true(v:null == g:null_dict)
@@ -739,21 +751,33 @@ def Test_expr4_compare_null()
       assert_false(v:null != g:null_dict)
 
       assert_true(test_null_function() == v:null)
+      assert_true(null_function == null)
       assert_true(v:null == test_null_function())
+      assert_true(null == null_function)
       assert_false(test_null_function() != v:null)
+      assert_false(null_function != null)
       assert_false(v:null != test_null_function())
+      assert_false(null != null_function)
 
       if has('job')
         assert_true(test_null_job() == v:null)
+        assert_true(null_job == null)
         assert_true(v:null == test_null_job())
+        assert_true(null == null_job)
         assert_false(test_null_job() != v:null)
+        assert_false(null_job != null)
         assert_false(v:null != test_null_job())
+        assert_false(null != null_job)
       endif
 
       assert_true(test_null_list() == v:null)
+      assert_true(null_list == null)
       assert_true(v:null == test_null_list())
+      assert_true(null == null_list)
       assert_false(test_null_list() != v:null)
+      assert_false(null_list != null)
       assert_false(v:null != test_null_list())
+      assert_false(null != null_list)
 
       assert_false(g:not_null_list == v:null)
       assert_false(v:null == g:not_null_list)
@@ -761,19 +785,33 @@ def Test_expr4_compare_null()
       assert_true(v:null != g:not_null_list)
 
       assert_true(test_null_partial() == v:null)
+      assert_true(null_partial == null)
       assert_true(v:null == test_null_partial())
+      assert_true(null == null_partial)
       assert_false(test_null_partial() != v:null)
+      assert_false(null_partial != null)
       assert_false(v:null != test_null_partial())
+      assert_false(null != null_partial)
 
       assert_true(test_null_string() == v:null)
+      assert_true(null_string == null)
       assert_true(v:null == test_null_string())
+      assert_true(null == null_string)
       assert_false(test_null_string() != v:null)
+      assert_false(null_string != null)
       assert_false(v:null != test_null_string())
+      assert_false(null != null_string)
   END
   v9.CheckDefAndScriptSuccess(lines)
   unlet g:null_dict
   unlet g:not_null_list
 
+  lines =<< trim END
+      var d: dict<func> = {f: null_function}
+      assert_equal(null_function, d.f)
+  END
+  v9.CheckDefAndScriptSuccess(lines)
+
   v9.CheckDefAndScriptFailure(['echo 123 == v:null'], 'E1072: Cannot compare number with special')
   v9.CheckDefAndScriptFailure(['echo v:null == 123'], 'E1072: Cannot compare special with number')
   v9.CheckDefAndScriptFailure(['echo 123 != v:null'], 'E1072: Cannot compare number with special')
index 131413b160e986f62b5d2db4e795fa63c653e331..85e8e9d3dd3819de52b43fc2549212f268872485 100644 (file)
@@ -3341,7 +3341,7 @@ def Test_partial_null_function()
   var lines =<< trim END
       var d: dict<func> = {f: null_function}
       var Ref = d.f
-      assert_equal('func', typename(Ref))
+      assert_equal('func(...): unknown', typename(Ref))
   END
   v9.CheckDefAndScriptSuccess(lines)
 enddef
index 24dfd1b23fc306a52f33e7817d455f95f8d9e516..ce3dbca681f01c42843f82adab9c91aa5891294f 100644 (file)
@@ -6571,6 +6571,9 @@ func Test_type()
     call assert_false(v:true is 1)
     call assert_false(v:true is v:false)
     call assert_false(v:none is 0)
+    call assert_false(v:none is [])
+    call assert_false(v:none is {})
+    call assert_false(v:none is 'text')
     call assert_false(v:null is 0)
     call assert_false(v:null is v:none)
 
index f0abaee5f01ef2407854335b9448bf76cc757483..42e1e89bc369e3605912304a7ca3f330001b51c9 100644 (file)
@@ -5730,18 +5730,27 @@ func_has_abort(
 make_partial(dict_T *selfdict_in, typval_T *rettv)
 {
     char_u     *fname;
-    ufunc_T    *fp;
+    ufunc_T    *fp = NULL;
     char_u     fname_buf[FLEN_FIXED + 1];
     int                error;
     dict_T     *selfdict = selfdict_in;
 
-    if (rettv->v_type == VAR_PARTIAL && rettv->vval.v_partial->pt_func != NULL)
+    if (rettv->v_type == VAR_PARTIAL  && rettv->vval.v_partial != NULL
+                                    && rettv->vval.v_partial->pt_func != NULL)
        fp = rettv->vval.v_partial->pt_func;
     else
     {
        fname = rettv->v_type == VAR_FUNC ? rettv->vval.v_string
+                                        : rettv->vval.v_partial == NULL ? NULL
                                              : rettv->vval.v_partial->pt_name;
-       if (fname != NULL)
+       if (fname == NULL)
+       {
+           // There is no point binding a dict to a NULL function, just create
+           // a function reference.
+           rettv->v_type = VAR_FUNC;
+           rettv->vval.v_string = NULL;
+       }
+       else
        {
            char_u      *tofree = NULL;
 
@@ -5752,8 +5761,7 @@ make_partial(dict_T *selfdict_in, typval_T *rettv)
        }
     }
 
-    if ((fp != NULL && (fp->uf_flags & FC_DICT))
-               || (rettv->v_type == VAR_FUNC && rettv->vval.v_string == NULL))
+    if (fp != NULL && (fp->uf_flags & FC_DICT))
     {
        partial_T       *pt = ALLOC_CLEAR_ONE(partial_T);
 
index f6aaa79554f07941bd3951d990f294aac7d48d89..3e212db88bf6d5ef3cd878f06b9ab75ebd5269d3 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4529,
 /**/
     4528,
 /**/
index 7fbf529a6477e9e9acc8850a69e86cdf561f6613..e36ea16e2e9b36f6fd44449b211edda3b81dbcff 100644 (file)
@@ -370,7 +370,9 @@ get_compare_isn(exprtype_T exprtype, vartype_T type1, vartype_T type2)
     }
     else if (type1 == VAR_ANY || type2 == VAR_ANY
            || ((type1 == VAR_NUMBER || type1 == VAR_FLOAT)
-             && (type2 == VAR_NUMBER || type2 == VAR_FLOAT)))
+                              && (type2 == VAR_NUMBER || type2 == VAR_FLOAT))
+           || (type1 == VAR_FUNC && type2 == VAR_PARTIAL)
+           || (type1 == VAR_PARTIAL && type2 == VAR_FUNC))
        isntype = ISN_COMPAREANY;
     else if (type1 == VAR_SPECIAL || type2 == VAR_SPECIAL)
     {
index fe4dec59f03d1ae8b3761b411f060909254742fa..6a44c7b7c8ba266ebe647d3ccba6e5139eb7a725 100644 (file)
@@ -420,6 +420,8 @@ typval2type_int(typval_T *tv, int copyID, garray_T *type_gap, int flags)
        }
        else
            name = tv->vval.v_string;
+       if (name == NULL && ufunc == NULL)
+           return &t_func_unknown;
        if (name != NULL)
        {
            int idx = find_internal_func(name);