Skip to content

Commit 129d74c

Browse files
committed
Binding#implicit_parameters, etc. support the implicit "it" parameter
[Bug #21049]
1 parent fa7cddc commit 129d74c

File tree

6 files changed

+159
-15
lines changed

6 files changed

+159
-15
lines changed

defs/id.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ firstline, predefined = __LINE__+1, %[\
7878
_7 NUMPARAM_7
7979
_8 NUMPARAM_8
8080
_9 NUMPARAM_9
81+
<it> ItImplicit
82+
it It
8183
8284
"/*NULL*/" NULL
8385
empty?

iseq.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#endif
2020

2121
#include "eval_intern.h"
22+
#include "id.h"
2223
#include "id_table.h"
2324
#include "internal.h"
2425
#include "internal/bits.h"
@@ -3363,7 +3364,7 @@ iseq_data_to_ary(const rb_iseq_t *iseq)
33633364
for (i=0; i<iseq_body->local_table_size; i++) {
33643365
ID lid = iseq_body->local_table[i];
33653366
if (lid) {
3366-
if (rb_id2str(lid)) {
3367+
if (lid != idItImplicit && rb_id2str(lid)) {
33673368
rb_ary_push(locals, ID2SYM(lid));
33683369
}
33693370
else { /* hidden variable from id_internal() */
@@ -3673,10 +3674,10 @@ rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
36733674
ID req, opt, rest, block, key, keyrest;
36743675
#define PARAM_TYPE(type) rb_ary_push(a = rb_ary_new2(2), ID2SYM(type))
36753676
#define PARAM_ID(i) body->local_table[(i)]
3676-
#define PARAM(i, type) ( \
3677-
PARAM_TYPE(type), \
3678-
rb_id2str(PARAM_ID(i)) ? \
3679-
rb_ary_push(a, ID2SYM(PARAM_ID(i))) : \
3677+
#define PARAM(i, type) ( \
3678+
PARAM_TYPE(type), \
3679+
PARAM_ID(i) != idItImplicit && rb_id2str(PARAM_ID(i)) ? \
3680+
rb_ary_push(a, ID2SYM(PARAM_ID(i))) : \
36803681
a)
36813682

36823683
CONST_ID(req, "req");
@@ -3695,7 +3696,7 @@ rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
36953696
if (is_proc) {
36963697
for (i = 0; i < body->param.lead_num; i++) {
36973698
PARAM_TYPE(opt);
3698-
if (rb_id2str(PARAM_ID(i))) {
3699+
if (PARAM_ID(i) != idItImplicit && rb_id2str(PARAM_ID(i))) {
36993700
rb_ary_push(a, ID2SYM(PARAM_ID(i)));
37003701
}
37013702
rb_ary_push(args, a);

parse.y

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13035,14 +13035,14 @@ gettable(struct parser_params *p, ID id, const YYLTYPE *loc)
1303513035
}
1303613036
# endif
1303713037
/* method call without arguments */
13038-
if (dyna_in_block(p) && id == rb_intern("it") && !(DVARS_TERMINAL_P(p->lvtbl->args) || DVARS_TERMINAL_P(p->lvtbl->args->prev))) {
13038+
if (dyna_in_block(p) && id == idIt && !(DVARS_TERMINAL_P(p->lvtbl->args) || DVARS_TERMINAL_P(p->lvtbl->args->prev))) {
1303913039
if (numparam_used_p(p)) return 0;
1304013040
if (p->max_numparam == ORDINAL_PARAM) {
1304113041
compile_error(p, "ordinary parameter is defined");
1304213042
return 0;
1304313043
}
1304413044
if (!p->it_id) {
13045-
p->it_id = internal_id(p);
13045+
p->it_id = idItImplicit;
1304613046
vtable_add(p->lvtbl->args, p->it_id);
1304713047
}
1304813048
NODE *node = NEW_DVAR(p->it_id, loc);

prism_compile.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6398,8 +6398,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
63986398
}
63996399

64006400
if (scope_node->parameters != NULL && PM_NODE_TYPE_P(scope_node->parameters, PM_IT_PARAMETERS_NODE)) {
6401-
ID local = rb_make_temporary_id(local_index);
6402-
local_table_for_iseq->ids[local_index++] = local;
6401+
local_table_for_iseq->ids[local_index++] = idItImplicit;
64036402
}
64046403

64056404
// def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)

proc.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,12 @@ rb_numparam_id_p(ID id)
514514
return (tNUMPARAM_1 << ID_SCOPE_SHIFT) <= id && id < ((tNUMPARAM_1 + 9) << ID_SCOPE_SHIFT);
515515
}
516516

517+
int
518+
rb_implicit_param_p(ID id)
519+
{
520+
return id == idItImplicit || rb_numparam_id_p(id);
521+
}
522+
517523
/*
518524
* call-seq:
519525
* binding.local_variable_get(symbol) -> obj
@@ -662,9 +668,13 @@ bind_implicit_parameters(VALUE bindval)
662668
const rb_binding_t *bind;
663669
const rb_env_t *env;
664670

665-
// TODO: it
666-
667671
GetBindingPtr(bindval, bind);
672+
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
673+
674+
if (RBOOL(get_local_variable_ptr(&env, idItImplicit, FALSE))) {
675+
return rb_ary_new_from_args(1, ID2SYM(idIt));
676+
}
677+
668678
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
669679
return rb_vm_env_numbered_parameters(env);
670680
}
@@ -683,7 +693,9 @@ bind_implicit_parameter_get(VALUE bindval, VALUE sym)
683693
const VALUE *ptr;
684694
const rb_env_t *env;
685695

686-
if (!lid || !rb_numparam_id_p(lid)) {
696+
if (lid == idIt) lid = idItImplicit;
697+
698+
if (!lid || !rb_implicit_param_p(lid)) {
687699
rb_name_err_raise("'%1$s' is not an implicit parameter",
688700
bindval, ID2SYM(lid));
689701
}
@@ -695,6 +707,7 @@ bind_implicit_parameter_get(VALUE bindval, VALUE sym)
695707
return *ptr;
696708
}
697709

710+
if (lid == idItImplicit) lid = idIt;
698711
rb_name_err_raise("implicit parameter '%1$s' is not defined for %2$s", bindval, ID2SYM(lid));
699712
UNREACHABLE_RETURN(Qundef);
700713
}
@@ -713,7 +726,9 @@ bind_implicit_parameter_defined_p(VALUE bindval, VALUE sym)
713726
const rb_binding_t *bind;
714727
const rb_env_t *env;
715728

716-
if (!lid || !rb_numparam_id_p(lid)) {
729+
if (lid == idIt) lid = idItImplicit;
730+
731+
if (!lid || !rb_implicit_param_p(lid)) {
717732
rb_name_err_raise("'%1$s' is not an implicit parameter",
718733
bindval, ID2SYM(lid));
719734
}

test/ruby/test_proc.rb

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1691,7 +1691,7 @@ def test_numparam_is_not_local_variables
16911691
end
16921692
end
16931693

1694-
def test_implicit_parameters
1694+
def test_implicit_parameters_for_numparams
16951695
x = x = 1
16961696
assert_raise(NameError) { binding.implicit_parameter_get(:x) }
16971697
assert_raise(NameError) { binding.implicit_parameter_defined?(:x) }
@@ -1702,23 +1702,29 @@ def test_implicit_parameters
17021702
assert_equal("foo", binding.implicit_parameter_get(:_1))
17031703
assert_equal(nil, binding.implicit_parameter_get(:_5))
17041704
assert_raise(NameError) { binding.implicit_parameter_get(:_6) }
1705+
assert_raise(NameError) { binding.implicit_parameter_get(:it) }
17051706
assert_equal(true, binding.implicit_parameter_defined?(:_1))
17061707
assert_equal(true, binding.implicit_parameter_defined?(:_5))
17071708
assert_equal(false, binding.implicit_parameter_defined?(:_6))
1709+
assert_equal(false, binding.implicit_parameter_defined?(:it))
17081710
"bar".tap do
17091711
assert_equal([], binding.implicit_parameters)
17101712
assert_raise(NameError) { binding.implicit_parameter_get(:_1) }
17111713
assert_raise(NameError) { binding.implicit_parameter_get(:_6) }
1714+
assert_raise(NameError) { binding.implicit_parameter_get(:it) }
17121715
assert_equal(false, binding.implicit_parameter_defined?(:_1))
17131716
assert_equal(false, binding.implicit_parameter_defined?(:_6))
1717+
assert_equal(false, binding.implicit_parameter_defined?(:it))
17141718
end
17151719
assert_equal([:_1, :_2, :_3, :_4, :_5], binding.implicit_parameters)
17161720
assert_equal("foo", binding.implicit_parameter_get(:_1))
17171721
assert_equal(nil, binding.implicit_parameter_get(:_5))
17181722
assert_raise(NameError) { binding.implicit_parameter_get(:_6) }
1723+
assert_raise(NameError) { binding.implicit_parameter_get(:it) }
17191724
assert_equal(true, binding.implicit_parameter_defined?(:_1))
17201725
assert_equal(true, binding.implicit_parameter_defined?(:_5))
17211726
assert_equal(false, binding.implicit_parameter_defined?(:_6))
1727+
assert_equal(false, binding.implicit_parameter_defined?(:it))
17221728
end
17231729

17241730
"foo".tap do
@@ -1727,21 +1733,25 @@ def test_implicit_parameters
17271733
assert_raise(NameError) { binding.implicit_parameter_get(:_6) }
17281734
assert_equal(false, binding.implicit_parameter_defined?(:_1))
17291735
assert_equal(false, binding.implicit_parameter_defined?(:_6))
1736+
assert_equal(false, binding.implicit_parameter_defined?(:it))
17301737
"bar".tap do
17311738
_5 and flunk
17321739
assert_equal([:_1, :_2, :_3, :_4, :_5], binding.implicit_parameters)
17331740
assert_equal("bar", binding.implicit_parameter_get(:_1))
17341741
assert_equal(nil, binding.implicit_parameter_get(:_5))
17351742
assert_raise(NameError) { binding.implicit_parameter_get(:_6) }
1743+
assert_raise(NameError) { binding.implicit_parameter_get(:it) }
17361744
assert_equal(true, binding.implicit_parameter_defined?(:_1))
17371745
assert_equal(true, binding.implicit_parameter_defined?(:_5))
17381746
assert_equal(false, binding.implicit_parameter_defined?(:_6))
1747+
assert_equal(false, binding.implicit_parameter_defined?(:it))
17391748
end
17401749
assert_equal([], binding.implicit_parameters)
17411750
assert_raise(NameError) { binding.implicit_parameter_get(:_1) }
17421751
assert_raise(NameError) { binding.implicit_parameter_get(:_6) }
17431752
assert_equal(false, binding.implicit_parameter_defined?(:_1))
17441753
assert_equal(false, binding.implicit_parameter_defined?(:_6))
1754+
assert_equal(false, binding.implicit_parameter_defined?(:it))
17451755
end
17461756
end
17471757

@@ -1786,6 +1796,123 @@ def test_it_is_not_local_variable
17861796
end
17871797
end
17881798

1799+
def test_implicit_parameters_for_it
1800+
"foo".tap do
1801+
it or flunk
1802+
assert_equal([:it], binding.implicit_parameters)
1803+
assert_equal("foo", binding.implicit_parameter_get(:it))
1804+
assert_raise(NameError) { binding.implicit_parameter_get(:_1) }
1805+
assert_equal(true, binding.implicit_parameter_defined?(:it))
1806+
assert_equal(false, binding.implicit_parameter_defined?(:_1))
1807+
"bar".tap do
1808+
assert_equal([], binding.implicit_parameters)
1809+
assert_raise(NameError) { binding.implicit_parameter_get(:it) }
1810+
assert_raise(NameError) { binding.implicit_parameter_get(:_1) }
1811+
assert_equal(false, binding.implicit_parameter_defined?(:it))
1812+
assert_equal(false, binding.implicit_parameter_defined?(:_1))
1813+
end
1814+
assert_equal([:it], binding.implicit_parameters)
1815+
assert_equal("foo", binding.implicit_parameter_get(:it))
1816+
assert_raise(NameError) { binding.implicit_parameter_get(:_1) }
1817+
assert_equal(true, binding.implicit_parameter_defined?(:it))
1818+
assert_equal(false, binding.implicit_parameter_defined?(:_1))
1819+
end
1820+
1821+
"foo".tap do
1822+
assert_equal([], binding.implicit_parameters)
1823+
assert_raise(NameError) { binding.implicit_parameter_get(:it) }
1824+
assert_raise(NameError) { binding.implicit_parameter_get(:_1) }
1825+
assert_equal(false, binding.implicit_parameter_defined?(:it))
1826+
assert_equal(false, binding.implicit_parameter_defined?(:_1))
1827+
"bar".tap do
1828+
it or flunk
1829+
assert_equal([:it], binding.implicit_parameters)
1830+
assert_equal("bar", binding.implicit_parameter_get(:it))
1831+
assert_raise(NameError) { binding.implicit_parameter_get(:_1) }
1832+
assert_equal(true, binding.implicit_parameter_defined?(:it))
1833+
assert_equal(false, binding.implicit_parameter_defined?(:_1))
1834+
end
1835+
assert_equal([], binding.implicit_parameters)
1836+
assert_raise(NameError) { binding.implicit_parameter_get(:it) }
1837+
assert_raise(NameError) { binding.implicit_parameter_get(:_1) }
1838+
assert_equal(false, binding.implicit_parameter_defined?(:it))
1839+
assert_equal(false, binding.implicit_parameter_defined?(:_1))
1840+
end
1841+
end
1842+
1843+
def test_implicit_parameters_for_it_complex
1844+
"foo".tap do
1845+
it = "bar"
1846+
1847+
assert_equal([], binding.implicit_parameters)
1848+
assert_raise(NameError) { binding.implicit_parameter_get(:it) }
1849+
assert_equal(false, binding.implicit_parameter_defined?(:it))
1850+
1851+
assert_equal([:it], binding.local_variables)
1852+
assert_equal("bar", binding.local_variable_get(:it))
1853+
assert_equal(true, binding.local_variable_defined?(:it))
1854+
end
1855+
1856+
"foo".tap do
1857+
it or flunk
1858+
1859+
assert_equal([:it], binding.implicit_parameters)
1860+
assert_equal("foo", binding.implicit_parameter_get(:it))
1861+
assert_equal(true, binding.implicit_parameter_defined?(:it))
1862+
1863+
assert_equal([], binding.local_variables)
1864+
assert_raise(NameError) { binding.local_variable_get(:it) }
1865+
assert_equal(false, binding.local_variable_defined?(:it))
1866+
end
1867+
1868+
"foo".tap do
1869+
it or flunk
1870+
it = "bar"
1871+
1872+
assert_equal([:it], binding.implicit_parameters)
1873+
assert_equal("foo", binding.implicit_parameter_get(:it))
1874+
assert_equal(true, binding.implicit_parameter_defined?(:it))
1875+
1876+
assert_equal([:it], binding.local_variables)
1877+
assert_equal("bar", binding.local_variable_get(:it))
1878+
assert_equal(true, binding.local_variable_defined?(:it))
1879+
end
1880+
end
1881+
1882+
def test_implicit_parameters_for_it_and_numparams
1883+
"foo".tap do
1884+
it or flunk
1885+
"bar".tap do
1886+
_5 and flunk
1887+
assert_equal([:_1, :_2, :_3, :_4, :_5], binding.implicit_parameters)
1888+
assert_raise(NameError) { binding.implicit_parameter_get(:it) }
1889+
assert_equal("bar", binding.implicit_parameter_get(:_1))
1890+
assert_equal(nil, binding.implicit_parameter_get(:_5))
1891+
assert_raise(NameError) { binding.implicit_parameter_get(:_6) }
1892+
assert_equal(false, binding.implicit_parameter_defined?(:it))
1893+
assert_equal(true, binding.implicit_parameter_defined?(:_1))
1894+
assert_equal(true, binding.implicit_parameter_defined?(:_5))
1895+
assert_equal(false, binding.implicit_parameter_defined?(:_6))
1896+
end
1897+
end
1898+
1899+
"foo".tap do
1900+
_5 and flunk
1901+
"bar".tap do
1902+
it or flunk
1903+
assert_equal([:it], binding.implicit_parameters)
1904+
assert_equal("bar", binding.implicit_parameter_get(:it))
1905+
assert_raise(NameError) { binding.implicit_parameter_get(:_1) }
1906+
assert_raise(NameError) { binding.implicit_parameter_get(:_5) }
1907+
assert_raise(NameError) { binding.implicit_parameter_get(:_6) }
1908+
assert_equal(true, binding.implicit_parameter_defined?(:it))
1909+
assert_equal(false, binding.implicit_parameter_defined?(:_1))
1910+
assert_equal(false, binding.implicit_parameter_defined?(:_5))
1911+
assert_equal(false, binding.implicit_parameter_defined?(:_6))
1912+
end
1913+
end
1914+
end
1915+
17891916
def test_local_variable_set_wb
17901917
assert_ruby_status([], <<-'end;', '[Bug #13605]', timeout: 30)
17911918
b = binding

0 commit comments

Comments
 (0)