0
0
mirror of https://github.com/vim/vim.git synced 2025-07-26 11:04:33 -04:00

patch 9.1.1546: Vim9: error with has() and short circuit evaluation

Problem:  Vim9: error with has() and short circuit evaluation
Solution: Only eval, if ctx_skip is not SKIP_YES (Yegappan Lakshmanan).

fixes: #17750
closes: #17755

Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Yegappan Lakshmanan 2025-07-15 20:26:52 +02:00 committed by Christian Brabandt
parent edce68912e
commit 8de753148f
No known key found for this signature in database
GPG Key ID: F3F92DA383FDDE09
4 changed files with 241 additions and 11 deletions

View File

@ -3875,4 +3875,131 @@ def Test_disassemble_assign_tuple_set_type()
unlet g:instr
enddef
" Disassemble the code generated for a has() function call
def Test_disassemble_has_shortcircuit()
# true && false condition check
var lines =<< trim END
vim9script
def Fn(): string
if has('jumplist') && has('foobar')
return 'present'
endif
return 'missing'
enddef
g:instr = execute('disassemble Fn')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d\+_Fn\_s*' ..
'if has(''jumplist'') && has(''foobar'')\_s*' ..
'return ''present''\_s*' ..
'endif\_s*' ..
'return ''missing''\_s*' ..
'0 PUSHS "missing"\_s*' ..
'1 RETURN', g:instr)
# false && true condition check
lines =<< trim END
vim9script
def Fn(): string
if has('foobar') && has('jumplist')
return 'present'
endif
return 'missing'
enddef
g:instr = execute('disassemble Fn')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d\+_Fn\_s*' ..
'if has(''foobar'') && has(''jumplist'')\_s*' ..
'return ''present''\_s*' ..
'endif\_s*' ..
'return ''missing''\_s*' ..
'0 PUSHS "missing"\_s*' ..
'1 RETURN', g:instr)
# false && false condition check
lines =<< trim END
vim9script
def Fn(): string
if has('foobar') && has('foobaz')
return 'present'
endif
return 'missing'
enddef
g:instr = execute('disassemble Fn')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d\+_Fn\_s*' ..
'if has(''foobar'') && has(''foobaz'')\_s*' ..
'return ''present''\_s*' ..
'endif\_s*' ..
'return ''missing''\_s*' ..
'0 PUSHS "missing"\_s*' ..
'1 RETURN', g:instr)
# true || false condition check
lines =<< trim END
vim9script
def Fn(): string
if has('jumplist') || has('foobar')
return 'present'
endif
return 'missing'
enddef
g:instr = execute('disassemble Fn')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d\+_Fn\_s*' ..
'if has(''jumplist'') || has(''foobar'')\_s*' ..
'return ''present''\_s*' ..
'0 PUSHS "present"\_s*' ..
'1 RETURN\_s*' ..
'endif\_s*' ..
'return ''missing''\_s*' ..
'2 PUSHS "missing"\_s*' ..
'3 RETURN', g:instr)
# false || true condition check
lines =<< trim END
vim9script
def Fn(): string
if has('foobar') || has('jumplist')
return 'present'
endif
return 'missing'
enddef
g:instr = execute('disassemble Fn')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d\+_Fn\_s*' ..
'if has(''foobar'') || has(''jumplist'')\_s*' ..
'return ''present''\_s*' ..
'0 PUSHS "present"\_s*' ..
'1 RETURN\_s*' ..
'endif\_s*' ..
'return ''missing''\_s*' ..
'2 PUSHS "missing"\_s*' ..
'3 RETURN', g:instr)
# false || false condition check
lines =<< trim END
vim9script
def Fn(): string
if has('foobar') || has('foobaz')
return 'present'
endif
return 'missing'
enddef
g:instr = execute('disassemble Fn')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d\+_Fn\_s*' ..
'if has(''foobar'') || has(''foobaz'')\_s*' ..
'return ''present''\_s*' ..
'endif\_s*' ..
'return ''missing''\_s*' ..
'0 PUSHS "missing"\_s*' ..
'1 RETURN', g:instr)
enddef
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker

View File

@ -5265,6 +5265,102 @@ def Test_method_call_with_list_arg()
v9.CheckSourceSuccess(lines)
enddef
" Test for using more than one has() check in a compound if condition.
def Test_has_func_shortcircuit()
def Has_And1_Cond(): string
# true && false
if has('jumplist') && has('foobar')
return 'present'
endif
return 'missing'
enddef
assert_equal('missing', Has_And1_Cond())
def Has_And2_Cond(): string
# false && true
if has('foobar') && has('jumplist')
return 'present'
endif
return 'missing'
enddef
assert_equal('missing', Has_And2_Cond())
def Has_And3_Cond(): string
# false && false
if has('foobar') && has('foobaz')
return 'present'
endif
return 'missing'
enddef
assert_equal('missing', Has_And3_Cond())
def Has_Or1_Cond(): string
# true || false
if has('jumplist') || has('foobar')
return 'present'
endif
return 'missing'
enddef
assert_equal('present', Has_Or1_Cond())
def Has_Or2_Cond(): string
# false || true
if has('foobar') || has('jumplist')
return 'present'
endif
return 'missing'
enddef
assert_equal('present', Has_Or2_Cond())
def Has_Or3_Cond(): string
# false || false
if has('foobar') || has('foobaz')
return 'present'
endif
return 'missing'
enddef
assert_equal('missing', Has_Or3_Cond())
enddef
" Test for using more than one len() function in a compound if condition.
def Test_len_func_shortcircuit()
def Len_And1_Cond(): string
# true && false
if len('xxx') == 3 && len('yyy') == 2
return 'match'
endif
return 'nomatch'
enddef
assert_equal('nomatch', Len_And1_Cond())
def Len_And2_Cond(): string
# false && true
if len('xxx') == 2 && len('yyy') == 3
return 'match'
endif
return 'nomatch'
enddef
assert_equal('nomatch', Len_And2_Cond())
def Len_Or1_Cond(): string
# true || false
if len('xxx') == 3 || len('yyy') == 2
return 'match'
endif
return 'nomatch'
enddef
assert_equal('match', Len_Or1_Cond())
def Len_Or2_Cond(): string
# false || true
if len('xxx') == 2 || len('yyy') == 3
return 'match'
endif
return 'nomatch'
enddef
assert_equal('match', Len_Or2_Cond())
enddef
" Keep this last, it messes up highlighting.
def Test_substitute_cmd()
new

View File

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

View File

@ -1233,20 +1233,25 @@ compile_call(
&& ((is_has && !dynamic_feature(argvars[0].vval.v_string))
|| !is_has))
{
typval_T *tv = &ppconst->pp_tv[ppconst->pp_used];
*arg = s + 1;
argvars[1].v_type = VAR_UNKNOWN;
tv->v_type = VAR_NUMBER;
tv->vval.v_number = 0;
if (is_has)
f_has(argvars, tv);
else if (is_len)
f_len(argvars, tv);
else
f_exists(argvars, tv);
if (cctx->ctx_skip != SKIP_YES)
{
typval_T *tv = &ppconst->pp_tv[ppconst->pp_used];
argvars[1].v_type = VAR_UNKNOWN;
tv->v_type = VAR_NUMBER;
tv->vval.v_number = 0;
if (is_has)
f_has(argvars, tv);
else if (is_len)
f_len(argvars, tv);
else
f_exists(argvars, tv);
++ppconst->pp_used;
}
clear_tv(&argvars[0]);
++ppconst->pp_used;
return OK;
}
clear_tv(&argvars[0]);