Skip to content

Commit 43d6c59

Browse files
committed
Start handling &nil in method parameters
Similar to `:nokey` for `**nil` declaring methods/procs, a method/proc with a `&nil` declaration will return a `:noblock` entry in the parameters array.
1 parent b1b9bbd commit 43d6c59

8 files changed

Lines changed: 54 additions & 3 deletions

File tree

iseq.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3787,7 +3787,13 @@ rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
37873787
}
37883788
rb_ary_push(args, a);
37893789
}
3790-
if (body->param.flags.has_block) {
3790+
if (body->param.flags.accepts_no_block) {
3791+
ID noblock;
3792+
CONST_ID(noblock, "noblock");
3793+
PARAM_TYPE(noblock);
3794+
rb_ary_push(args, a);
3795+
}
3796+
else if (body->param.flags.has_block) {
37913797
CONST_ID(block, "block");
37923798
rb_ary_push(args, PARAM(body->param.block_start, block));
37933799
}

proc.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3431,6 +3431,7 @@ method_inspect(VALUE method)
34313431
const VALUE keyrest = ID2SYM(rb_intern("keyrest"));
34323432
const VALUE block = ID2SYM(rb_intern("block"));
34333433
const VALUE nokey = ID2SYM(rb_intern("nokey"));
3434+
const VALUE noblock = ID2SYM(rb_intern("noblock"));
34343435
int forwarding = 0;
34353436

34363437
rb_str_buf_cat2(str, "(");
@@ -3465,6 +3466,9 @@ method_inspect(VALUE method)
34653466
else if (kind == nokey) {
34663467
name = rb_str_new2("nil");
34673468
}
3469+
else if (kind == noblock) {
3470+
name = rb_str_new2("nil");
3471+
}
34683472
else {
34693473
name = Qnil;
34703474
}
@@ -3517,6 +3521,9 @@ method_inspect(VALUE method)
35173521
else if (kind == nokey) {
35183522
rb_str_buf_cat2(str, "**nil");
35193523
}
3524+
else if (kind == noblock) {
3525+
rb_str_buf_cat2(str, "&nil");
3526+
}
35203527

35213528
if (i < RARRAY_LEN(params) - 1) {
35223529
rb_str_buf_cat2(str, ", ");

spec/ruby/core/method/parameters_spec.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ def one_splat_one_block(*args, &block)
2222
local_is_not_parameter = {}
2323
end
2424

25+
ruby_version_is "4.1" do
26+
eval <<-RUBY
27+
def one_noblock(&nil); end
28+
RUBY
29+
end
30+
2531
def forward_parameters(...) end
2632

2733
def underscore_parameters(_, _, _ = 1, *_, _:, _: 2, **_, &_); end
@@ -187,6 +193,13 @@ def underscore_parameters(_, _, _ = 1, *_, _:, _: 2, **_, &_); end
187193
m.parameters.should == [[:nokey]]
188194
end
189195

196+
ruby_version_is "4.1" do
197+
it "returns [[:noblock]] for a method with a single &nil parameter" do
198+
m = MethodSpecs::Methods.instance_method(:one_noblock)
199+
m.parameters.should == [[:noblock]]
200+
end
201+
end
202+
190203
it "works with ->(){} as the value of an optional argument" do
191204
m = MethodSpecs::Methods.instance_method(:one_opt_with_stabby)
192205
m.parameters.should == [[:opt,:a]]

spec/ruby/core/proc/parameters_spec.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,4 +172,12 @@
172172
eval("lambda { it }").parameters.should == [[:req]]
173173
end
174174
end
175+
176+
ruby_version_is "4.1" do
177+
it "returns :noblock for &nil parameter" do
178+
eval <<~RUBY
179+
proc { |&nil| }.parameters.should == [[:noblock]]
180+
RUBY
181+
end
182+
end
175183
end

spec/ruby/language/block_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1111,7 +1111,7 @@ def o.it
11111111
end
11121112
end
11131113

1114-
ruby_version_is "3.4" do
1114+
ruby_version_is "4.1" do
11151115
it "works alongside disallowed block argument" do
11161116
no_block = eval <<-EOF
11171117
proc {|arg1, &nil| arg1}

spec/ruby/language/method_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1128,7 +1128,7 @@ def m(a, b = nil, c = nil, d, e: nil, **f)
11281128
result.should == [1, nil, nil, {foo: :bar}, nil, {}]
11291129
end
11301130

1131-
ruby_version_is "3.4" do
1131+
ruby_version_is "4.1" do
11321132
evaluate <<-ruby do
11331133
def m(a, &nil); a end;
11341134
ruby

test/ruby/test_iseq.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,17 @@ def foo(**nil); end
682682
assert_equal([[:nokey]], iseq.eval.singleton_method(:foo).parameters)
683683
end
684684

685+
def test_to_binary_dumps_noblock
686+
iseq = assert_iseq_to_binary(<<-RUBY)
687+
o = Object.new
688+
class << o
689+
def foo(&nil); end
690+
end
691+
o
692+
RUBY
693+
assert_equal([[:noblock]], iseq.eval.singleton_method(:foo).parameters)
694+
end
695+
685696
def test_to_binary_line_info
686697
assert_iseq_to_binary("#{<<~"begin;"}\n#{<<~'end;'}", '[Bug #14660]').eval
687698
begin;

test/ruby/test_method.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ def mk6(a, b = nil, c, **o) nil && o end
3232
def mk7(a, b = nil, *c, d, **o) nil && o end
3333
def mk8(a, b = nil, *c, d, e:, f: nil, **o) nil && o end
3434
def mnk(**nil) end
35+
def mnb(&nil) end
3536
def mf(...) end
3637

3738
class Base
@@ -603,6 +604,7 @@ def obj.respond_to_missing?(id, *)
603604
define_method(:pmk7) {|a, b = nil, *c, d, **o|}
604605
define_method(:pmk8) {|a, b = nil, *c, d, e:, f: nil, **o|}
605606
define_method(:pmnk) {|**nil|}
607+
define_method(:pmnb) {|&nil|}
606608

607609
def test_bound_parameters
608610
assert_equal([], method(:m0).parameters)
@@ -626,6 +628,7 @@ def test_bound_parameters
626628
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], method(:mk7).parameters)
627629
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyreq, :e], [:key, :f], [:keyrest, :o]], method(:mk8).parameters)
628630
assert_equal([[:nokey]], method(:mnk).parameters)
631+
assert_equal([[:noblock]], method(:mnb).parameters)
629632
# pending
630633
assert_equal([[:rest, :*], [:keyrest, :**], [:block, :&]], method(:mf).parameters)
631634
end
@@ -652,6 +655,7 @@ def test_unbound_parameters
652655
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], self.class.instance_method(:mk7).parameters)
653656
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyreq, :e], [:key, :f], [:keyrest, :o]], self.class.instance_method(:mk8).parameters)
654657
assert_equal([[:nokey]], self.class.instance_method(:mnk).parameters)
658+
assert_equal([[:noblock]], self.class.instance_method(:mnb).parameters)
655659
# pending
656660
assert_equal([[:rest, :*], [:keyrest, :**], [:block, :&]], self.class.instance_method(:mf).parameters)
657661
end
@@ -677,6 +681,7 @@ def test_bmethod_bound_parameters
677681
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], method(:pmk7).parameters)
678682
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyreq, :e], [:key, :f], [:keyrest, :o]], method(:pmk8).parameters)
679683
assert_equal([[:nokey]], method(:pmnk).parameters)
684+
assert_equal([[:noblock]], method(:pmnb).parameters)
680685
end
681686

682687
def test_bmethod_unbound_parameters
@@ -701,6 +706,7 @@ def test_bmethod_unbound_parameters
701706
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], self.class.instance_method(:pmk7).parameters)
702707
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyreq, :e], [:key, :f], [:keyrest, :o]], self.class.instance_method(:pmk8).parameters)
703708
assert_equal([[:nokey]], self.class.instance_method(:pmnk).parameters)
709+
assert_equal([[:noblock]], self.class.instance_method(:pmnb).parameters)
704710
end
705711

706712
def test_hidden_parameters

0 commit comments

Comments
 (0)