forked from aniani/vim
patch 8.2.4642: Vim9: in :def function script var cannot be null
Problem: Vim9: in :def function script var cannot be null. Solution: Only initialize a script variable when not set to a null value. (closes #10034)
This commit is contained in:
@@ -2823,7 +2823,7 @@ eval_variable(
|
||||
{
|
||||
if (tv->v_type == VAR_DICT && tv->vval.v_dict == NULL
|
||||
&& ((type != NULL && type != &t_dict_empty)
|
||||
|| !in_vim9script()))
|
||||
|| !in_vim9script()))
|
||||
{
|
||||
tv->vval.v_dict = dict_alloc();
|
||||
if (tv->vval.v_dict != NULL)
|
||||
@@ -2843,6 +2843,14 @@ eval_variable(
|
||||
tv->vval.v_list->lv_type = alloc_type(type);
|
||||
}
|
||||
}
|
||||
else if (tv->v_type == VAR_BLOB && tv->vval.v_blob == NULL
|
||||
&& ((type != NULL && type != &t_blob_null)
|
||||
|| !in_vim9script()))
|
||||
{
|
||||
tv->vval.v_blob = blob_alloc();
|
||||
if (tv->vval.v_blob != NULL)
|
||||
++tv->vval.v_blob->bv_refcount;
|
||||
}
|
||||
}
|
||||
copy_tv(tv, rettv);
|
||||
}
|
||||
|
@@ -405,6 +405,7 @@ EXTERN type_T t_number_bool INIT6(VAR_NUMBER, 0, 0, TTFLAG_STATIC|TTFLAG_BOOL_OK
|
||||
EXTERN type_T t_float INIT6(VAR_FLOAT, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
||||
EXTERN type_T t_string INIT6(VAR_STRING, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
||||
EXTERN type_T t_blob INIT6(VAR_BLOB, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
||||
EXTERN type_T t_blob_null INIT6(VAR_BLOB, 0, 0, TTFLAG_STATIC, &t_void, NULL);
|
||||
EXTERN type_T t_job INIT6(VAR_JOB, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
||||
EXTERN type_T t_channel INIT6(VAR_CHANNEL, 0, 0, TTFLAG_STATIC, NULL, NULL);
|
||||
|
||||
|
@@ -890,6 +890,93 @@ def Test_expr4_compare_null()
|
||||
unlet g:null_dict
|
||||
unlet g:not_null_list
|
||||
|
||||
# variables declared at script level used in a :def function
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
|
||||
var l_decl: list<number>
|
||||
var l_empty = []
|
||||
var l_null = null_list
|
||||
|
||||
def TestList()
|
||||
assert_false(l_decl == null)
|
||||
assert_false(l_decl is null_list)
|
||||
assert_false(l_empty == null)
|
||||
assert_false(l_empty is null_list)
|
||||
assert_true(l_null == null)
|
||||
assert_true(l_null is null_list)
|
||||
assert_true(l_null == null_list)
|
||||
|
||||
add(l_decl, 6)
|
||||
assert_equal([6], l_decl)
|
||||
add(l_empty, 7)
|
||||
assert_equal([7], l_empty)
|
||||
var caught = false
|
||||
try
|
||||
add(l_null, 9)
|
||||
catch /E1130:/
|
||||
caught = true
|
||||
endtry
|
||||
assert_true(caught)
|
||||
enddef
|
||||
TestList()
|
||||
|
||||
var b_decl: blob
|
||||
var b_empty = 0z
|
||||
var b_null = null_blob
|
||||
|
||||
def TestBlob()
|
||||
assert_false(b_decl == null)
|
||||
assert_false(b_decl is null_blob)
|
||||
assert_false(b_empty == null)
|
||||
assert_false(b_empty is null_blob)
|
||||
assert_true(b_null == null)
|
||||
assert_true(b_null is null_blob)
|
||||
assert_true(b_null == null_blob)
|
||||
|
||||
add(b_decl, 6)
|
||||
assert_equal(0z06, b_decl)
|
||||
add(b_empty, 7)
|
||||
assert_equal(0z07, b_empty)
|
||||
var caught = false
|
||||
try
|
||||
add(b_null, 9)
|
||||
catch /E1131:/
|
||||
caught = true
|
||||
endtry
|
||||
assert_true(caught)
|
||||
enddef
|
||||
TestBlob()
|
||||
|
||||
var d_decl: dict<number>
|
||||
var d_empty = {}
|
||||
var d_null = null_dict
|
||||
|
||||
def TestDict()
|
||||
assert_false(d_decl == null)
|
||||
assert_false(d_decl is null_dict)
|
||||
assert_false(d_empty == null)
|
||||
assert_false(d_empty is null_dict)
|
||||
assert_true(d_null == null)
|
||||
assert_true(d_null is null_dict)
|
||||
assert_true(d_null == null_dict)
|
||||
|
||||
d_decl['a'] = 6
|
||||
assert_equal({a: 6}, d_decl)
|
||||
d_empty['b'] = 7
|
||||
assert_equal({b: 7}, d_empty)
|
||||
var caught = false
|
||||
try
|
||||
d_null['c'] = 9
|
||||
catch /E1103:/
|
||||
caught = true
|
||||
endtry
|
||||
assert_true(caught)
|
||||
enddef
|
||||
TestDict()
|
||||
END
|
||||
v9.CheckScriptSuccess(lines)
|
||||
|
||||
lines =<< trim END
|
||||
var d: dict<func> = {f: null_function}
|
||||
assert_equal(null_function, d.f)
|
||||
|
@@ -750,6 +750,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
4642,
|
||||
/**/
|
||||
4641,
|
||||
/**/
|
||||
|
@@ -2229,6 +2229,7 @@ typedef enum {
|
||||
#define ASSIGN_UNPACK 0x10 // using [a, b] = list
|
||||
#define ASSIGN_NO_MEMBER_TYPE 0x20 // use "any" for list and dict member type
|
||||
#define ASSIGN_FOR_LOOP 0x40 // assigning to loop variable
|
||||
#define ASSIGN_INIT 0x80 // not assigning a value, just a declaration
|
||||
|
||||
#include "ex_cmds.h" // Ex command defines
|
||||
#include "spell.h" // spell checking stuff
|
||||
|
@@ -1336,20 +1336,22 @@ do_2string(typval_T *tv, int is_2string_any, int tolerant)
|
||||
* When the value of "sv" is a null list of dict, allocate it.
|
||||
*/
|
||||
static void
|
||||
allocate_if_null(typval_T *tv)
|
||||
allocate_if_null(svar_T *sv)
|
||||
{
|
||||
typval_T *tv = sv->sv_tv;
|
||||
|
||||
switch (tv->v_type)
|
||||
{
|
||||
case VAR_LIST:
|
||||
if (tv->vval.v_list == NULL)
|
||||
if (tv->vval.v_list == NULL && sv->sv_type != &t_list_empty)
|
||||
(void)rettv_list_alloc(tv);
|
||||
break;
|
||||
case VAR_DICT:
|
||||
if (tv->vval.v_dict == NULL)
|
||||
if (tv->vval.v_dict == NULL && sv->sv_type != &t_dict_empty)
|
||||
(void)rettv_dict_alloc(tv);
|
||||
break;
|
||||
case VAR_BLOB:
|
||||
if (tv->vval.v_blob == NULL)
|
||||
if (tv->vval.v_blob == NULL && sv->sv_type != &t_blob_null)
|
||||
(void)rettv_blob_alloc(tv);
|
||||
break;
|
||||
default:
|
||||
@@ -2891,7 +2893,7 @@ exec_instructions(ectx_T *ectx)
|
||||
sv = get_script_svar(sref, ectx->ec_dfunc_idx);
|
||||
if (sv == NULL)
|
||||
goto theend;
|
||||
allocate_if_null(sv->sv_tv);
|
||||
allocate_if_null(sv);
|
||||
if (GA_GROW_FAILS(&ectx->ec_stack, 1))
|
||||
goto theend;
|
||||
copy_tv(sv->sv_tv, STACK_TV_BOT(0));
|
||||
|
@@ -822,7 +822,7 @@ vim9_declare_scriptvar(exarg_T *eap, char_u *arg)
|
||||
init_tv.v_type = VAR_NUMBER;
|
||||
else
|
||||
init_tv.v_type = type->tt_type;
|
||||
set_var_const(name, 0, type, &init_tv, FALSE, 0, 0);
|
||||
set_var_const(name, 0, type, &init_tv, FALSE, ASSIGN_INIT, 0);
|
||||
|
||||
vim_free(name);
|
||||
return p;
|
||||
@@ -925,6 +925,13 @@ update_vim9_script_var(
|
||||
if (*type == NULL)
|
||||
*type = typval2type(tv, get_copyID(), &si->sn_type_list,
|
||||
do_member ? TVTT_DO_MEMBER : 0);
|
||||
else if ((flags & ASSIGN_INIT) == 0
|
||||
&& (*type)->tt_type == VAR_BLOB && tv->v_type == VAR_BLOB
|
||||
&& tv->vval.v_blob == NULL)
|
||||
{
|
||||
// "var b: blob = null_blob" has a different type.
|
||||
*type = &t_blob_null;
|
||||
}
|
||||
if (sv->sv_type_allocated)
|
||||
free_type(sv->sv_type);
|
||||
if (*type != NULL && ((*type)->tt_type == VAR_FUNC
|
||||
|
@@ -337,7 +337,11 @@ typval2type_int(typval_T *tv, int copyID, garray_T *type_gap, int flags)
|
||||
if (tv->v_type == VAR_STRING)
|
||||
return &t_string;
|
||||
if (tv->v_type == VAR_BLOB)
|
||||
{
|
||||
if (tv->vval.v_blob == NULL)
|
||||
return &t_blob_null;
|
||||
return &t_blob;
|
||||
}
|
||||
|
||||
if (tv->v_type == VAR_LIST)
|
||||
{
|
||||
|
Reference in New Issue
Block a user