aboutsummaryrefslogtreecommitdiffstats
path: root/bootstraptest
diff options
context:
space:
mode:
authorAlan Wu <XrXr@users.noreply.github.com>2023-08-15 10:08:48 -0400
committerGitHub <noreply@github.com>2023-08-15 10:08:48 -0400
commit9acc73d7c583649240906b079c270e6ce1d8c50f (patch)
tree2793e27724115c4dd2fe5c694af4180ec115a33a /bootstraptest
parent2f57db6c778f18a6967b8d7bcca33593fa8f013b (diff)
downloadruby-9acc73d7c583649240906b079c270e6ce1d8c50f.tar.gz
YJIT: Optional parameter rework and bugfix (#8220)
* YJIT: Fix splatting empty array with rest param * YJIT: Rework optional parameter handling to fix corner case The old code had a few unintuitive parts. The starting PC of the callee was set in different places; `num_param`, which one would assume to be static for a particular callee seemingly tallied to different amounts depending on the what the caller passed; `opts_filled_with_splat` was greater than zero even when the opts were not filled by items in the splat array. Functionally, the bits that lets the callee know which keyword parameters are unspecified were not passed properly when there are optional parameters and a rest parameter, and then optional parameters are all filled. Make `num_param` non-mut and use parameter information in the callee iseq as-is. Move local variable nil fill and placing of the rest array out of `gen_push_frame()` as they are only ever relevant for iseq calls. Always place the rest array at `lead_num + opt_num` to fix the previously buggy situation. * YJIT: Compile splat calls to iseqs with rest params Test interactions with optional parameters.
Diffstat (limited to 'bootstraptest')
-rw-r--r--bootstraptest/test_yjit.rb54
1 files changed, 54 insertions, 0 deletions
diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb
index d87454c38c..196fa454ff 100644
--- a/bootstraptest/test_yjit.rb
+++ b/bootstraptest/test_yjit.rb
@@ -1,3 +1,57 @@
+# test splat filling required and feeding rest
+assert_equal '[0, 1, 2, [3, 4]]', %q{
+ public def lead_rest(a, b, *rest)
+ [self, a, b, rest]
+ end
+
+ def call(args) = 0.lead_rest(*args)
+
+ call([1, 2, 3, 4])
+}
+
+# test missing opts are nil initialized
+assert_equal '[[0, 1, nil, 3], [0, 1, nil, 3], [0, 1, nil, 3, []], [0, 1, nil, 3, []]]', %q{
+ public def lead_opts(a, b=binding.local_variable_get(:c), c=3)
+ [self, a, b, c]
+ end
+
+ public def opts_rest(a=raise, b=binding.local_variable_get(:c), c=3, *rest)
+ [self, a, b, c, rest]
+ end
+
+ def call(args)
+ [
+ 0.lead_opts(1),
+ 0.lead_opts(*args),
+
+ 0.opts_rest(1),
+ 0.opts_rest(*args),
+ ]
+ end
+
+ call([1])
+}
+
+# test filled optionals with unspecified keyword param
+assert_equal 'ok', %q{
+ def opt_rest_opt_kw(_=1, *, k: :ok) = k
+
+ def call = opt_rest_opt_kw(0)
+
+ call
+}
+
+# test splat empty array with rest param
+assert_equal '[0, 1, 2, []]', %q{
+ public def foo(a=1, b=2, *rest)
+ [self, a, b, rest]
+ end
+
+ def call(args) = 0.foo(*args)
+
+ call([])
+}
+
# Regression test for yielding with autosplat to block with
# optional parameters. https://github.com/Shopify/yjit/issues/313
assert_equal '[:a, :b, :a, :b]', %q{