Issue #20457 has been reported by tenderlovemaking (Aaron Patterson).
----------------------------------------
Bug #20457: Final `return` is eliminated from the AST
https://bugs.ruby-lang.org/issues/20457
* Author: tenderlovemaking (Aaron Patterson)
* Status: Open
* Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN
----------------------------------------
Given the following code:
```ruby
def foo
a = 1
return a
end
```
If you parse this with RubyVM::AbstractSyntaxTree, the AST will be missing the `return` node. Of course the `return` node isn't necessary for compilation, but would be required for building an LSP for example.
Here's a full program to demonstrate:
```ruby
ast = RubyVM::AbstractSyntaxTree.parse DATA.read
pp ast
# Output is like this:
#
# (SCOPE@1:0-4:3
# tbl: []
# args: nil
# body:
# (DEFN@1:0-4:3
# mid: :foo
# body:
# (SCOPE@1:0-4:3
# tbl: [:a]
# args: (ARGS@1:7-1:7 pre_num: 0 pre_init: nil opt: nil first_post: nil post_num: 0 post_init: nil rest: nil kw: nil kwrest: nil block: nil)
# body: (BLOCK@2:2-3:10 (LASGN@2:2-2:7 :a (INTEGER@2:6-2:7 1)) (LVAR@3:9-3:10 :a)))))
__END__
def foo
a = 1
return a
end
```
Btw, I'm happy to write failing tests for this type of stuff I'm just not sure where to put it! :)
--
https://bugs.ruby-lang.org/
Issue #20454 has been reported by zonuexe (Kenta USAMI).
----------------------------------------
Bug #20454: IRB echoes excessive input in dumb terminal
https://bugs.ruby-lang.org/issues/20454
* Author: zonuexe (Kenta USAMI)
* Status: Open
* ruby -v: ruby 3.3.1 (2024-04-23 revision c56cd86388) [arm64-darwin23]
* Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN
----------------------------------------
When IRB is started on a terminal with the environment variable TERM=dumb, excessive output is generated as shown below.
A simple terminal such as Emacs shell-mode or comint-mode is assumed, but it should be possible to reproduce the following with a rich terminal such as iTerm.
Type 1[RET], 12[RET], 123[RET] on your keyboard in this order.
% TERM=dumb irb
irb(main):001> 1
irb(main):001> 1=> 1
irb(main):002> 12
irb(main):002> 1irb(main):002> 12=> 12
irb(main):003> 123
irb(main):003> 1irb(main):003> 12irb(main):003> 123=> 123
As arton-san says, you can avoid the problem by not using ReadlineInputMethod.
https://twitter.com/arton/status/1783008921000804630
--
https://bugs.ruby-lang.org/
Issue #20461 has been reported by yamam (Masanari Yamamoto).
----------------------------------------
Bug #20461: Unreadable pipe included in the readable IO of IO.select
https://bugs.ruby-lang.org/issues/20461
* Author: yamam (Masanari Yamamoto)
* Status: Open
* ruby -v: ruby 3.4.0dev (2024-04-27T12:55:28Z master c844968b72) [x86_64-linux]
* Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN
----------------------------------------
When executing the following script, pipe_r is not supposed to be readable because no writing is done to pipe_w, but pipe_r is included in the return value rs of IO.select. Since it is not possible to read from pipe_r, the IO::EAGAINWaitReadable exception is raised.
```ruby
pipe_r, pipe_w = IO.pipe
1000.times do |i|
File.popen(['seq', '1', '1000']) do |popen_r|
j = 0
while true
rs, ws, = IO.select([popen_r, pipe_r])
if rs.include?(popen_r)
unless popen_r.gets
break
end
end
if rs.include?(pipe_r)
puts "IO.select BUG pipe_r is not readable! i = #{i} j = #{j}"
p pipe_r.read_nonblock(1)
end
j += 1
end
end
end
```
```
$ ruby select.rb
IO.select BUG pipe_r is not readable! i = 0 j = 20
<internal:io>:63:in `read_nonblock': Resource temporarily unavailable - read would block (IO::EAGAINWaitReadable)
from select.rb:14:in `block (2 levels) in <main>'
from select.rb:3:in `popen'
from select.rb:3:in `block in <main>'
from select.rb:2:in `times'
from select.rb:2:in `<main>'
[1] 73732 exit 1 ruby select.rb
```
--
https://bugs.ruby-lang.org/
Issue #15438 has been updated by jhawthorn (John Hawthorn).
Status changed from Open to Closed
I think this is something we should improve more (I would like even faster switching times), but it does seem possible as of Ruby 3.3 to have threads switch faster than 100ms.
```
def test_switching(priority = 0)
done = false
started = false
busy = Thread.new do
Thread.current.priority = priority
until done
started = true
end
end
Thread.pass until started
times = []
while times.length < 10
before = Process.clock_gettime(Process::CLOCK_MONOTONIC)
Thread.pass
after = Process.clock_gettime(Process::CLOCK_MONOTONIC)
times << (after - before)
end
done = true
busy.join
times
end
puts RUBY_VERSION
(-3).upto(3) do |priority|
print "Priority: #{priority}"
times = test_switching(priority)
times = times.sort[1..-2] # drop fastest and slowest
average = (times.sum / times.length)
puts " average: #{average}"
end
```
```
$ ruby test_measure_switching_times.rb
3.2.2
Priority: -3 average: 0.10010529025021242
Priority: -2 average: 0.10010091188087245
Priority: -1 average: 0.10010025675364886
Priority: 0 average: 0.10010364262052462
Priority: 1 average: 0.20017941037440323
Priority: 2 average: 0.4003785701279412
Priority: 3 average: 0.8007820281236491
```
```
$ ruby test_measure_switching_times.rb
3.3.1
Priority: -3 average: 0.02040818374371156
Priority: -2 average: 0.03023905074587674
Priority: -1 average: 0.05040335562443943
Priority: 0 average: 0.10088755612378009
Priority: 1 average: 0.20198591962616774
Priority: 2 average: 0.4033456226279668
Priority: 3 average: 0.8073137137507729
```
----------------------------------------
Feature #15438: Threads can't switch faster than TIME_QUANTUM_(NSEC|USEC|MSEC)
https://bugs.ruby-lang.org/issues/15438#change-108145
* Author: sylvain.joyeux (Sylvain Joyeux)
* Status: Closed
----------------------------------------
Thread#priority can be set to negative values, which when looking at the code is meant to reduce the time allocated to the thread. However, as far as I could understand in the codebase, the quantum of time is definitely hard-coded to 100ms (TIME_QUANTUM_...). This means that the "lower allocated time" would only work for threads that would often yield one way or the other (sleep, blocking calls, ...)
My projects would definitely benefit from a faster switching period. I was wondering how best to implement this ability ?
I thought of the following:
1. globally using an environment variable
2. globally using an API
3. trying to adapt dynamically, using the highest needed period
4. lowering the period when a priority lower than 0 is set, leaving it at the lower period.
Obviously (3) would seem to be the best, but I'm not sure I would be able to get it right in a decent amount of time. (4) seem to be a good trade-off between simplicity and performance (nothing changes if you never use priorities lower than 0, and if you were you basically get what you wanted).
What do you think ?
---Files--------------------------------
0001-dynamically-modify-the-timer-thread-period-to-accoun.patch (3.12 KB)
0001-2.6-fix-handling-of-negative-priorities.patch (8.43 KB)
--
https://bugs.ruby-lang.org/
Issue #20451 has been reported by Bo98 (Bo Anderson).
----------------------------------------
Bug #20451: Bad Ruby 3.1.5 backport causes fiddle to fail to build
https://bugs.ruby-lang.org/issues/20451
* Author: Bo98 (Bo Anderson)
* Status: Open
* ruby -v: 3.1.5p252
* Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN
----------------------------------------
Ruby 3.1.5 shipped with the following backport: https://github.com/ruby/ruby/commit/84f2aabd272a54e79979795d2d405090704a1d07
However this backport directly breaks the build:
```
closure.c:279:60: error: use of undeclared identifier 'data'
result = ffi_prep_closure(pcl, cif, callback, (void *)(data->self));
^
```
The original commit (https://github.com/ruby/fiddle/commit/2530496602) was updating the second branch to match the change in the first branch a couple lines up. However that change in the other branch does not exist in Ruby 3.1. The commit in question requires a previous commit of https://github.com/ruby/fiddle/commit/81a8a56239973ab7559229830a449d201955b….
The backport should either be reverted or an other commit should also be backported. Note that these commits were in a series of many commits made to fix an upstream issue https://github.com/ruby/fiddle/issues/102 so I cannot vouch whether or not the two commits are sufficient to fix the originally reported issue.
--
https://bugs.ruby-lang.org/
Issue #20094 has been reported by sisyphus_cg (Sisyphus CG).
----------------------------------------
Bug #20094: Inline while loop behavior changed unexpectedly in 3.3.0
https://bugs.ruby-lang.org/issues/20094
* Author: sisyphus_cg (Sisyphus CG)
* Status: Open
* Priority: Normal
* ruby -v: 3.3.0
* Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN
----------------------------------------
The behavior of the inline while loop has changed in 3.3.0. This unexpectedly broke my code and I couldn't find anything in the changelog about it so reporting it as a bug.
In ruby <= 3.2:
``` ruby
(p 1) while false # nothing
(p 1; p 2) while false # nothing
```
In ruby 3.3:
``` ruby
(p 1) while false # 1
(p 1; p 2) while false # 1 2
```
Essentially, if the left hand side looks like a statement, now it is treated as a do-while loop. In ruby 3.2 and less this only happened with explicit use of `begin` and `end`.
--
https://bugs.ruby-lang.org/
Issue #18583 has been updated by ntl (Nathan Ladd).
Could the match operator, `=~`, could be used as a general complement to `===`?
Example (following Victor's original sketch):
``` ruby
class Matcher
def initialize(regexp)
@regexp = regexp
end
def ===(obj)
@regexp.match?(obj)
end
def =~(obj)
match_data = @regexp.match(obj)
match_data
end
end
case "some string"
in ^(Matcher.new(/(?<some_named_capture>some) string/) => match_data
some_named_capture = match_data[:some_named_capture]
puts "Match: #{some_named_capture}"
end
```
This would add `=~` to the pattern matching protocol that's currently comprised of `===`, `deconstruct` and `deconstruct_keys`. It would make `===` significantly more useful, and regular expressions provide a great example of why: when matching a string to a regular expression pattern, the string is already in lexical scope, but the match data is novel and only comes into existence upon a successful match:
```
subject = "some string"
case subject
in ^(Matcher.new(/(?<some_named_capture>some) string/) => match_data
# Capturing the match data variable instead of the original string doesn't make the original string inaccessible:
puts "Match subject: #{subject.inspect}"
end
```
I also suspect this could be embedded into the pattern syntax itself, and could allow for some interesting possibilities. One example that leaps to mind is reifying primitive data parsed from JSON into a data structure:
``` ruby
SomeStruct = Struct.new(:some_attr, :some_other_attr) do
def self.===(data)
data.is_a?(Hash) && data.key?(:some_attr) && data.key?(:some_other_attr)
end
def self.=~(data)
new(**data)
end
end
# Parse JSON into raw (primitive) data
some_data = JSON.parse(<<JSON)
{
"some_attr": "some value",
"some_other_attr": "some other value"
}
JSON
# Reify data structure from raw data
case some_data
in SomeStruct => some_struct
puts some_struct.inspect
end
```
----------------------------------------
Feature #18583: Pattern-matching: API for custom unpacking strategies?
https://bugs.ruby-lang.org/issues/18583#change-108142
* Author: zverok (Victor Shepelev)
* Status: Open
----------------------------------------
I started to think about it when discussing https://github.com/ruby/strscan/pull/30.
The thing is, usage of StringScanner for many complicated parsers invokes some kind of branching.
In pseudocode, the "ideal API" would allow to write something like this:
```ruby
case <what next matches>
in /regexp1/ => value_that_matched
# use value_that_matched
in /regexp2/ => value_that_matched
# use value_that_matched
# ...
```
This seems "intuitively" that there *should* be some way of implementing it, but we fall short. We can do some StringScanner-specific matcher object which defines its own `#===` and use it with pinning:
```ruby
case scanner
in ^(Matcher.new(/regexp1/)) => value_that_matched
# ...
```
But there is no API to tell how the match result will be unpacked, just the whole `StringScanner` will be put into `value_that_matched`.
So, I thought that maybe it would be possible to define some kind of API for pattern-like objects, the method with signature like `try_match_pattern(value)`, which by default is implemented like `return value if self === value`, but can be redefined to return something different, like part of the object, or object transformed somehow.
This will open some interesting (if maybe uncanny) possibilities: not just slicing out the necessary part, but something like
```ruby
value => ^(type_caster(Integer)) => int_value
```
So... Just a discussion topic!
--
https://bugs.ruby-lang.org/
Issue #18915 has been updated by Quintasan (Michał Zając).
nithinbekal (Nithin Bekal) wrote in #note-18:
> > What name candidate do you have?
>
> What do you think about the name `SubclassResponsibilityError`? As @citizen428 explains [here](https://ruby.social/@citizen428@chaos.social/112239323523258221):
>
> > Smalltalk had the idiom of implementing abstract methods with the body `self subclassResponsibility` which raises an error.
>
> The name gives a pretty clear indication of what is wrong, and it seems fitting considering Ruby's Smalltalk heritage.
I like this as well as `AbstractMethodError`
----------------------------------------
Feature #18915: New error class: NotImplementedYetError or scope change for NotImplementedError
https://bugs.ruby-lang.org/issues/18915#change-108140
* Author: Quintasan (Michał Zając)
* Status: Open
----------------------------------------
# Abstract
Introduce `NotImplementedYetError` exception that should be used in case when the codepath has not been implemented by the developer for some reason (maybe they're designing an abstract class or are designing some sort of interface to reuse later on) OR extend the meaning of `NotImplementedError` to cover those usecases so we don't have to introduce another exception
# Background
`NotImplementedError` is supposed to be raised `if the underlying operating system or Ruby runtime does not support them` (https://ruby-doc.org/core-3.1.2/NotImplementedError.html)
However it appears that many people are misusing this exception by raising this in a superclass from which they later inherit from. I do realize that Ruby promotes duck-typing (the default RuboCop style guide has a cop for this – https://github.com/rubocop/ruby-style-guide#duck-typing). However I have seen this being discussed numerous times:
* https://github.com/rubocop/ruby-style-guide/issues/458
* http://chrisstump.online/2016/03/23/stop-abusing-notimplementederror/
* https://oleg0potapov.medium.com/ruby-notimplementederror-dont-use-it-dff1fd…
* https://gitlab.com/gitlab-org/gitlab/-/issues/354314 (which I'm the author of)
* https://github.com/rmosolgo/graphql-ruby/issues/2067 (here the author actually confused it with Python's `NotImplementedError`)
* https://stackoverflow.com/questions/13668068/how-to-signal-not-implemented-…
# Proposal
Create `NotImplementedYetError` exception
OR
Allow raising `NotImplementedError` in cases other than OS or Ruby runtime incompatibilities
# Evaluation
### Add `NotImplementedYetError`
I think a new exception is a better idea than changing the usage of an existing one just because "everyone is using it". That said it would require people to refactor their code which might prevent wider adoption of the new exception.
### Change scope of `NotImplementedError`
This would require the least amount of changes possible (only a documentation change) and I believe there would be no compatibility problems whatsoever.
---Files--------------------------------
not-implemented-error-docs.patch (1.57 KB)
--
https://bugs.ruby-lang.org/
Issue #20460 has been reported by kddnewton (Kevin Newton).
----------------------------------------
Bug #20460: Ripper `eval` option
https://bugs.ruby-lang.org/issues/20460
* Author: kddnewton (Kevin Newton)
* Status: Open
* Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN
----------------------------------------
There are a couple of differences when producing syntax trees from the parser/ripper when compiling for eval. Namely, for the eval case it does not raise a syntax error for invalid jumps. It would be nice to be able to pass an `eval: true/false` option to `Ripper.sexp`/`Ripper.sexp_raw`/`Ripper.new` to tell it to parse as if it were an `eval`.
Because of some new syntax errors, this had led to bugs like https://bugs.ruby-lang.org/issues/20186. If we provide such an option, it could also be useful for debugging purposes.
--
https://bugs.ruby-lang.org/
Issue #20450 has been reported by philippe.bs.noel(a)tutanota.com (Philippe Noel).
----------------------------------------
Bug #20450: Ruby 3.1.1 broken with bootsnap
https://bugs.ruby-lang.org/issues/20450
* Author: philippe.bs.noel(a)tutanota.com (Philippe Noel)
* Status: Open
* ruby -v: ruby 3.3.1 (2024-04-23 revision c56cd86388) [x86_64-linux]
* Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN
----------------------------------------
The issue looks like https://bugs.ruby-lang.org/issues/20060
With the new release of ruby 3.1.1, bootsnap does not work anymore.
```
bin/rails aborted!
ArgumentError: comparison of String with nil failed (ArgumentError)
msg = " #{RUBY_VERSION < SINCE[gem] ? "will no longer be" : "is not"} part of the default gems since Ruby #{SINCE[gem]}."
^^^^^^^^^^
/usr/local/bundle/gems/bootsnap-1.18.3/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
```
It's working with DISABLE_BOOTSNAP=1 with the following message : `warning: parser/current is loading parser/ruby33, which recognizes 3.3.0-compliant syntax, but you are running 3.3.1.`
--
https://bugs.ruby-lang.org/