0
0
mirror of https://github.com/vim/vim.git synced 2025-07-24 10:45:12 -04:00

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.
This commit is contained in:
Bram Moolenaar 2020-09-09 20:03:46 +02:00
parent 33e3346322
commit 4ed124cc6c
4 changed files with 66 additions and 2 deletions

View File

@ -1199,6 +1199,29 @@ def Test_disassemble_invert_bool()
assert_equal(true, InvertBool())
enddef
def ReturnBool(): bool
let var: bool = "no" && [] || 123
return var
enddef
def Test_disassemble_return_bool()
let instr = execute('disassemble ReturnBool')
assert_match('ReturnBool\_s*' ..
'let var: bool = "no" && \[\] || 123\_s*' ..
'0 PUSHS "no"\_s*' ..
'1 JUMP_AND_KEEP_IF_FALSE -> 3\_s*' ..
'2 NEWLIST size 0\_s*' ..
'3 JUMP_AND_KEEP_IF_TRUE -> 5\_s*' ..
'4 PUSHNR 123\_s*' ..
'5 2BOOL (!!val)\_s*' ..
'\d STORE $0\_s*' ..
'return var\_s*' ..
'\d LOAD $0\_s*' ..
'\d RETURN',
instr)
assert_equal(true, InvertBool())
enddef
def Test_disassemble_compare()
let cases = [
['true == isFalse', 'COMPAREBOOL =='],

View File

@ -46,9 +46,16 @@ def Test_assignment_bool()
assert_equal(v:false, bool2)
let bool3: bool = 0
assert_equal(0, bool3)
assert_equal(false, bool3)
let bool4: bool = 1
assert_equal(1, bool4)
assert_equal(true, bool4)
let bool5: bool = 'yes' && 'no'
assert_equal(true, bool5)
let bool6: bool = [] && 99
assert_equal(false, bool6)
let bool7: bool = [] || #{a: 1} && 99
assert_equal(true, bool7)
let lines =<< trim END
vim9script
@ -57,8 +64,15 @@ def Test_assignment_bool()
return flag
enddef
let flag: bool = GetFlag()
assert_equal(true, flag)
flag = 0
# assert_equal(false, flag)
flag = 1
# assert_equal(true, flag)
# flag = 99 || 123
# assert_equal(true, flag)
# flag = 'yes' && []
# assert_equal(false, flag)
END
CheckScriptSuccess(lines)
CheckDefAndScriptFailure(['let x: bool = 2'], 'E1012:')

View File

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

View File

@ -729,6 +729,15 @@ need_type(
cctx_T *cctx,
int silent)
{
if (expected == &t_bool && actual != &t_bool
&& (actual->tt_flags & TTFLAG_BOOL_OK))
{
// Using "0", "1" or the result of an expression with "&&" or "||" as a
// boolean is OK but requires a conversion.
generate_2BOOL(cctx, FALSE);
return OK;
}
if (check_type(expected, actual, FALSE, 0) == OK)
return OK;
if (actual->tt_type != VAR_ANY
@ -3926,6 +3935,8 @@ compile_and_or(
{
garray_T *instr = &cctx->ctx_instr;
garray_T end_ga;
garray_T *stack = &cctx->ctx_type_stack;
type_T **typep;
/*
* Repeat until there is no following "||" or "&&"
@ -3985,6 +3996,20 @@ compile_and_or(
isn->isn_arg.jump.jump_where = instr->ga_len;
}
ga_clear(&end_ga);
// The resulting type can be used as a bool.
typep = ((type_T **)stack->ga_data) + stack->ga_len - 1;
if (*typep != &t_bool)
{
type_T *type = alloc_type(cctx->ctx_type_list);
if (type != NULL)
{
*type = **typep;
type->tt_flags |= TTFLAG_BOOL_OK;
*typep = type;
}
}
}
return OK;