Skip to content

Commit ed0c62e

Browse files
committed
patch 8.2.4529: Vim9: comparing partial with function fails
Problem: Vim9: comparing partial with function fails. Solution: Support this comparison. Avoid a crash. (closes #9909) Add more test cases.
1 parent 673bcb1 commit ed0c62e

File tree

8 files changed

+64
-8
lines changed

8 files changed

+64
-8
lines changed

src/testdir/test_vim9_builtin.vim

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1687,6 +1687,7 @@ def Test_getenv()
16871687
endif
16881688
$SOMEENVVAR = 'some'
16891689
assert_equal('some', getenv('SOMEENVVAR'))
1690+
assert_notequal(null, getenv('SOMEENVVAR'))
16901691
unlet $SOMEENVVAR
16911692
getenv('')->assert_equal(v:null)
16921693
enddef
@@ -4398,7 +4399,7 @@ def Test_typename()
43984399
if has('float')
43994400
assert_equal('func([unknown], [unknown]): float', typename(function('pow')))
44004401
endif
4401-
assert_equal('func', test_null_partial()->typename())
4402+
assert_equal('func(...): unknown', test_null_partial()->typename())
44024403
assert_equal('list<unknown>', test_null_list()->typename())
44034404
assert_equal('dict<unknown>', test_null_dict()->typename())
44044405
if has('job')

src/testdir/test_vim9_expr.vim

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,63 +717,101 @@ def Test_expr4_compare_null()
717717
g:not_null_list = []
718718
var lines =<< trim END
719719
assert_true(test_null_blob() == v:null)
720+
assert_true(null_blob == null)
720721
assert_true(v:null == test_null_blob())
722+
assert_true(null == null_blob)
721723
assert_false(test_null_blob() != v:null)
724+
assert_false(null_blob != null)
722725
assert_false(v:null != test_null_blob())
726+
assert_false(null != null_blob)
723727

724728
if has('channel')
725729
assert_true(test_null_channel() == v:null)
730+
assert_true(null_channel == null)
726731
assert_true(v:null == test_null_channel())
732+
assert_true(null == null_channel)
727733
assert_false(test_null_channel() != v:null)
734+
assert_false(null_channel != null)
728735
assert_false(v:null != test_null_channel())
736+
assert_false(null != null_channel)
729737
endif
730738

731739
assert_true(test_null_dict() == v:null)
740+
assert_true(null_dict == null)
732741
assert_true(v:null == test_null_dict())
742+
assert_true(null == null_dict)
733743
assert_false(test_null_dict() != v:null)
744+
assert_false(null_dict != null)
734745
assert_false(v:null != test_null_dict())
746+
assert_false(null != null_dict)
735747

736748
assert_true(g:null_dict == v:null)
737749
assert_true(v:null == g:null_dict)
738750
assert_false(g:null_dict != v:null)
739751
assert_false(v:null != g:null_dict)
740752

741753
assert_true(test_null_function() == v:null)
754+
assert_true(null_function == null)
742755
assert_true(v:null == test_null_function())
756+
assert_true(null == null_function)
743757
assert_false(test_null_function() != v:null)
758+
assert_false(null_function != null)
744759
assert_false(v:null != test_null_function())
760+
assert_false(null != null_function)
745761

746762
if has('job')
747763
assert_true(test_null_job() == v:null)
764+
assert_true(null_job == null)
748765
assert_true(v:null == test_null_job())
766+
assert_true(null == null_job)
749767
assert_false(test_null_job() != v:null)
768+
assert_false(null_job != null)
750769
assert_false(v:null != test_null_job())
770+
assert_false(null != null_job)
751771
endif
752772

753773
assert_true(test_null_list() == v:null)
774+
assert_true(null_list == null)
754775
assert_true(v:null == test_null_list())
776+
assert_true(null == null_list)
755777
assert_false(test_null_list() != v:null)
778+
assert_false(null_list != null)
756779
assert_false(v:null != test_null_list())
780+
assert_false(null != null_list)
757781

758782
assert_false(g:not_null_list == v:null)
759783
assert_false(v:null == g:not_null_list)
760784
assert_true(g:not_null_list != v:null)
761785
assert_true(v:null != g:not_null_list)
762786

763787
assert_true(test_null_partial() == v:null)
788+
assert_true(null_partial == null)
764789
assert_true(v:null == test_null_partial())
790+
assert_true(null == null_partial)
765791
assert_false(test_null_partial() != v:null)
792+
assert_false(null_partial != null)
766793
assert_false(v:null != test_null_partial())
794+
assert_false(null != null_partial)
767795

768796
assert_true(test_null_string() == v:null)
797+
assert_true(null_string == null)
769798
assert_true(v:null == test_null_string())
799+
assert_true(null == null_string)
770800
assert_false(test_null_string() != v:null)
801+
assert_false(null_string != null)
771802
assert_false(v:null != test_null_string())
803+
assert_false(null != null_string)
772804
END
773805
v9.CheckDefAndScriptSuccess(lines)
774806
unlet g:null_dict
775807
unlet g:not_null_list
776808

809+
lines =<< trim END
810+
var d: dict<func> = {f: null_function}
811+
assert_equal(null_function, d.f)
812+
END
813+
v9.CheckDefAndScriptSuccess(lines)
814+
777815
v9.CheckDefAndScriptFailure(['echo 123 == v:null'], 'E1072: Cannot compare number with special')
778816
v9.CheckDefAndScriptFailure(['echo v:null == 123'], 'E1072: Cannot compare special with number')
779817
v9.CheckDefAndScriptFailure(['echo 123 != v:null'], 'E1072: Cannot compare number with special')

src/testdir/test_vim9_func.vim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3341,7 +3341,7 @@ def Test_partial_null_function()
33413341
var lines =<< trim END
33423342
var d: dict<func> = {f: null_function}
33433343
var Ref = d.f
3344-
assert_equal('func', typename(Ref))
3344+
assert_equal('func(...): unknown', typename(Ref))
33453345
END
33463346
v9.CheckDefAndScriptSuccess(lines)
33473347
enddef

src/testdir/test_vimscript.vim

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6571,6 +6571,9 @@ func Test_type()
65716571
call assert_false(v:true is 1)
65726572
call assert_false(v:true is v:false)
65736573
call assert_false(v:none is 0)
6574+
call assert_false(v:none is [])
6575+
call assert_false(v:none is {})
6576+
call assert_false(v:none is 'text')
65746577
call assert_false(v:null is 0)
65756578
call assert_false(v:null is v:none)
65766579

src/userfunc.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5730,18 +5730,27 @@ func_has_abort(
57305730
make_partial(dict_T *selfdict_in, typval_T *rettv)
57315731
{
57325732
char_u *fname;
5733-
ufunc_T *fp;
5733+
ufunc_T *fp = NULL;
57345734
char_u fname_buf[FLEN_FIXED + 1];
57355735
int error;
57365736
dict_T *selfdict = selfdict_in;
57375737

5738-
if (rettv->v_type == VAR_PARTIAL && rettv->vval.v_partial->pt_func != NULL)
5738+
if (rettv->v_type == VAR_PARTIAL && rettv->vval.v_partial != NULL
5739+
&& rettv->vval.v_partial->pt_func != NULL)
57395740
fp = rettv->vval.v_partial->pt_func;
57405741
else
57415742
{
57425743
fname = rettv->v_type == VAR_FUNC ? rettv->vval.v_string
5744+
: rettv->vval.v_partial == NULL ? NULL
57435745
: rettv->vval.v_partial->pt_name;
5744-
if (fname != NULL)
5746+
if (fname == NULL)
5747+
{
5748+
// There is no point binding a dict to a NULL function, just create
5749+
// a function reference.
5750+
rettv->v_type = VAR_FUNC;
5751+
rettv->vval.v_string = NULL;
5752+
}
5753+
else
57455754
{
57465755
char_u *tofree = NULL;
57475756

@@ -5752,8 +5761,7 @@ make_partial(dict_T *selfdict_in, typval_T *rettv)
57525761
}
57535762
}
57545763

5755-
if ((fp != NULL && (fp->uf_flags & FC_DICT))
5756-
|| (rettv->v_type == VAR_FUNC && rettv->vval.v_string == NULL))
5764+
if (fp != NULL && (fp->uf_flags & FC_DICT))
57575765
{
57585766
partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
57595767

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,8 @@ static char *(features[]) =
750750

751751
static int included_patches[] =
752752
{ /* Add new patch number below this line */
753+
/**/
754+
4529,
753755
/**/
754756
4528,
755757
/**/

src/vim9instr.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,9 @@ get_compare_isn(exprtype_T exprtype, vartype_T type1, vartype_T type2)
370370
}
371371
else if (type1 == VAR_ANY || type2 == VAR_ANY
372372
|| ((type1 == VAR_NUMBER || type1 == VAR_FLOAT)
373-
&& (type2 == VAR_NUMBER || type2 == VAR_FLOAT)))
373+
&& (type2 == VAR_NUMBER || type2 == VAR_FLOAT))
374+
|| (type1 == VAR_FUNC && type2 == VAR_PARTIAL)
375+
|| (type1 == VAR_PARTIAL && type2 == VAR_FUNC))
374376
isntype = ISN_COMPAREANY;
375377
else if (type1 == VAR_SPECIAL || type2 == VAR_SPECIAL)
376378
{

src/vim9type.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,8 @@ typval2type_int(typval_T *tv, int copyID, garray_T *type_gap, int flags)
420420
}
421421
else
422422
name = tv->vval.v_string;
423+
if (name == NULL && ufunc == NULL)
424+
return &t_func_unknown;
423425
if (name != NULL)
424426
{
425427
int idx = find_internal_func(name);

0 commit comments

Comments
 (0)