[Feature #20205]
The warning now suggests running with --debug-frozen-string-literal:
```
test.rb:3: warning: literal string will be frozen in the future (run with --debug-frozen-string-literal for more information)
```
When using --debug-frozen-string-literal, the location where the string
was created is shown:
```
test.rb:3: warning: literal string will be frozen in the future
test.rb:1: info: the string was created here
```
When resurrecting strings and debug mode is not enabled, the overhead is a simple FL_TEST_RAW.
When mutating chilled strings and deprecation warnings are not enabled,
the overhead is a simple warning category enabled check.
Co-authored-by: Jean Boussier <byroot@ruby-lang.org>
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
Co-authored-by: Jean Boussier <byroot@ruby-lang.org>
If there is a syntax error, there could be an ast_node in the result.
This could get leaked if there is a syntax error so parsing could not
complete (parsed is not set to true).
For example, the following script leaks memory:
10.times do
10_000.times do
eval("def foo(...) super(...) {}; end")
rescue SyntaxError
end
puts `ps -o rss= -p #{$$}`
end
Before:
31328
42768
53856
65120
76208
86768
97856
109120
120208
131296
After:
20944
20944
20944
20944
20944
20944
20944
20944
20944
20944
This caused an issue when `defined?` was in the `if` condition. Its
instructions weren't appended to the instruction sequence even though it was compiled
if a compile-time known logical short-circuit happened before the `defined?`. The catch table
entry (`defined?` compilation produces a catch table entry) was still on the iseq even though the
instructions weren't there. This caused faulty exception handling in the method.
The solution is to no add the catch table entry for `defined?` after a compile-time known logical
short circuit.
This shouldn't touch much code, it's only for cases like the following,
which can occur during debugging:
if false && defined?(Some::CONSTANT)
"more code..."
end
Fixes [Bug #20501]
In cases where break/next/redo are not valid syntax, they should
raise a SyntaxError even if inside a conditional block that is
optimized away.
Fixes [Bug #20597]
Co-authored-by: Kevin Newton <kddnewton@gmail.com>
Previously, this would delete the key in `h` before keyword
splatting `h`. This goes against how ruby handles `f(*a, &a.pop)`
and similar expressions.
Fix this by having the compiler check whether the block pass
expression is safe. If it is not safe, then dup the keyword
splatted hash before evaluating the block pass expression.
For expression: `h=nil; f(**h, &h.delete(:key))`
VM instructions before:
```
0000 putnil ( 1)[Li]
0001 setlocal_WC_0 h@0
0003 putself
0004 getlocal_WC_0 h@0
0006 getlocal_WC_0 h@0
0008 putobject :key
0010 opt_send_without_block <calldata!mid:delete, argc:1, ARGS_SIMPLE>
0012 splatkw
0013 send <calldata!mid:f, argc:1, ARGS_BLOCKARG|FCALL|KW_SPLAT>, nil
0016 leave
```
VM instructions after:
```
0000 putnil ( 1)[Li]
0001 setlocal_WC_0 h@0
0003 putself
0004 putspecialobject 1
0006 newhash 0
0008 getlocal_WC_0 h@0
0010 opt_send_without_block <calldata!mid:core#hash_merge_kwd, argc:2, ARGS_SIMPLE>
0012 getlocal_WC_0 h@0
0014 putobject :key
0016 opt_send_without_block <calldata!mid:delete, argc:1, ARGS_SIMPLE>
0018 send <calldata!mid:f, argc:1, ARGS_BLOCKARG|FCALL|KW_SPLAT|KW_SPLAT_MUT>, nil
0021 leave
```
This is the same as 07d3bf4832, except that
it removes unnecessary hash allocations when using the prism compiler.
Fixes [Bug #20640]
This commit switches the default parser to Prism. There are a
couple of additional changes related to this that are a part of
this as well to make this happen.
* Switch the default parser in parse.h
* Remove the Prism-specific workflow and add a parse.y-specific
workflow to CI so that it continues to be tested
* Update a few test exclusions since Prism has the correct
behavior but parse.y doesn't per
https://bugs.ruby-lang.org/issues/20504.
* Skips a couple of tests on RBS which are failing because they
are using RubyVM::AbstractSyntaxTree.of.
Fixes [Feature #20564]
With the parse.y parser, when a fifo (named pipe) is passed to
Kernel#load and friends, we wait for data to be available first before
reading. Note that with fifos, opening with `O_RDONLY|O_NONBLOCK` and
then reading will look like EOF with read(2) returning 0, but data can
become available later.
The prism compiler needs to match this behavior to pass
`test_loading_fifo_{fd_leak,threading_raise,threading_success}`. I chose
to use IO#read to do this.
An alternative way to match behavior would be to use open_load_file()
from ruby.c like parse.y, but I opted to only allocate an IO to deal
with threading when reading from pipes and character devices. The
memory mapping code seems to work fine for regular files.
This addresses one of the issues in the `test_kw_splat_nil` failure, but
doesn't make the test pass because of other changes that need to be made
to Prism directly.
One issue was when we have the following code Prism was using
`putobject` with an empty hash whereas the parse.y parser used `putnil`.
```ruby
:ok.itself(**nil)
```
Before:
```
0000 putobject :ok ( 1)[Li]
0002 putobject {}
0004 opt_send_without_block <calldata!mid:itself, argc:1, KW_SPLAT>
0006 leave
```
After:
```
== disasm: #<ISeq:<main>@test2.rb:1 (1,0)-(1,17)>
0000 putobject :ok ( 1)[Li]
0002 putnil
0003 opt_send_without_block <calldata!mid:itself, argc:1, KW_SPLAT>
0005 leave
```
Related to ruby/prism#2935.