Project

General

Profile

Actions

Bug #19330

closed

ruby 3.2.0 parameter lack-of-autosplat breaks call using (*args, &block)

Added by rockorequin (rocko requin) over 2 years ago. Updated over 2 years ago.

Status:
Closed
Assignee:
-
Target version:
-
[ruby-core:111775]

Description

The following code in Rails 6.1.7 activerecord relation.rb no longer works with ruby 3.2.0, because the call "instance_exec(*args, &block)" raises an ArgumentException:

def _exec_scope(*args, &block) # :nodoc:
  @delegate_to_klass = true
  _scoping(nil) { instance_exec(*args, &block) || self }
ensure
  @delegate_to_klass = false
end

I think it may be due to the bugfix https://bugs.ruby-lang.org/issues/18633 ("proc { |a, **kw| a } autosplats and treats empty kwargs specially").

There is more info at https://github.com/rails/rails/issues/46934, including this code to reproduce the issue:

gem 'rails', '=6.1.7'
require 'active_record'
class Test < ActiveRecord::Base
   scope :test, ->(arg: nil) {}
end

Test.test(arg: 1)

Another user in that issue report has indicated that the syntax "save(**)" in suppressor.rb raises the same exception in ruby 3.2.0:

def save(**) # :nodoc:
  SuppressorRegistry.suppressed[self.class.name] ? true : super
end

Is this intentional, ie is the syntax "instance_exec(*args, &block)" etc no longer valid in ruby 3.2.0?

If so, could a note indicating this incompatibility perhaps be added to the release notes for 3.2.0?

Actions #1

Updated by rockorequin (rocko requin) over 2 years ago

  • Subject changed from ruby 3.2.0 parameter autosplat breaks call using (*args, &block) to ruby 3.2.0 parameter lack-of-autosplat breaks call using (*args, &block)

Updated by jeremyevans0 (Jeremy Evans) over 2 years ago

  • Status changed from Open to Closed

rockorequin (rocko requin) wrote:

The following code in Rails 6.1.7 activerecord relation.rb no longer works with ruby 3.2.0, because the call "instance_exec(*args, &block)" raises an ArgumentException:

def _exec_scope(*args, &block) # :nodoc:
  @delegate_to_klass = true
  _scoping(nil) { instance_exec(*args, &block) || self }
ensure
  @delegate_to_klass = false
end

I think it may be due to the bugfix https://bugs.ruby-lang.org/issues/18633 ("proc { |a, **kw| a } autosplats and treats empty kwargs specially").

There is more info at https://github.com/rails/rails/issues/46934, including this code to reproduce the issue:

gem 'rails', '=6.1.7'
require 'active_record'
class Test < ActiveRecord::Base
   scope :test, ->(arg: nil) {}
end

Test.test(arg: 1)

This code is expected to break with keyword argument separation. The code should either use ruby2_keywords :_exec_scope (if you need it to work in Ruby 2) or def _exec_scope(*args, **kw, &block) and instance_exec(*args, **kw, &block). The fact that it still worked in Ruby 3.0 and Ruby 3.1 was a bug in the implementation (#18625 and #16466, not #18633), which was fixed in Ruby 3.2 and mentioned in the release notes.

Another user in that issue report has indicated that the syntax "save(**)" in suppressor.rb raises the same exception in ruby 3.2.0:

def save(**) # :nodoc:
  SuppressorRegistry.suppressed[self.class.name] ? true : super
end

Probably the same issue. Either ruby2_keywords or explicit keyword delegation is needed for methods delegating arguments to save.

Is this intentional, ie is the syntax "instance_exec(*args, &block)" etc no longer valid in ruby 3.2.0?

The syntax is fine. If the block only accepts keywords, it will result in exceptions if args is not empty (that should be true in Ruby 3.0 and Ruby 3.1 as well).

If so, could a note indicating this incompatibility perhaps be added to the release notes for 3.2.0?

The release notes already discuss the bug fix. If you think additional documentation is needed, could you please submit a pull request?

Actions

Also available in: Atom PDF

Like0
Like0Like0