mirror of
https://github.com/ruby/ruby.git
synced 2026-01-27 04:24:23 +00:00
Avoid allocation for positional splat for literal array keyword argument
If all nodes in the array are safe, then it is safe to avoid allocation for the positional splat: ```ruby m(*a, kw: [:a]) # Safe m(*a, kw: [meth]) # Unsafe ``` This avoids an unnecessary allocation in a Rails method call. Details: https://github.com/rails/rails/pull/54949/files#r2052645431
This commit is contained in:
parent
d84a811f31
commit
353fa6f0ba
@ -6643,6 +6643,14 @@ setup_args_dup_rest_p(const NODE *argn)
|
||||
return false;
|
||||
case NODE_COLON2:
|
||||
return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
|
||||
case NODE_LIST:
|
||||
while (argn) {
|
||||
if (setup_args_dup_rest_p(RNODE_LIST(argn)->nd_head)) {
|
||||
return true;
|
||||
}
|
||||
argn = RNODE_LIST(argn)->nd_next;
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1882,6 +1882,15 @@ pm_setup_args_dup_rest_p(const pm_node_t *node)
|
||||
}
|
||||
case PM_IMPLICIT_NODE:
|
||||
return pm_setup_args_dup_rest_p(((const pm_implicit_node_t *) node)->value);
|
||||
case PM_ARRAY_NODE: {
|
||||
const pm_array_node_t *cast = (const pm_array_node_t *) node;
|
||||
for (size_t index = 0; index < cast->elements.size; index++) {
|
||||
if (pm_setup_args_dup_rest_p(cast->elements.nodes[index])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -807,6 +807,13 @@ class TestAllocation < Test::Unit::TestCase
|
||||
check_allocations(0, 1, "keyword(*empty_array, a: ->{}#{block})") # LAMBDA
|
||||
check_allocations(0, 1, "keyword(*empty_array, a: $1#{block})") # NTH_REF
|
||||
check_allocations(0, 1, "keyword(*empty_array, a: $`#{block})") # BACK_REF
|
||||
|
||||
# LIST: Only 1 array (literal [:c]), not 2 (one for [:c] and one for *empty_array)
|
||||
check_allocations(1, 1, "keyword(*empty_array, a: empty_array, b: [:c]#{block})")
|
||||
check_allocations(1, 1, "keyword(*empty_array, a: empty_array, b: [:c, $x]#{block})")
|
||||
# LIST unsafe: 2 (one for [Object()] and one for *empty_array)
|
||||
check_allocations(2, 1, "keyword(*empty_array, a: empty_array, b: [Object()]#{block})")
|
||||
check_allocations(2, 1, "keyword(*empty_array, a: empty_array, b: [:c, $x, Object()]#{block})")
|
||||
RUBY
|
||||
end
|
||||
|
||||
@ -877,6 +884,13 @@ class TestAllocation < Test::Unit::TestCase
|
||||
check_allocations(0, 1, "keyword.(*empty_array, a: ->{}#{block})") # LAMBDA
|
||||
check_allocations(0, 1, "keyword.(*empty_array, a: $1#{block})") # NTH_REF
|
||||
check_allocations(0, 1, "keyword.(*empty_array, a: $`#{block})") # BACK_REF
|
||||
|
||||
# LIST safe: Only 1 array (literal [:c]), not 2 (one for [:c] and one for *empty_array)
|
||||
check_allocations(1, 1, "keyword.(*empty_array, a: empty_array, b: [:c]#{block})")
|
||||
check_allocations(1, 1, "keyword.(*empty_array, a: empty_array, b: [:c, $x]#{block})")
|
||||
# LIST unsafe: 2 (one for [:c] and one for *empty_array)
|
||||
check_allocations(2, 1, "keyword.(*empty_array, a: empty_array, b: [Object()]#{block})")
|
||||
check_allocations(2, 1, "keyword.(*empty_array, a: empty_array, b: [:c, $x, Object()]#{block})")
|
||||
RUBY
|
||||
end
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user