Skip to content

Commit c1ec042

Browse files
committed
patch 8.2.1650: Vim9: result of && and || expression is not bool in script
Problem: Vim9: result of && and || expression cannot be assigned to a bool at the script level. Solution: Add the VAR_BOOL_OK flag. Convert to bool when needed.
1 parent 3e4cc96 commit c1ec042

8 files changed

Lines changed: 92 additions & 29 deletions

File tree

src/eval.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2356,6 +2356,9 @@ eval2(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
23562356
clear_evalarg(&local_evalarg, NULL);
23572357
else
23582358
evalarg->eval_flags = orig_flags;
2359+
2360+
// Resulting value can be assigned to a bool.
2361+
rettv->v_lock |= VAR_BOOL_OK;
23592362
}
23602363

23612364
return OK;
@@ -2451,6 +2454,7 @@ eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
24512454
*arg = skipwhite_and_linebreak(*arg + 2, evalarg_used);
24522455
evalarg_used->eval_flags = result ? orig_flags
24532456
: orig_flags & ~EVAL_EVALUATE;
2457+
CLEAR_FIELD(var2);
24542458
if (eval4(arg, &var2, evalarg_used) == FAIL)
24552459
return FAIL;
24562460

@@ -2487,6 +2491,9 @@ eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
24872491
clear_evalarg(&local_evalarg, NULL);
24882492
else
24892493
evalarg->eval_flags = orig_flags;
2494+
2495+
// Resulting value can be assigned to a bool.
2496+
rettv->v_lock |= VAR_BOOL_OK;
24902497
}
24912498

24922499
return OK;

src/evalvars.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -778,7 +778,7 @@ ex_let(exarg_T *eap)
778778
evalarg_T evalarg;
779779
int len = 1;
780780

781-
rettv.v_type = VAR_UNKNOWN;
781+
CLEAR_FIELD(rettv);
782782
i = FAIL;
783783
if (has_assign || concat)
784784
{
@@ -2935,10 +2935,12 @@ set_var(
29352935
set_var_const(
29362936
char_u *name,
29372937
type_T *type,
2938-
typval_T *tv,
2938+
typval_T *tv_arg,
29392939
int copy, // make copy of value in "tv"
29402940
int flags) // LET_IS_CONST and/or LET_NO_COMMAND
29412941
{
2942+
typval_T *tv = tv_arg;
2943+
typval_T bool_tv;
29422944
dictitem_T *di;
29432945
char_u *varname;
29442946
hashtab_T *ht;
@@ -2971,6 +2973,15 @@ set_var_const(
29712973
&& var_wrong_func_name(name, di == NULL))
29722974
return;
29732975

2976+
if (need_convert_to_bool(type, tv))
2977+
{
2978+
// Destination is a bool and the value is not, but it can be converted.
2979+
CLEAR_FIELD(bool_tv);
2980+
bool_tv.v_type = VAR_BOOL;
2981+
bool_tv.vval.v_number = tv2bool(tv) ? VVAL_TRUE : VVAL_FALSE;
2982+
tv = &bool_tv;
2983+
}
2984+
29742985
if (di != NULL)
29752986
{
29762987
if ((di->di_flags & DI_FLAGS_RELOAD) == 0)
@@ -2989,7 +3000,7 @@ set_var_const(
29893000
return;
29903001
}
29913002

2992-
// check the type
3003+
// check the type and adjust to bool if needed
29933004
if (check_script_var_type(&di->di_tv, tv, name) == FAIL)
29943005
return;
29953006
}

src/proto/vim9type.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ type_T *get_dict_type(type_T *member_type, garray_T *type_gap);
66
type_T *alloc_func_type(type_T *ret_type, int argcount, garray_T *type_gap);
77
type_T *get_func_type(type_T *ret_type, int argcount, garray_T *type_gap);
88
int func_type_add_arg_types(type_T *functype, int argcount, garray_T *type_gap);
9+
int need_convert_to_bool(type_T *type, typval_T *tv);
910
type_T *typval2type(typval_T *tv, garray_T *type_gap);
1011
type_T *typval2type_vimvar(typval_T *tv, garray_T *type_gap);
1112
int check_typval_type(type_T *expected, typval_T *actual_tv, int argidx);

src/structs.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,7 +1381,7 @@ struct type_S {
13811381
typedef struct
13821382
{
13831383
vartype_T v_type;
1384-
char v_lock; // see below: VAR_LOCKED, VAR_FIXED
1384+
char v_lock; // see below: VAR_LOCKED, VAR_FIXED, VAR_BOOL_OK
13851385
union
13861386
{
13871387
varnumber_T v_number; // number value
@@ -1406,8 +1406,9 @@ typedef struct
14061406
// allowed to mask existing functions
14071407

14081408
// Values for "v_lock".
1409-
#define VAR_LOCKED 1 // locked with lock(), can use unlock()
1410-
#define VAR_FIXED 2 // locked forever
1409+
#define VAR_LOCKED 1 // locked with lock(), can use unlock()
1410+
#define VAR_FIXED 2 // locked forever
1411+
#define VAR_BOOL_OK 4 // can be convered to bool
14111412

14121413
/*
14131414
* Structure to hold an item of a list: an internal variable without a name.

src/testdir/test_vim9_script.vim

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,13 @@ def Test_assignment_bool()
6666
let flag: bool = GetFlag()
6767
assert_equal(true, flag)
6868
flag = 0
69-
# assert_equal(false, flag)
69+
assert_equal(false, flag)
7070
flag = 1
71-
# assert_equal(true, flag)
72-
# flag = 99 || 123
73-
# assert_equal(true, flag)
74-
# flag = 'yes' && []
75-
# assert_equal(false, flag)
71+
assert_equal(true, flag)
72+
flag = 99 || 123
73+
assert_equal(true, flag)
74+
flag = 'yes' && []
75+
assert_equal(false, flag)
7676
END
7777
CheckScriptSuccess(lines)
7878
CheckDefAndScriptFailure(['let x: bool = 2'], 'E1012:')

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+
1650,
753755
/**/
754756
1649,
755757
/**/

src/vim9script.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,7 @@ vim9_declare_scriptvar(exarg_T *eap, char_u *arg)
557557

558558
/*
559559
* Check if the type of script variable "dest" allows assigning "value".
560+
* If needed convert "value" to a bool.
560561
*/
561562
int
562563
check_script_var_type(typval_T *dest, typval_T *value, char_u *name)
@@ -575,12 +576,24 @@ check_script_var_type(typval_T *dest, typval_T *value, char_u *name)
575576

576577
if (sv->sv_tv == dest)
577578
{
579+
int ret;
580+
578581
if (sv->sv_const)
579582
{
580583
semsg(_(e_readonlyvar), name);
581584
return FAIL;
582585
}
583-
return check_typval_type(sv->sv_type, value, 0);
586+
ret = check_typval_type(sv->sv_type, value, 0);
587+
if (ret == OK && need_convert_to_bool(sv->sv_type, value))
588+
{
589+
int val = tv2bool(value);
590+
591+
clear_tv(value);
592+
value->v_type = VAR_BOOL;
593+
value->v_lock = 0;
594+
value->vval.v_number = val ? VVAL_TRUE : VVAL_FALSE;
595+
}
596+
return ret;
584597
}
585598
}
586599
iemsg("check_script_var_type(): not found");

src/vim9type.c

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -199,28 +199,16 @@ func_type_add_arg_types(
199199
* Get a type_T for a typval_T.
200200
* "type_list" is used to temporarily create types in.
201201
*/
202-
type_T *
203-
typval2type(typval_T *tv, garray_T *type_gap)
202+
static type_T *
203+
typval2type_int(typval_T *tv, garray_T *type_gap)
204204
{
205205
type_T *type;
206206
type_T *member_type;
207207

208208
if (tv->v_type == VAR_NUMBER)
209-
{
210-
if (tv->vval.v_number == 0 || tv->vval.v_number == 1)
211-
{
212-
// number 0 and 1 can also be used for bool
213-
type = alloc_type(type_gap);
214-
if (type == NULL)
215-
return NULL;
216-
type->tt_type = VAR_NUMBER;
217-
type->tt_flags = TTFLAG_BOOL_OK;
218-
return type;
219-
}
220209
return &t_number;
221-
}
222210
if (tv->v_type == VAR_BOOL)
223-
return &t_bool; // not used
211+
return &t_bool;
224212
if (tv->v_type == VAR_STRING)
225213
return &t_string;
226214

@@ -297,6 +285,46 @@ typval2type(typval_T *tv, garray_T *type_gap)
297285
return type;
298286
}
299287

288+
/*
289+
* Return TRUE if "tv" is not a bool but should be converted to bool.
290+
*/
291+
int
292+
need_convert_to_bool(type_T *type, typval_T *tv)
293+
{
294+
return type != NULL && type == &t_bool && tv->v_type != VAR_BOOL
295+
&& ((tv->v_lock & VAR_BOOL_OK)
296+
|| (tv->v_type == VAR_NUMBER
297+
&& (tv->vval.v_number == 0 || tv->vval.v_number == 1)));
298+
}
299+
300+
/*
301+
* Get a type_T for a typval_T and handle VAR_BOOL_OK.
302+
* "type_list" is used to temporarily create types in.
303+
*/
304+
type_T *
305+
typval2type(typval_T *tv, garray_T *type_gap)
306+
{
307+
type_T *type = typval2type_int(tv, type_gap);
308+
309+
if (type != NULL && type != &t_bool
310+
&& ((tv->v_type == VAR_NUMBER
311+
&& (tv->vval.v_number == 0 || tv->vval.v_number == 1))
312+
|| (tv->v_lock & VAR_BOOL_OK)))
313+
{
314+
type_T *newtype = alloc_type(type_gap);
315+
316+
// Number 0 and 1 and expression with "&&" or "||" can also be used
317+
// for bool.
318+
if (newtype != NULL)
319+
{
320+
*newtype = *type;
321+
newtype->tt_flags = TTFLAG_BOOL_OK;
322+
type = newtype;
323+
}
324+
}
325+
return type;
326+
}
327+
300328
/*
301329
* Get a type_T for a typval_T, used for v: variables.
302330
* "type_list" is used to temporarily create types in.
@@ -371,7 +399,7 @@ check_type(type_T *expected, type_T *actual, int give_msg, int argidx)
371399
{
372400
if (expected->tt_type != actual->tt_type)
373401
{
374-
if (expected->tt_type == VAR_BOOL && actual->tt_type == VAR_NUMBER
402+
if (expected->tt_type == VAR_BOOL
375403
&& (actual->tt_flags & TTFLAG_BOOL_OK))
376404
// Using number 0 or 1 for bool is OK.
377405
return OK;

0 commit comments

Comments
 (0)