Previously, only certain values of the 3rd argument triggered a
deprecation warning.
First step for fix for bug #18797. Support for the 3rd argument
will be removed after the release of Ruby 3.2.
Fix minor fallout discovered by the tests.
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
Implements [Feature #19000]
This commit adds copy with changes functionality for `Data` objects
using a new method `Data#with`.
Since Data objects are immutable, the only way to change them is by
creating a copy. This PR adds a `with` method for `Data` class instances
that optionally takes keyword arguments.
If the `with` method is called with no arguments, the behaviour is the
same as the `Kernel#dup` method, i.e. a new shallow copy is created
with no field values changed.
However, if keyword arguments are supplied to the `with` method, then
the copy is created with the specified field values changed. For
example:
```ruby
Point = Data.define(:x, :y)
point = Point.new(x: 1, y: 2)
point.with(x: 3) # => #<data Point x: 3, y: 2>
```
Passing positional arguments to `with` or passing keyword arguments to
it that do not correspond to any of the members of the Data class will
raise an `ArgumentError`.
Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
Make printing shapes better, use a struct instead of specific methods
for each field on a shape.
Co-Authored-By: Aaron Patterson <tenderlove@ruby-lang.org>
All the method call types need to handle argument shifting in case they're
called by `.send`, and we weren't handling that in `OPTIMIZED_METHOD_TYPE_CALL`.
Lack of shifting caused the stack size assertion in gen_leave() to fail.
Discovered by Rails CI: https://buildkite.com/rails/rails/builds/91705#018516c4-f8f8-469e-bc2d-ddeb25ca8317/1920-2067
Diagnosed with help from `@eileencodes` and `@k0kubun`.
When moving Objects between size pools we have to assign a new shape.
This happened during updating references - we tried to create a new shape
tree that mirrored the existing tree, but based on the root shape of the
new size pool.
This causes allocations to happen if the new tree doesn't already exist,
potentially triggering a GC, during GC.
This commit changes object movement to look for a pre-existing new tree
during object movement, and if that tree does not exist, we don't move
the object to the new pool.
This allows us to remove the shape allocation from update references.
Co-Authored-By: Peter Zhu <peter@peterzhu.ca>
When an object becomes "too complex" (in other words it has too many
variations in the shape tree), we transition it to use a "too complex"
shape and use a hash for storing instance variables.
Without this patch, there were rare cases where shape tree growth could
"explode" and cause performance degradation on what would otherwise have
been cached fast paths.
This patch puts a limit on shape tree growth, and gracefully degrades in
the rare case where there could be a factorial growth in the shape tree.
For example:
```ruby
class NG; end
HUGE_NUMBER.times do
NG.new.instance_variable_set(:"@unique_ivar_#{_1}", 1)
end
```
We consider objects to be "too complex" when the object's class has more
than SHAPE_MAX_VARIATIONS (currently 8) leaf nodes in the shape tree and
the object introduces a new variation (a new leaf node) associated with
that class.
For example, new variations on instances of the following class would be
considered "too complex" because those instances create more than 8
leaves in the shape tree:
```ruby
class Foo; end
9.times { Foo.new.instance_variable_set(":@uniq_#{_1}", 1) }
```
However, the following class is *not* too complex because it only has
one leaf in the shape tree:
```ruby
class Foo
def initialize
@a = @b = @c = @d = @e = @f = @g = @h = @i = nil
end
end
9.times { Foo.new }
``
This case is rare, so we don't expect this change to impact performance
of most applications, but it needs to be handled.
Co-Authored-By: Aaron Patterson <tenderlove@ruby-lang.org>
When moving Objects between size pools we have to assign a new shape.
This happened during updating references - we tried to create a new shape
tree that mirrored the existing tree, but based on the root shape of the
new size pool.
This causes allocations to happen if the new tree doesn't already exist,
potentially triggering a GC, during GC.
This commit changes object movement to look for a pre-existing new tree
during object movement, and if that tree does not exist, we don't move
the object to the new pool.
This allows us to remove the shape allocation from update references.
Co-Authored-By: Peter Zhu <peter@peterzhu.ca>
termination_checker.rb
(https://github.com/ruby/reline/pull/482)
* Fix a misparameter of RubyLex#set_input in termination_checker.rb
The keyword parameter `:context` of RubyLex#set_input became mandatory due to this commit:
https://github.com/ruby/irb/pull/427/files#diff-612b926e42ed78aed1a889ac1944f7d22229b3a489cc08f837a7f75eca3d3399R51
Without my patch, tests that specify "--auto-indent" option in test_yamatanooroti fall into an infinite loop.
This would need more explanation:
- The infinite loop happens in Yamatanooroti::VTermTestCaseModule#sync
see: https://github.com/aycabta/yamatanooroti/blob/v0.0.9/lib/yamatanooroti/vterm.rb#L60-L63
- `@pty_output.read_nonblock(1024)` actually returned an exception
- However, this method doesn't anticipate such a situation
- As a result, `startup_message` couldn't be resolved for good and the
infinite loop happens
- I think we would eventually have to fix yamatanooroti, though the
inconsistency of the kwarg of "set_input" has to be fixed anyway
The actual exception message that is raised but ignored silently in Yamatanooroti::VTermTestCaseModule#sync:
```
/home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/irb-d30c0c994351/lib/irb/ruby-lex.rb:51:in `set_input': missing keyword: :context (ArgumentError)
from /home/hasumi/work/ruby/reline/test/reline/yamatanooroti/termination_checker.rb:23:in `initialize'
from /home/hasumi/work/ruby/reline/test/reline/yamatanooroti/multiline_repl:43:in `new'
from /home/hasumi/work/ruby/reline/test/reline/yamatanooroti/multiline_repl:43:in `block in <main>'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/3.1.0/optparse.rb:1576:in `block in parse_in_order'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/3.1.0/optparse.rb:1559:in `catch'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/3.1.0/optparse.rb:1559:in `parse_in_order'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/3.1.0/optparse.rb:1553:in `order!'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/3.1.0/optparse.rb:1659:in `permute!'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/3.1.0/optparse.rb:1684:in `parse!'
from /home/hasumi/work/ruby/reline/test/reline/yamatanooroti/multiline_repl:174:in `<main>'
```
Backtrace of an inifinite loop:
```
/home/hasumi/work/ruby/yamatanooroti/lib/yamatanooroti/vterm.rb:59:in `sleep': Interrupt
from /home/hasumi/work/ruby/yamatanooroti/lib/yamatanooroti/vterm.rb:59:in `block in sync'
from /home/hasumi/work/ruby/yamatanooroti/lib/yamatanooroti/vterm.rb:58:in `loop'
from /home/hasumi/work/ruby/yamatanooroti/lib/yamatanooroti/vterm.rb:58:in `sync'
from /home/hasumi/work/ruby/yamatanooroti/lib/yamatanooroti/vterm.rb:28:in `start_terminal'
from /home/hasumi/work/ruby/reline/test/reline/yamatanooroti/test_rendering.rb:653:in `test_suppress_auto_indent_just_after_pasted'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/testcase.rb:871:in `run_test'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/testcase.rb:566:in `block (2 levels) in run'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/fixture.rb:276:in `block in create_fixtures_runner'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/fixture.rb:276:in `block in create_fixtures_runner'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/fixture.rb:257:in `run_fixture'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/fixture.rb:292:in `run_setup'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/testcase.rb:564:in `block in run'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/testcase.rb:563:in `catch'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/testcase.rb:563:in `run'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/testsuite.rb:124:in `run_test'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/testsuite.rb:53:in `run'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/testsuite.rb:124:in `run_test'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/testsuite.rb:53:in `run'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/testsuite.rb:124:in `run_test'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/testsuite.rb:53:in `run'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/testsuite.rb:124:in `run_test'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/testsuite.rb:53:in `run'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/ui/testrunnermediator.rb:67:in `run_suite'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/ui/testrunnermediator.rb:45:in `block (2 levels) in run'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/ui/testrunnermediator.rb:102:in `with_listener'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/ui/testrunnermediator.rb:41:in `block in run'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/ui/testrunnermediator.rb:39:in `catch'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/ui/testrunnermediator.rb:39:in `run'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/ui/testrunner.rb:40:in `start_mediator'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/ui/testrunner.rb:25:in `start'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/ui/testrunnerutilities.rb:24:in `run'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/autorunner.rb:458:in `block in run'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/autorunner.rb:514:in `change_work_directory'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/autorunner.rb:457:in `run'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit/autorunner.rb:66:in `run'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/test-unit-3.5.5/lib/test/unit.rb:518:in `block (2 levels) in <top (required)>'
```
* Fix mock object of Context
The previous commit solved one problem, but it found the next problem.
Following error message got from the command `RELINE_STDERR_TTY=error.log rake test_yamatanooroti`:
```
Reline is used by 24373
/home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/irb-d30c0c994351/lib/irb/ruby-lex.rb:151:in `ripper_lex_without_warning': private method `local_variables' called for #<struct auto_indent_mode=true, workspace=nil> (NoMethodError)
lvars_code = generate_local_variables_assign_code(context&.local_variables || [])
^^^^^^^^^^^^^^^^^
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/bundler/gems/irb-d30c0c994351/lib/irb/ruby-lex.rb:213:in `block in set_auto_indent'
from /home/hasumi/work/ruby/reline/lib/reline/line_editor.rb:1721:in `process_auto_indent'
from /home/hasumi/work/ruby/reline/lib/reline/line_editor.rb:1663:in `input_key'
from /home/hasumi/work/ruby/reline/lib/reline.rb:346:in `block (3 levels) in inner_readline'
from /home/hasumi/work/ruby/reline/lib/reline.rb:345:in `each'
from /home/hasumi/work/ruby/reline/lib/reline.rb:345:in `block (2 levels) in inner_readline'
from /home/hasumi/work/ruby/reline/lib/reline.rb:420:in `block in read_io'
from /home/hasumi/work/ruby/reline/lib/reline.rb:390:in `loop'
from /home/hasumi/work/ruby/reline/lib/reline.rb:390:in `read_io'
from /home/hasumi/work/ruby/reline/lib/reline.rb:343:in `block in inner_readline'
from /home/hasumi/work/ruby/reline/lib/reline.rb:341:in `loop'
from /home/hasumi/work/ruby/reline/lib/reline.rb:341:in `inner_readline'
from /home/hasumi/work/ruby/reline/lib/reline.rb:271:in `readmultiline'
from /home/hasumi/.rbenv/versions/3.1.2/lib/ruby/3.1.0/forwardable.rb:238:in `readmultiline'
from /home/hasumi/work/ruby/reline/test/reline/yamatanooroti/multiline_repl:185:in `<main>'
```
In irb/ruby-lex.rb, `context` is originally supposed to be an instance of IRB::Context with a public method `#local_variables`.
However, the `context` in reline/test/reline/yamatanooroti/termination_checker.rb is a Struct that is a mock object with no `#local_variables` method.
Thus, `rake test_yamatanooroti` no longer causes an infinite loop and an unexpected error with these two commits (at least in WITH_VTERM environment)
* Name the Struct "MockIRBContext" to specify what it is for
(https://github.com/ruby/irb/pull/478)
Given that `show_doc` already supports syntax like `String#gsub`, it
should be able to take it in non-string form too, like `edit` and
`show_source` do. This ensures users can have a consistent syntax on
argument between different commands.