Project

General

Profile

Actions

Bug #22522

open

`Ractor.shareable_proc` silently drops the block of the method for `block_given?`, `defined?(yield)` and `super`

Bug #22522: `Ractor.shareable_proc` silently drops the block of the method for `block_given?`, `defined?(yield)` and `super`

Added by Eregon (Benoit Daloze) 1 day ago.

Status:
Open
Assignee:
-
Target version:
ruby -v:
ruby 4.1.0dev (2026-11-09T15:47:20Z master 7e5d882817) +PRISM [arm64-darwin25]
[ruby-core:127382]

Description

yield in a block calls the block of the enclosing method. A shareable Proc cannot keep that block: the block (or the Proc it becomes) has its own self and environment, which are generally not shareable, and the copied environment of the shareable Proc has no block. That is why Ractor.shareable_proc already rejects yield:

def m = Ractor.shareable_proc { yield }
m {} # can not make a Proc shareable because it uses 'yield'. (Ractor::IsolationError)

But other constructs inside a block use the block of the enclosing method too, and are not rejected. The shareable Proc silently behaves as if the method had no block:

def m1 = Ractor.shareable_proc { block_given? }
p m1 {}.call # Ruby block semantics: true

def m2 = Ractor.shareable_proc { defined?(yield) }
p m2 {}.call # "yield"

class Parent
  def foo = block_given?
end
class Child < Parent
  # super without an explicit block passes the block of the method
  def foo = Ractor.shareable_proc(self: self) { super() }
end
obj = Ractor.make_shareable(Child.new)
p obj.foo {}.call # true
$ ruby -v block.rb
ruby 4.1.0dev (2026-11-09T15:47:20Z master 7e5d882817) +PRISM [arm64-darwin25]
false
nil
false

Same result on 4.0.7. iterator? (the deprecated alias of block_given?) and zsuper (super) behave the same way. Since #22444 this also applies to Ractor.new blocks.

These should raise Ractor::IsolationError like yield does, for the same reason. Following [Feature #21557], it is better to raise than to silently change the semantics of the block.

Fix

PR: https://github.com/ruby/ruby/pull/19803

The compiler now records block_given?/iterator? calls without a receiver, defined?(yield), and super without an explicit block argument or literal block, the same way it records yield. This is done only when the enclosing scope is a method, since otherwise there is no block of the method and nothing to lose, so Ractor.new { block_given? } keeps working. The error message names the construct:

can not make a Proc shareable because it uses 'block_given?'. (Ractor::IsolationError)

Like the existing check for yield, this check is static, so it raises even if the method was called without a block. A possible later relaxation, for yield too, would be to check at runtime instead and reject only when the method has a block which is not shareable. A method's block cannot change during the call, so without a block the shareable Proc behaves exactly like the original.

Code which currently creates such a shareable Proc gets Ractor::IsolationError after this fix, so I don't think this should be backported.


Related issues 1 (0 open — 1 closed)

Related to Ruby - Feature #21557: Ractor.shareable_proc to make sharable Proc objects, safely and flexiblyClosedko1 (Koichi Sasada)Actions
Actions

Also available in: PDF Atom