summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authordearblue <[email protected]>2021-11-24 23:34:31 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2021-11-26 12:18:41 +0900
commit668b12e7566282f6c0165252e2b2f5432964020a (patch)
treee8d2cd84b26ed6980f3c83b5ee7a2ef83225083b /src
parentb631c226eb3e59a813224183bbc9ddc2a01acd0e (diff)
downloadmruby-668b12e7566282f6c0165252e2b2f5432964020a.tar.gz
mruby-668b12e7566282f6c0165252e2b2f5432964020a.zip
Check more `MRB_ARGS_NONE()`
The `__id__` method implemented in the C function has `MRB_ARGS_NONE()` specified, but it is also effective in the following cases. ```ruby p nil.__id__ opts: 1 rescue p :a p nil.method(:__id__).call 1 rescue p :b p nil.method(:__id__).call opts: 1 rescue p :c p nil.method(:__id__).to_proc.call 1 rescue p :d p nil.method(:__id__).to_proc.call opts: 1 rescue p :e p nil.method(:__id__).unbind.bind_call nil, 1 rescue p :f p nil.method(:__id__).unbind.bind_call nil, opts: 1 rescue p :g p nil.__send__ :__id__, 1 rescue p :h p nil.__send__ :__id__, opts: 1 rescue p :i ``` After applying this patch, all items will output symbols in the same way as CRuby. For this purpose, add `MRB_PROC_NOARG` to `struct RProc::flags`.
Diffstat (limited to 'src')
-rw-r--r--src/vm.c28
1 files changed, 27 insertions, 1 deletions
diff --git a/src/vm.c b/src/vm.c
index dabf12240..65af8dcc0 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -541,6 +541,18 @@ mrb_funcall_argv(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, cons
return mrb_funcall_with_block(mrb, self, mid, argc, argv, mrb_nil_value());
}
+static void
+check_method_noarg(mrb_state *mrb, const mrb_callinfo *ci)
+{
+ int argc = ci->n == CALL_MAXARGS ? RARRAY_LEN(ci->stack[1]) : ci->n;
+ if (ci->nk != 0 && !mrb_hash_empty_p(mrb, ci->stack[ci->n == CALL_MAXARGS ? 2 : ci->n + 1])) {
+ argc++;
+ }
+ if (argc > 0) {
+ mrb_argnum_error(mrb, argc, 0, 0);
+ }
+}
+
static mrb_value
exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p)
{
@@ -550,6 +562,9 @@ exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p)
ci->stack[0] = self;
mrb_vm_ci_proc_set(ci, p);
if (MRB_PROC_CFUNC_P(p)) {
+ if (MRB_PROC_NOARG_P(p)) {
+ check_method_noarg(mrb, ci);
+ }
return MRB_PROC_CFUNC(p)(mrb, self);
}
nregs = p->body.irep->nregs;
@@ -577,6 +592,9 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p)
else {
mrb_value ret;
if (MRB_PROC_CFUNC_P(p)) {
+ if (MRB_PROC_NOARG_P(p)) {
+ check_method_noarg(mrb, ci);
+ }
cipush(mrb, 0, CINFO_DIRECT, mrb_vm_ci_target_class(ci), p, ci->mid, ci->n|(ci->nk<<4));
ret = MRB_PROC_CFUNC(p)(mrb, self);
cipop(mrb);
@@ -665,6 +683,10 @@ mrb_f_send(mrb_state *mrb, mrb_value self)
}
if (MRB_METHOD_CFUNC_P(m)) {
+ if (MRB_METHOD_NOARG_P(m)) {
+ check_method_noarg(mrb, ci);
+ }
+
if (MRB_METHOD_PROC_P(m)) {
mrb_vm_ci_proc_set(ci, MRB_METHOD_PROC(m));
}
@@ -938,6 +960,9 @@ argnum_error(mrb_state *mrb, mrb_int num)
argc = RARRAY_LEN(args);
}
}
+ if (argc == 0 && mrb->c->ci->nk != 0 && !mrb_hash_empty_p(mrb, mrb->c->ci->stack[1])) {
+ argc++;
+ }
if (mrb->c->ci->mid) {
str = mrb_format(mrb, "'%n': wrong number of arguments (%i for %i)",
mrb->c->ci->mid, argc, num);
@@ -1617,7 +1642,8 @@ RETRY_TRY_BLOCK:
recv = p->body.func(mrb, recv);
}
else if (MRB_METHOD_NOARG_P(m) &&
- !(n == 0 || (n == CALL_MAXARGS && RARRAY_LEN(regs[1]) == 0))) {
+ (!(n == 0 || (n == CALL_MAXARGS && RARRAY_LEN(regs[1]) == 0)) ||
+ !(nk == 0 || mrb_hash_empty_p(mrb, regs[n == CALL_MAXARGS ? 2 : n + 1])))) {
argnum_error(mrb, 0);
goto L_RAISE;
}