1
0
forked from aniani/vim

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.
This commit is contained in:
Bram Moolenaar 2022-03-08 19:43:55 +00:00
parent 673bcb10eb
commit ed0c62e7b1
8 changed files with 64 additions and 8 deletions

View File

@ -1687,6 +1687,7 @@ def Test_getenv()
endif endif
$SOMEENVVAR = 'some' $SOMEENVVAR = 'some'
assert_equal('some', getenv('SOMEENVVAR')) assert_equal('some', getenv('SOMEENVVAR'))
assert_notequal(null, getenv('SOMEENVVAR'))
unlet $SOMEENVVAR unlet $SOMEENVVAR
getenv('')->assert_equal(v:null) getenv('')->assert_equal(v:null)
enddef enddef
@ -4398,7 +4399,7 @@ def Test_typename()
if has('float') if has('float')
assert_equal('func([unknown], [unknown]): float', typename(function('pow'))) assert_equal('func([unknown], [unknown]): float', typename(function('pow')))
endif 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('list<unknown>', test_null_list()->typename())
assert_equal('dict<unknown>', test_null_dict()->typename()) assert_equal('dict<unknown>', test_null_dict()->typename())
if has('job') if has('job')

View File

@ -717,21 +717,33 @@ def Test_expr4_compare_null()
g:not_null_list = [] g:not_null_list = []
var lines =<< trim END var lines =<< trim END
assert_true(test_null_blob() == v:null) assert_true(test_null_blob() == v:null)
assert_true(null_blob == null)
assert_true(v:null == test_null_blob()) assert_true(v:null == test_null_blob())
assert_true(null == null_blob)
assert_false(test_null_blob() != v:null) assert_false(test_null_blob() != v:null)
assert_false(null_blob != null)
assert_false(v:null != test_null_blob()) assert_false(v:null != test_null_blob())
assert_false(null != null_blob)
if has('channel') if has('channel')
assert_true(test_null_channel() == v:null) assert_true(test_null_channel() == v:null)
assert_true(null_channel == null)
assert_true(v:null == test_null_channel()) assert_true(v:null == test_null_channel())
assert_true(null == null_channel)
assert_false(test_null_channel() != v:null) assert_false(test_null_channel() != v:null)
assert_false(null_channel != null)
assert_false(v:null != test_null_channel()) assert_false(v:null != test_null_channel())
assert_false(null != null_channel)
endif endif
assert_true(test_null_dict() == v:null) assert_true(test_null_dict() == v:null)
assert_true(null_dict == null)
assert_true(v:null == test_null_dict()) assert_true(v:null == test_null_dict())
assert_true(null == null_dict)
assert_false(test_null_dict() != v:null) assert_false(test_null_dict() != v:null)
assert_false(null_dict != null)
assert_false(v:null != test_null_dict()) assert_false(v:null != test_null_dict())
assert_false(null != null_dict)
assert_true(g:null_dict == v:null) assert_true(g:null_dict == v:null)
assert_true(v:null == g:null_dict) assert_true(v:null == g:null_dict)
@ -739,21 +751,33 @@ def Test_expr4_compare_null()
assert_false(v:null != g:null_dict) assert_false(v:null != g:null_dict)
assert_true(test_null_function() == v:null) assert_true(test_null_function() == v:null)
assert_true(null_function == null)
assert_true(v:null == test_null_function()) assert_true(v:null == test_null_function())
assert_true(null == null_function)
assert_false(test_null_function() != v:null) assert_false(test_null_function() != v:null)
assert_false(null_function != null)
assert_false(v:null != test_null_function()) assert_false(v:null != test_null_function())
assert_false(null != null_function)
if has('job') if has('job')
assert_true(test_null_job() == v:null) assert_true(test_null_job() == v:null)
assert_true(null_job == null)
assert_true(v:null == test_null_job()) assert_true(v:null == test_null_job())
assert_true(null == null_job)
assert_false(test_null_job() != v:null) assert_false(test_null_job() != v:null)
assert_false(null_job != null)
assert_false(v:null != test_null_job()) assert_false(v:null != test_null_job())
assert_false(null != null_job)
endif endif
assert_true(test_null_list() == v:null) assert_true(test_null_list() == v:null)
assert_true(null_list == null)
assert_true(v:null == test_null_list()) assert_true(v:null == test_null_list())
assert_true(null == null_list)
assert_false(test_null_list() != v:null) assert_false(test_null_list() != v:null)
assert_false(null_list != null)
assert_false(v:null != test_null_list()) assert_false(v:null != test_null_list())
assert_false(null != null_list)
assert_false(g:not_null_list == v:null) assert_false(g:not_null_list == v:null)
assert_false(v:null == g:not_null_list) 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(v:null != g:not_null_list)
assert_true(test_null_partial() == v:null) assert_true(test_null_partial() == v:null)
assert_true(null_partial == null)
assert_true(v:null == test_null_partial()) assert_true(v:null == test_null_partial())
assert_true(null == null_partial)
assert_false(test_null_partial() != v:null) assert_false(test_null_partial() != v:null)
assert_false(null_partial != null)
assert_false(v:null != test_null_partial()) assert_false(v:null != test_null_partial())
assert_false(null != null_partial)
assert_true(test_null_string() == v:null) assert_true(test_null_string() == v:null)
assert_true(null_string == null)
assert_true(v:null == test_null_string()) assert_true(v:null == test_null_string())
assert_true(null == null_string)
assert_false(test_null_string() != v:null) assert_false(test_null_string() != v:null)
assert_false(null_string != null)
assert_false(v:null != test_null_string()) assert_false(v:null != test_null_string())
assert_false(null != null_string)
END END
v9.CheckDefAndScriptSuccess(lines) v9.CheckDefAndScriptSuccess(lines)
unlet g:null_dict unlet g:null_dict
unlet g:not_null_list 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 123 == v:null'], 'E1072: Cannot compare number with special')
v9.CheckDefAndScriptFailure(['echo v:null == 123'], 'E1072: Cannot compare special with number') v9.CheckDefAndScriptFailure(['echo v:null == 123'], 'E1072: Cannot compare special with number')
v9.CheckDefAndScriptFailure(['echo 123 != v:null'], 'E1072: Cannot compare number with special') v9.CheckDefAndScriptFailure(['echo 123 != v:null'], 'E1072: Cannot compare number with special')

View File

@ -3341,7 +3341,7 @@ def Test_partial_null_function()
var lines =<< trim END var lines =<< trim END
var d: dict<func> = {f: null_function} var d: dict<func> = {f: null_function}
var Ref = d.f var Ref = d.f
assert_equal('func', typename(Ref)) assert_equal('func(...): unknown', typename(Ref))
END END
v9.CheckDefAndScriptSuccess(lines) v9.CheckDefAndScriptSuccess(lines)
enddef enddef

View File

@ -6571,6 +6571,9 @@ func Test_type()
call assert_false(v:true is 1) call assert_false(v:true is 1)
call assert_false(v:true is v:false) call assert_false(v:true is v:false)
call assert_false(v:none is 0) 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 0)
call assert_false(v:null is v:none) call assert_false(v:null is v:none)

View File

@ -5730,18 +5730,27 @@ func_has_abort(
make_partial(dict_T *selfdict_in, typval_T *rettv) make_partial(dict_T *selfdict_in, typval_T *rettv)
{ {
char_u *fname; char_u *fname;
ufunc_T *fp; ufunc_T *fp = NULL;
char_u fname_buf[FLEN_FIXED + 1]; char_u fname_buf[FLEN_FIXED + 1];
int error; int error;
dict_T *selfdict = selfdict_in; 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; fp = rettv->vval.v_partial->pt_func;
else else
{ {
fname = rettv->v_type == VAR_FUNC ? rettv->vval.v_string fname = rettv->v_type == VAR_FUNC ? rettv->vval.v_string
: rettv->vval.v_partial == NULL ? NULL
: rettv->vval.v_partial->pt_name; : 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; 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)) if (fp != NULL && (fp->uf_flags & FC_DICT))
|| (rettv->v_type == VAR_FUNC && rettv->vval.v_string == NULL))
{ {
partial_T *pt = ALLOC_CLEAR_ONE(partial_T); partial_T *pt = ALLOC_CLEAR_ONE(partial_T);

View File

@ -750,6 +750,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
4529,
/**/ /**/
4528, 4528,
/**/ /**/

View 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 else if (type1 == VAR_ANY || type2 == VAR_ANY
|| ((type1 == VAR_NUMBER || type1 == VAR_FLOAT) || ((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; isntype = ISN_COMPAREANY;
else if (type1 == VAR_SPECIAL || type2 == VAR_SPECIAL) else if (type1 == VAR_SPECIAL || type2 == VAR_SPECIAL)
{ {

View File

@ -420,6 +420,8 @@ typval2type_int(typval_T *tv, int copyID, garray_T *type_gap, int flags)
} }
else else
name = tv->vval.v_string; name = tv->vval.v_string;
if (name == NULL && ufunc == NULL)
return &t_func_unknown;
if (name != NULL) if (name != NULL)
{ {
int idx = find_internal_func(name); int idx = find_internal_func(name);