1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Struct setter's parameters == [:req, :_]

fix [Bug #18405]

Note that the parameter name `_` is not a spec, so we shouldn't
rely on this behavior.
This commit is contained in:
Koichi Sasada 2021-12-13 01:58:21 +09:00
parent 4d0cb1a54b
commit 6659253cc6
Notes: git 2021-12-13 10:24:24 +09:00
2 changed files with 80 additions and 6 deletions

71
proc.c
View file

@ -1259,7 +1259,7 @@ rb_proc_get_iseq(VALUE self, int *is_proc)
return rb_proc_get_iseq(block->as.proc, is_proc);
case block_type_ifunc:
{
const struct vm_ifunc *ifunc = block->as.captured.code.ifunc;
const struct vm_ifunc *ifunc = block->as.captured.code.ifunc;
if (IS_METHOD_PROC_IFUNC(ifunc)) {
/* method(:foo).to_proc */
if (is_proc) *is_proc = 0;
@ -2910,6 +2910,69 @@ rb_method_location(VALUE method)
return method_def_location(rb_method_def(method));
}
static const rb_method_definition_t *
vm_proc_method_def(VALUE procval)
{
const rb_proc_t *proc;
const struct rb_block *block;
const struct vm_ifunc *ifunc;
GetProcPtr(procval, proc);
block = &proc->block;
if (vm_block_type(block) == block_type_ifunc &&
IS_METHOD_PROC_IFUNC(ifunc = block->as.captured.code.ifunc)) {
return rb_method_def((VALUE)ifunc->data);
}
else {
return NULL;
}
}
static VALUE
method_def_parameters(const rb_method_definition_t *def)
{
const rb_iseq_t *iseq;
const rb_method_definition_t *bmethod_def;
switch (def->type) {
case VM_METHOD_TYPE_ISEQ:
iseq = method_def_iseq(def);
return rb_iseq_parameters(iseq, 0);
case VM_METHOD_TYPE_BMETHOD:
if ((iseq = method_def_iseq(def)) != NULL) {
return rb_iseq_parameters(iseq, 0);
}
else if ((bmethod_def = vm_proc_method_def(def->body.bmethod.proc)) != NULL) {
return method_def_parameters(bmethod_def);
}
break;
case VM_METHOD_TYPE_ALIAS:
return method_def_parameters(def->body.alias.original_me->def);
case VM_METHOD_TYPE_OPTIMIZED:
if (def->body.optimized.type == OPTIMIZED_METHOD_TYPE_STRUCT_ASET) {
VALUE param = rb_ary_new_from_args(2, ID2SYM(rb_intern("req")), ID2SYM(rb_intern("_")));
return rb_ary_new_from_args(1, param);
}
break;
case VM_METHOD_TYPE_CFUNC:
case VM_METHOD_TYPE_ATTRSET:
case VM_METHOD_TYPE_IVAR:
case VM_METHOD_TYPE_ZSUPER:
case VM_METHOD_TYPE_UNDEF:
case VM_METHOD_TYPE_NOTIMPLEMENTED:
case VM_METHOD_TYPE_MISSING:
case VM_METHOD_TYPE_REFINED:
break;
}
return rb_unnamed_parameters(method_def_aritry(def));
}
/*
* call-seq:
* meth.parameters -> array
@ -2932,11 +2995,7 @@ rb_method_location(VALUE method)
static VALUE
rb_method_parameters(VALUE method)
{
const rb_iseq_t *iseq = rb_method_iseq(method);
if (!iseq) {
return rb_unnamed_parameters(method_arity(method));
}
return rb_iseq_parameters(iseq, 0);
return method_def_parameters(rb_method_def(method));
}
/*

View file

@ -497,6 +497,21 @@ module TestStruct
assert_equal(42, x.public_send("a"))
end
def test_parameters
klass = @Struct.new(:a)
assert_equal [], klass.instance_method(:a).parameters
# NOTE: :_ may not be a spec.
assert_equal [[:req, :_]], klass.instance_method(:a=).parameters
klass.module_eval do
define_method(:b=, &klass.new.method(:a=).to_proc)
alias c= a=
end
assert_equal [[:req, :_]], klass.instance_method(:b=).parameters
assert_equal [[:req, :_]], klass.instance_method(:c=).parameters
end
class TopStruct < Test::Unit::TestCase
include TestStruct