From 3fc7dd185862742ea1c35ad2ffb77d961d1e03ad Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 11 May 2026 14:06:28 +0900 Subject: [PATCH] mruby-proc-ext: Proc#curry should check max arity for lambdas `lambda {|a, b=nil|}.curry(3)` used to silently return a curried Proc; CRuby raises `ArgumentError` because the lambda accepts at most 2 args. Use `self.parameters` to compute the upper bound (count `:req`/`:opt` entries, unbounded if `:rest`/`:keyrest` is present) and add the corresponding range check alongside the existing minimum check. close #2855 Co-authored-by: Claude --- mrbgems/mruby-proc-ext/mrblib/proc.rb | 19 ++++++++++++++++--- mrbgems/mruby-proc-ext/test/proc.rb | 7 +++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-proc-ext/mrblib/proc.rb b/mrbgems/mruby-proc-ext/mrblib/proc.rb index 4e7dfac57..320549ce7 100644 --- a/mrbgems/mruby-proc-ext/mrblib/proc.rb +++ b/mrbgems/mruby-proc-ext/mrblib/proc.rb @@ -75,9 +75,22 @@ class Proc if lambda? type = :lambda self_arity = self.arity - if (self_arity >= 0 && arity != self_arity) || - (self_arity < 0 && abs[self_arity] > arity) - raise ArgumentError, "wrong number of arguments (given #{arity}, expected #{abs[self_arity]})" + min_req = abs[self_arity] + if self_arity < 0 + max_arity = 0 + has_rest = false + self.parameters.each do |p| + case p[0] + when :rest, :keyrest then has_rest = true + when :req, :opt then max_arity += 1 + end + end + if arity < min_req || (!has_rest && arity > max_arity) + expected = (!has_rest && max_arity != min_req) ? "#{min_req}..#{max_arity}" : min_req.to_s + raise ArgumentError, "wrong number of arguments (given #{arity}, expected #{expected})" + end + elsif arity != self_arity + raise ArgumentError, "wrong number of arguments (given #{arity}, expected #{self_arity})" end end diff --git a/mrbgems/mruby-proc-ext/test/proc.rb b/mrbgems/mruby-proc-ext/test/proc.rb index 7a105323a..fcbeb4962 100644 --- a/mrbgems/mruby-proc-ext/test/proc.rb +++ b/mrbgems/mruby-proc-ext/test/proc.rb @@ -64,6 +64,13 @@ assert('Proc#curry') do assert_false(proc{}.curry.lambda?) assert_true(lambda{}.curry.lambda?) + + # #2855: lambda with optional param: curry must validate against max arity + l = lambda {|a, b=nil|} + assert_raise(ArgumentError) { l.curry(3) } # over max + assert_kind_of Proc, l.curry(2) # within range + assert_kind_of Proc, l.curry(1) # at min + assert_kind_of Proc, lambda {|a, *b|}.curry(99) # rest -> unbounded end assert('Proc#parameters') do