patch 9.1.1546: Vim9: error with has() and short circuit evaluation Commit: https://github.com/vim/vim/commit/8de753148f6300aa00f0c3c5dacec3b1ca886c34 Author: Yegappan Lakshmanan <yegap...@yahoo.com> Date: Tue Jul 15 20:26:52 2025 +0200
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 <yegap...@yahoo.com> Signed-off-by: Christian Brabandt <c...@256bit.org> diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index 4a86a9b56..04b5e1118 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -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 diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index d4043d1db..2e70a3ba9 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -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 diff --git a/src/version.c b/src/version.c index e4084d585..16b71bb68 100644 --- a/src/version.c +++ b/src/version.c @@ -719,6 +719,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1546, /**/ 1545, /**/ diff --git a/src/vim9expr.c b/src/vim9expr.c index d169ed75a..33c0dafb7 100644 --- a/src/vim9expr.c +++ b/src/vim9expr.c @@ -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]); -- -- You received this message from the "vim_dev" maillist. Do not top-post! Type your reply below the text you are replying to. For more information, visit http://www.vim.org/maillist.php --- You received this message because you are subscribed to the Google Groups "vim_dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to vim_dev+unsubscr...@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/vim_dev/E1ubkeF-007dbI-HM%40256bit.org.