Skip to content

Commit f0f9788

Browse files
committed
merge revision(s) 1d94a9e: [Backport #21447]
Fix handling of PM_CONSTANT_PATH_NODE node in keyword arguments with ARGS_SPLAT This was handled correctly in parse.y (NODE_COLON2), but not in prism. This wasn't caught earlier, because I only added tests for the optimized case and not the unoptimized case. Add tests for the unoptimized case. In code terms: ```ruby m(*a, kw: lvar::X) # Does not require allocation for *a m(*a, kw: method()::X) # Requires allocation for *a ``` This commit fixes the second case when prism is used.
1 parent fee9200 commit f0f9788

File tree

3 files changed

+14
-4
lines changed

3 files changed

+14
-4
lines changed

prism_compile.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1855,7 +1855,6 @@ pm_setup_args_dup_rest_p(const pm_node_t *node)
18551855
switch (PM_NODE_TYPE(node)) {
18561856
case PM_BACK_REFERENCE_READ_NODE:
18571857
case PM_CLASS_VARIABLE_READ_NODE:
1858-
case PM_CONSTANT_PATH_NODE:
18591858
case PM_CONSTANT_READ_NODE:
18601859
case PM_FALSE_NODE:
18611860
case PM_FLOAT_NODE:
@@ -1874,6 +1873,13 @@ pm_setup_args_dup_rest_p(const pm_node_t *node)
18741873
case PM_SYMBOL_NODE:
18751874
case PM_TRUE_NODE:
18761875
return false;
1876+
case PM_CONSTANT_PATH_NODE: {
1877+
const pm_constant_path_node_t *cast = (const pm_constant_path_node_t *) node;
1878+
if (cast->parent != NULL) {
1879+
return pm_setup_args_dup_rest_p(cast->parent);
1880+
}
1881+
return false;
1882+
}
18771883
case PM_IMPLICIT_NODE:
18781884
return pm_setup_args_dup_rest_p(((const pm_implicit_node_t *) node)->value);
18791885
default:

test/ruby/test_allocation.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -742,13 +742,15 @@ def self.r2k(*a#{block}); end
742742
def test_no_array_allocation_with_splat_and_nonstatic_keywords
743743
check_allocations(<<~RUBY)
744744
def self.keyword(a: nil, b: nil#{block}); end
745+
def self.Object; Object end
745746
746747
check_allocations(0, 1, "keyword(*empty_array, a: empty_array#{block})") # LVAR
747748
check_allocations(0, 1, "->{keyword(*empty_array, a: empty_array#{block})}.call") # DVAR
748749
check_allocations(0, 1, "$x = empty_array; keyword(*empty_array, a: $x#{block})") # GVAR
749750
check_allocations(0, 1, "@x = empty_array; keyword(*empty_array, a: @x#{block})") # IVAR
750751
check_allocations(0, 1, "self.class.const_set(:X, empty_array); keyword(*empty_array, a: X#{block})") # CONST
751-
check_allocations(0, 1, "keyword(*empty_array, a: Object::X#{block})") # COLON2
752+
check_allocations(0, 1, "keyword(*empty_array, a: Object::X#{block})") # COLON2 - safe
753+
check_allocations(1, 1, "keyword(*empty_array, a: Object()::X#{block})") # COLON2 - unsafe
752754
check_allocations(0, 1, "keyword(*empty_array, a: ::X#{block})") # COLON3
753755
check_allocations(0, 1, "T = self; #{'B = block' unless block.empty?}; class Object; @@x = X; T.keyword(*X, a: @@x#{', &B' unless block.empty?}) end") # CVAR
754756
check_allocations(0, 1, "keyword(*empty_array, a: empty_array, b: 1#{block})") # INTEGER
@@ -807,13 +809,15 @@ def test_no_array_allocation_with_splat_and_nonstatic_keywords
807809

808810
check_allocations(<<~RUBY)
809811
keyword = keyword = proc{ |a: nil, b: nil #{block}| }
812+
def self.Object; Object end
810813
811814
check_allocations(0, 1, "keyword.(*empty_array, a: empty_array#{block})") # LVAR
812815
check_allocations(0, 1, "->{keyword.(*empty_array, a: empty_array#{block})}.call") # DVAR
813816
check_allocations(0, 1, "$x = empty_array; keyword.(*empty_array, a: $x#{block})") # GVAR
814817
check_allocations(0, 1, "@x = empty_array; keyword.(*empty_array, a: @x#{block})") # IVAR
815818
check_allocations(0, 1, "self.class.const_set(:X, empty_array); keyword.(*empty_array, a: X#{block})") # CONST
816-
check_allocations(0, 1, "keyword.(*empty_array, a: Object::X#{block})") # COLON2
819+
check_allocations(0, 1, "keyword.(*empty_array, a: Object::X#{block})") # COLON2 - safe
820+
check_allocations(1, 1, "keyword.(*empty_array, a: Object()::X#{block})") # COLON2 - unsafe
817821
check_allocations(0, 1, "keyword.(*empty_array, a: ::X#{block})") # COLON3
818822
check_allocations(0, 1, "T = keyword; #{'B = block' unless block.empty?}; class Object; @@x = X; T.(*X, a: @@x#{', &B' unless block.empty?}) end") # CVAR
819823
check_allocations(0, 1, "keyword.(*empty_array, a: empty_array, b: 1#{block})") # INTEGER

version.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
1212
#define RUBY_VERSION_TEENY 4
1313
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
14-
#define RUBY_PATCHLEVEL 45
14+
#define RUBY_PATCHLEVEL 46
1515

1616
#include "ruby/version.h"
1717
#include "ruby/internal/abi.h"

0 commit comments

Comments
 (0)