summaryrefslogtreecommitdiff
path: root/proc.c
diff options
context:
space:
mode:
authorYusuke Endoh <mame@ruby-lang.org>2020-03-16 23:03:22 +0900
committerYusuke Endoh <mame@ruby-lang.org>2020-03-16 23:17:12 +0900
commit47141797bed55eb10932c9a722a5132f50d4f3d8 (patch)
treea2934da7ecc862d7746eaf0f504aea16cc35b653 /proc.c
parent4be2a891cce920d2e2c2ece572c66e5aabe98eaa (diff)
downloadruby-47141797bed55eb10932c9a722a5132f50d4f3d8.tar.gz
hash.c: Do not use the fast path (rb_yield_values) for lambda blocks
As a semantics, Hash#each yields a 2-element array (pairs of keys and values). So, `{ a: 1 }.each(&->(k, v) { })` should raise an exception due to lambda's arity check. However, the optimization that avoids Array allocation by using rb_yield_values for blocks whose arity is more than 1 (introduced at b9d29603375d17c3d1d609d9662f50beaec61fa1 and some commits), seemed to overlook the lambda case, and wrongly allowed the code above to work. This change experimentally attempts to make it strict; now the code above raises an ArgumentError. This is an incompatible change; if the compatibility issue is bigger than our expectation, it may be reverted (until Ruby 3.0 release). [Bug #12706]
Diffstat (limited to 'proc.c')
-rw-r--r--proc.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/proc.c b/proc.c
index 5ee65a0fee..909a25994b 100644
--- a/proc.c
+++ b/proc.c
@@ -1145,6 +1145,41 @@ block_setup(struct rb_block *block, VALUE block_handler)
}
int
+rb_block_pair_yield_optimizable(void)
+{
+ int min, max;
+ const rb_execution_context_t *ec = GET_EC();
+ rb_control_frame_t *cfp = ec->cfp;
+ VALUE block_handler = rb_vm_frame_block_handler(cfp);
+ struct rb_block block;
+
+ if (block_handler == VM_BLOCK_HANDLER_NONE) {
+ rb_raise(rb_eArgError, "no block given");
+ }
+
+ block_setup(&block, block_handler);
+ min = rb_vm_block_min_max_arity(&block, &max);
+
+ switch (vm_block_type(&block)) {
+ case block_handler_type_symbol:
+ return 0;
+
+ case block_handler_type_proc:
+ {
+ VALUE procval = block_handler;
+ rb_proc_t *proc;
+ GetProcPtr(procval, proc);
+ if (proc->is_lambda) return 0;
+ if (min != max) return 0;
+ return min > 1;
+ }
+
+ default:
+ return min > 1;
+ }
+}
+
+int
rb_block_arity(void)
{
int min, max;