mirror of
https://github.com/macvim-dev/macvim.git
synced 2026-06-11 15:37:29 +02:00
patch 9.2.0292: E340 internal error when using method call on void value
Problem: E340 internal error when using method call on void value
(Peter Kenny)
Solution: Check for void value (Hirohito Higashi)
Using a method call on a void return value (e.g. "echo F()->empty()"
where F() returns void) caused an internal error E340. Now it properly
reports E1031 or E1186 depending on the context.
Changes:
- eval.c: check for void value before -> method call at runtime
- vim9expr.c: check for void type before -> method call at compile time
- vim9execute.c: check for void value in builtin function arguments and in
ISN_STORE
fixes: #19897
closes: #19912
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
cb51add7ae
commit
a9d01da661
+7
-1
@@ -7566,7 +7566,13 @@ handle_subscript(
|
||||
*arg = skipwhite(p + 2);
|
||||
else
|
||||
*arg = p + 2;
|
||||
if (VIM_ISWHITE(**arg))
|
||||
if (ret == OK && evaluate && rettv->v_type == VAR_VOID)
|
||||
{
|
||||
if (verbose)
|
||||
emsg(_(e_cannot_use_void_value));
|
||||
ret = FAIL;
|
||||
}
|
||||
else if (VIM_ISWHITE(**arg))
|
||||
{
|
||||
emsg(_(e_no_white_space_allowed_before_parenthesis));
|
||||
ret = FAIL;
|
||||
|
||||
@@ -402,7 +402,7 @@ enddef
|
||||
|
||||
def Test_bufload()
|
||||
assert_fails('bufload([])', 'E1220:')
|
||||
bufload('')->assert_equal(0)
|
||||
bufload('')
|
||||
enddef
|
||||
|
||||
def Test_bufloaded()
|
||||
@@ -647,7 +647,7 @@ def Test_ch_logfile()
|
||||
else
|
||||
assert_fails('ch_logfile(true)', 'E1174:')
|
||||
assert_fails('ch_logfile("foo", true)', 'E1174:')
|
||||
ch_logfile('', '')->assert_equal(0)
|
||||
ch_logfile('', '')
|
||||
|
||||
v9.CheckSourceDefAndScriptFailure(['ch_logfile(1)'], ['E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1'])
|
||||
v9.CheckSourceDefAndScriptFailure(['ch_logfile("a", true)'], ['E1013: Argument 2: type mismatch, expected string but got bool', 'E1174: String required for argument 2'])
|
||||
|
||||
@@ -3996,7 +3996,7 @@ def Test_expr9_method_call()
|
||||
enddef
|
||||
RetVoid()->byteidx(3)
|
||||
END
|
||||
v9.CheckDefExecFailure(lines, 'E1013:')
|
||||
v9.CheckDefExecFailure(lines, 'E1031: Cannot use void value')
|
||||
|
||||
lines =<< trim END
|
||||
const SetList = [function('len')]
|
||||
|
||||
@@ -4864,4 +4864,144 @@ if has('perl')
|
||||
endif
|
||||
|
||||
|
||||
def Test_void_method_chain()
|
||||
#### Case 1: Echo, method chain source is void ####
|
||||
# outside def: runtime error
|
||||
var lines =<< trim END
|
||||
vim9script
|
||||
var Fn1a: func = (): void => {
|
||||
}
|
||||
echo Fn1a()->empty()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1031: Cannot use void value')
|
||||
|
||||
# inside def, compile-time error (known void return)
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
def Fn1b(): void
|
||||
enddef
|
||||
def TestFunc()
|
||||
echo Fn1b()->empty()
|
||||
enddef
|
||||
defcompile TestFunc
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1031: Cannot use void value')
|
||||
|
||||
# inside def, runtime error (untyped func)
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
def TestFunc()
|
||||
var Fn1c: func = (): void => {
|
||||
}
|
||||
echo Fn1c()->empty()
|
||||
enddef
|
||||
TestFunc()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1031: Cannot use void value')
|
||||
|
||||
# inside def, compile-time error (func(): void)
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
def TestFunc()
|
||||
var Fn1d: func(): void = () => {
|
||||
}
|
||||
echo Fn1d()->empty()
|
||||
enddef
|
||||
defcompile TestFunc
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1031: Cannot use void value')
|
||||
|
||||
#### Case 2: Echo, method chain destination is void ####
|
||||
# outside def: runtime error
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
var Fn2a: func = (s: string): void => {
|
||||
}
|
||||
echo "x"->Fn2a()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1186: Expression does not result in a value: "x"->Fn2a()')
|
||||
|
||||
# inside def, compile-time error (known void return)
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
def Fn2b(s: string): void
|
||||
enddef
|
||||
def TestFunc()
|
||||
echo "x"->Fn2b()
|
||||
enddef
|
||||
defcompile TestFunc
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1186: Expression does not result in a value: "x"->Fn2b()')
|
||||
|
||||
# inside def, runtime error (untyped func)
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
def TestFunc()
|
||||
var Fn2c: func = (s: string): void => {
|
||||
}
|
||||
echo "x"->Fn2c()
|
||||
enddef
|
||||
TestFunc()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1031: Cannot use void value')
|
||||
|
||||
# inside def, compile-time error (func(string): void)
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
def TestFunc()
|
||||
var Fn2d: func(string): void = (s: string): void => {
|
||||
}
|
||||
echo "x"->Fn2d()
|
||||
enddef
|
||||
defcompile TestFunc
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1186: Expression does not result in a value: "x"->Fn2d()')
|
||||
|
||||
#### Case 3: Assignment, RHS is void ####
|
||||
# outside def: runtime error
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
var Fn3a: func = (): void => {
|
||||
}
|
||||
var x = Fn3a()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1031: Cannot use void value')
|
||||
|
||||
# inside def, compile-time error (known void return)
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
def Fn3b(): void
|
||||
enddef
|
||||
def TestFunc()
|
||||
var x = Fn3b()
|
||||
enddef
|
||||
defcompile TestFunc
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1031: Cannot use void value')
|
||||
|
||||
# inside def, runtime error (untyped func)
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
def TestFunc()
|
||||
var Fn3c: func = (): void => {
|
||||
}
|
||||
var x = Fn3c()
|
||||
enddef
|
||||
TestFunc()
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1031: Cannot use void value')
|
||||
|
||||
# inside def, compile-time error (func(): void)
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
def TestFunc()
|
||||
var Fn3d: func(): void = () => {
|
||||
}
|
||||
var x = Fn3d()
|
||||
enddef
|
||||
defcompile TestFunc
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1031: Cannot use void value')
|
||||
enddef
|
||||
|
||||
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
||||
|
||||
@@ -734,6 +734,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
292,
|
||||
/**/
|
||||
291,
|
||||
/**/
|
||||
|
||||
+15
-1
@@ -1412,6 +1412,17 @@ call_bfunc(int func_idx, int argcount, ectx_T *ectx)
|
||||
|
||||
if (call_prepare(argcount, argvars, ectx) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
// Check for void value being passed as an argument.
|
||||
for (idx = 0; idx < argcount; ++idx)
|
||||
if (argvars[idx].v_type == VAR_VOID)
|
||||
{
|
||||
emsg(_(e_cannot_use_void_value));
|
||||
for (idx = 0; idx < argcount; ++idx)
|
||||
clear_tv(&argvars[idx]);
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
ectx->ec_where.wt_func_name = internal_func_name(func_idx);
|
||||
|
||||
// Call the builtin function. Set "current_ectx" so that when it
|
||||
@@ -4307,8 +4318,11 @@ exec_instructions(ectx_T *ectx)
|
||||
case ISN_STORE:
|
||||
--ectx->ec_stack.ga_len;
|
||||
tv = STACK_TV_VAR(iptr->isn_arg.number);
|
||||
if (check_typval_is_value(STACK_TV_BOT(0)) == FAIL)
|
||||
if (check_typval_is_value(STACK_TV_BOT(0)) == FAIL
|
||||
|| STACK_TV_BOT(0)->v_type == VAR_VOID)
|
||||
{
|
||||
if (STACK_TV_BOT(0)->v_type == VAR_VOID)
|
||||
emsg(_(e_cannot_use_void_value));
|
||||
clear_tv(STACK_TV_BOT(0));
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
@@ -2568,6 +2568,13 @@ compile_subscript(
|
||||
return FAIL;
|
||||
ppconst->pp_is_const = FALSE;
|
||||
|
||||
type = get_type_on_stack(cctx, 0);
|
||||
if (type->tt_type == VAR_VOID)
|
||||
{
|
||||
emsg(_(e_cannot_use_void_value));
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
// Apply the '!', '-' and '+' first:
|
||||
// -1.0->func() works like (-1.0)->func()
|
||||
if (compile_leader(cctx, TRUE, start_leader, end_leader) == FAIL)
|
||||
|
||||
Reference in New Issue
Block a user