Skip to content

Commit 4ed124c

Browse files
committed
patch 8.2.1647: Vim9: result of expression with && and || is not a bool
Problem: Vim9: result of expression with && and || cannot be assigned to a bool variable. Solution: Add the TTFLAG_BOOL_OK flag and convert the value if needed.
1 parent 33e3346 commit 4ed124c

4 files changed

Lines changed: 66 additions & 2 deletions

File tree

src/testdir/test_vim9_disassemble.vim

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,6 +1199,29 @@ def Test_disassemble_invert_bool()
11991199
assert_equal(true, InvertBool())
12001200
enddef
12011201

1202+
def ReturnBool(): bool
1203+
let var: bool = "no" && [] || 123
1204+
return var
1205+
enddef
1206+
1207+
def Test_disassemble_return_bool()
1208+
let instr = execute('disassemble ReturnBool')
1209+
assert_match('ReturnBool\_s*' ..
1210+
'let var: bool = "no" && \[\] || 123\_s*' ..
1211+
'0 PUSHS "no"\_s*' ..
1212+
'1 JUMP_AND_KEEP_IF_FALSE -> 3\_s*' ..
1213+
'2 NEWLIST size 0\_s*' ..
1214+
'3 JUMP_AND_KEEP_IF_TRUE -> 5\_s*' ..
1215+
'4 PUSHNR 123\_s*' ..
1216+
'5 2BOOL (!!val)\_s*' ..
1217+
'\d STORE $0\_s*' ..
1218+
'return var\_s*' ..
1219+
'\d LOAD $0\_s*' ..
1220+
'\d RETURN',
1221+
instr)
1222+
assert_equal(true, InvertBool())
1223+
enddef
1224+
12021225
def Test_disassemble_compare()
12031226
let cases = [
12041227
['true == isFalse', 'COMPAREBOOL =='],

src/testdir/test_vim9_script.vim

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,16 @@ def Test_assignment_bool()
4646
assert_equal(v:false, bool2)
4747

4848
let bool3: bool = 0
49-
assert_equal(0, bool3)
49+
assert_equal(false, bool3)
5050
let bool4: bool = 1
51-
assert_equal(1, bool4)
51+
assert_equal(true, bool4)
52+
53+
let bool5: bool = 'yes' && 'no'
54+
assert_equal(true, bool5)
55+
let bool6: bool = [] && 99
56+
assert_equal(false, bool6)
57+
let bool7: bool = [] || #{a: 1} && 99
58+
assert_equal(true, bool7)
5259

5360
let lines =<< trim END
5461
vim9script
@@ -57,8 +64,15 @@ def Test_assignment_bool()
5764
return flag
5865
enddef
5966
let flag: bool = GetFlag()
67+
assert_equal(true, flag)
6068
flag = 0
69+
# assert_equal(false, flag)
6170
flag = 1
71+
# assert_equal(true, flag)
72+
# flag = 99 || 123
73+
# assert_equal(true, flag)
74+
# flag = 'yes' && []
75+
# assert_equal(false, flag)
6276
END
6377
CheckScriptSuccess(lines)
6478
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+
1647,
753755
/**/
754756
1646,
755757
/**/

src/vim9compile.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,15 @@ need_type(
729729
cctx_T *cctx,
730730
int silent)
731731
{
732+
if (expected == &t_bool && actual != &t_bool
733+
&& (actual->tt_flags & TTFLAG_BOOL_OK))
734+
{
735+
// Using "0", "1" or the result of an expression with "&&" or "||" as a
736+
// boolean is OK but requires a conversion.
737+
generate_2BOOL(cctx, FALSE);
738+
return OK;
739+
}
740+
732741
if (check_type(expected, actual, FALSE, 0) == OK)
733742
return OK;
734743
if (actual->tt_type != VAR_ANY
@@ -3926,6 +3935,8 @@ compile_and_or(
39263935
{
39273936
garray_T *instr = &cctx->ctx_instr;
39283937
garray_T end_ga;
3938+
garray_T *stack = &cctx->ctx_type_stack;
3939+
type_T **typep;
39293940

39303941
/*
39313942
* Repeat until there is no following "||" or "&&"
@@ -3985,6 +3996,20 @@ compile_and_or(
39853996
isn->isn_arg.jump.jump_where = instr->ga_len;
39863997
}
39873998
ga_clear(&end_ga);
3999+
4000+
// The resulting type can be used as a bool.
4001+
typep = ((type_T **)stack->ga_data) + stack->ga_len - 1;
4002+
if (*typep != &t_bool)
4003+
{
4004+
type_T *type = alloc_type(cctx->ctx_type_list);
4005+
4006+
if (type != NULL)
4007+
{
4008+
*type = **typep;
4009+
type->tt_flags |= TTFLAG_BOOL_OK;
4010+
*typep = type;
4011+
}
4012+
}
39884013
}
39894014

39904015
return OK;

0 commit comments

Comments
 (0)