patch 9.1.1546: Vim9: error with has() and short circuit evaluation
Commit:
https://github.com/vim/vim/commit/8de753148f6300aa00f0c3c5dacec3b1ca886c34
Author: Yegappan Lakshmanan <[email protected]>
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 <[email protected]>
Signed-off-by: Christian Brabandt <[email protected]>
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 [email protected].
To view this discussion visit
https://groups.google.com/d/msgid/vim_dev/E1ubkeF-007dbI-HM%40256bit.org.