Project

General

Profile

nested_methods-r29944-20101127.diff

a patch to change behavior of nested methods - shugo (Shugo Maeda), 11/27/2010 01:39 PM

Download (8.65 KB)

View differences:

bootstraptest/test_method.rb
287 287
assert_equal '1',       %q( class C
288 288
                              def m
289 289
                                def mm() 1 end
290
                                mm
290 291
                              end
291 292
                            end
292
                            C.new.m
293
                            C.new.mm )
293
                            C.new.m )
294 294
assert_equal '1',       %q( class C
295 295
                              def m
296 296
                                def mm() 1 end
297
                                mm
297 298
                              end
298 299
                            end
299
                            instance_eval "C.new.m; C.new.mm" )
300
                            instance_eval "C.new.m" )
300 301

  
301 302
# method_missing
302 303
assert_equal ':m',      %q( class C
compile.c
4575 4575
	ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
4576 4576
	ADD_INSN1(ret, nd_line(node), putobject, ID2SYM(node->nd_mid));
4577 4577
	ADD_INSN1(ret, nd_line(node), putiseq, iseqval);
4578
	ADD_SEND (ret, nd_line(node), ID2SYM(id_core_define_method), INT2FIX(3));
4578
	ADD_INSN1(ret, nd_line(node), putobject,
4579
		  node->flags & NODE_FL_NESTED_DEF ? Qtrue : Qfalse);
4580
	ADD_SEND (ret, nd_line(node), ID2SYM(id_core_define_method), INT2FIX(4));
4579 4581

  
4580 4582
	if (poped) {
4581 4583
	    ADD_INSN(ret, nd_line(node), pop);
include/ruby/ruby.h
630 630
#define RMODULE_M_TBL(m) RCLASS_M_TBL(m)
631 631
#define RMODULE_SUPER(m) RCLASS_SUPER(m)
632 632
#define RMODULE_IS_OVERLAYED FL_USER2
633
#define RMODULE_HAS_NESTED_METHODS FL_USER3
633 634

  
634 635
struct RFloat {
635 636
    struct RBasic basic;
node.h
269 269
#define NODE_FL_NEWLINE (((VALUE)1)<<7)
270 270
#define NODE_FL_CREF_PUSHED_BY_EVAL NODE_FL_NEWLINE
271 271
#define NODE_FL_CREF_OMOD_SHARED (((VALUE)1)<<6)
272
#define NODE_FL_NESTED_DEF NODE_FL_CREF_OMOD_SHARED
272 273

  
273 274
#define NODE_TYPESHIFT 8
274 275
#define NODE_TYPEMASK  (((VALUE)0x7f)<<NODE_TYPESHIFT)
parse.y
2967 2967
			reduce_nodes(&body);
2968 2968
			$$ = NEW_DEFN($2, $4, body, NOEX_PRIVATE);
2969 2969
			nd_set_line($$, $<num>1);
2970
			if (in_def > 1 || in_single > 0)
2971
			    $$->flags |= NODE_FL_NESTED_DEF;
2970 2972
		    /*%
2971 2973
			$$ = dispatch3(def, $2, $4, $5);
2972 2974
		    %*/
test/rdoc/test_rdoc_text.rb
62 62
    assert_equal expected, flush_left(text)
63 63
  end
64 64

  
65
  def formatter() RDoc::Markup::ToHtml.new end
65 66
  def test_markup
66
    def formatter() RDoc::Markup::ToHtml.new end
67 67

  
68 68
    assert_equal "<p>\nhi\n</p>\n", markup('hi')
69 69
  end
test/ruby/test_nested_method.rb
1
require 'test/unit'
2

  
3
class TestNestedMethod < Test::Unit::TestCase
4
  def call_nested_method
5
    def foo
6
      return "foo"
7
    end
8

  
9
    return foo
10
  end
11

  
12
  def test_nested_method
13
    assert_equal("foo", call_nested_method)
14
    assert_raise(NoMethodError) { foo() }
15
  end
16

  
17
  def test_doubly_nested_method
18
    def call_doubly_nested_method
19
      def foo
20
        return "foo"
21
      end
22

  
23
      return foo
24
    end
25

  
26
    assert_equal("foo", call_doubly_nested_method)
27
    assert_raise(NoMethodError) { foo() }
28
  end
29
end
vm.c
1822 1822
    return self;
1823 1823
}
1824 1824

  
1825
static VALUE
1826
find_module_for_nested_methods(NODE *cref, VALUE klass)
1827
{
1828
    VALUE iclass;
1829

  
1830
    if (NIL_P(cref->nd_omod))
1831
	return Qnil;
1832
    iclass = rb_hash_lookup(cref->nd_omod, klass);
1833
    if (NIL_P(iclass))
1834
	return Qnil;
1835
    while (iclass) {
1836
	VALUE module = RBASIC(iclass)->klass;
1837
	if (FL_TEST(module, RMODULE_HAS_NESTED_METHODS)) {
1838
	    return module;
1839
	}
1840
	iclass = RCLASS_SUPER(iclass);
1841
    }
1842
    return Qnil;
1843
}
1844

  
1825 1845
VALUE rb_iseq_clone(VALUE iseqval, VALUE newcbase);
1826 1846

  
1827 1847
static void
1828
vm_define_method(rb_thread_t *th, VALUE obj, ID id, VALUE iseqval,
1848
vm_define_method(rb_thread_t *th, VALUE obj, ID id, VALUE iseqval, VALUE nested,
1829 1849
		 rb_num_t is_singleton, NODE *cref)
1830 1850
{
1831 1851
    VALUE klass = cref->nd_clss;
1852
    VALUE target, defined_class;
1853
    rb_method_entry_t *me;
1832 1854
    int noex = (int)cref->nd_visi;
1855
    int is_nested = RTEST(nested);
1833 1856
    rb_iseq_t *miseq;
1834 1857
    GetISeqPtr(iseqval, miseq);
1835 1858

  
......
1854 1877
	noex = NOEX_PUBLIC;
1855 1878
    }
1856 1879

  
1880
    if (is_nested && th->cfp->lfp == th->cfp->dfp) {
1881
	VALUE c;
1882
       	if (TYPE(klass) == T_MODULE) {
1883
	    c = rb_obj_class(th->cfp->self);
1884
	}
1885
	else {
1886
	    c = klass;
1887
	}
1888
	if (cref->flags & NODE_FL_CREF_OMOD_SHARED) {
1889
	    target = Qnil;
1890
	}
1891
	else {
1892
	    target = find_module_for_nested_methods(cref, c);
1893
	}
1894
	if (NIL_P(target)) {
1895
	    target = rb_module_new();
1896
	    FL_SET(target, RMODULE_HAS_NESTED_METHODS);
1897
	    rb_overlay_module(cref, c, target);
1898
	}
1899
	else {
1900
	    me = search_method(target, id, Qnil, &defined_class);
1901
	    if (me && me->def->type == VM_METHOD_TYPE_ISEQ &&
1902
		me->def->body.iseq == miseq) {
1903
		return;
1904
	    }
1905
	}
1906
	noex = NOEX_PRIVATE;
1907
    }
1908
    else {
1909
	target = klass;
1910
    }
1857 1911
    /* dup */
1858 1912
    COPY_CREF(miseq->cref_stack, cref);
1859 1913
    miseq->cref_stack->nd_visi = NOEX_PUBLIC;
1860
    miseq->klass = klass;
1914
    miseq->klass = target;
1861 1915
    miseq->defined_method_id = id;
1862
    rb_add_method(klass, id, VM_METHOD_TYPE_ISEQ, miseq, noex);
1916
    rb_add_method(target, id, VM_METHOD_TYPE_ISEQ, miseq, noex);
1863 1917

  
1864 1918
    if (!is_singleton && noex == NOEX_MODFUNC) {
1865 1919
	rb_add_method(rb_singleton_class(klass), id, VM_METHOD_TYPE_ISEQ, miseq, NOEX_PUBLIC);
......
1873 1927
} while (0)
1874 1928

  
1875 1929
static VALUE
1876
m_core_define_method(VALUE self, VALUE cbase, VALUE sym, VALUE iseqval)
1930
m_core_define_method(VALUE self, VALUE cbase, VALUE sym, VALUE iseqval, VALUE nested)
1877 1931
{
1878 1932
    REWIND_CFP({
1879
	vm_define_method(GET_THREAD(), cbase, SYM2ID(sym), iseqval, 0, rb_vm_cref());
1933
	vm_define_method(GET_THREAD(), cbase, SYM2ID(sym), iseqval, nested, 0, rb_vm_cref());
1880 1934
    });
1881 1935
    return Qnil;
1882 1936
}
......
1885 1939
m_core_define_singleton_method(VALUE self, VALUE cbase, VALUE sym, VALUE iseqval)
1886 1940
{
1887 1941
    REWIND_CFP({
1888
	vm_define_method(GET_THREAD(), cbase, SYM2ID(sym), iseqval, 1, rb_vm_cref());
1942
	vm_define_method(GET_THREAD(), cbase, SYM2ID(sym), iseqval, Qfalse, 1, rb_vm_cref());
1889 1943
    });
1890 1944
    return Qnil;
1891 1945
}
......
2001 2055
    rb_define_method_id(klass, id_core_set_method_alias, m_core_set_method_alias, 3);
2002 2056
    rb_define_method_id(klass, id_core_set_variable_alias, m_core_set_variable_alias, 2);
2003 2057
    rb_define_method_id(klass, id_core_undef_method, m_core_undef_method, 2);
2004
    rb_define_method_id(klass, id_core_define_method, m_core_define_method, 3);
2058
    rb_define_method_id(klass, id_core_define_method, m_core_define_method, 4);
2005 2059
    rb_define_method_id(klass, id_core_define_singleton_method, m_core_define_singleton_method, 3);
2006 2060
    rb_define_method_id(klass, id_core_set_postexe, m_core_set_postexe, 1);
2007 2061
    rb_obj_freeze(fcore);
vm_core.h
717 717
    } \
718 718
} while (0)
719 719

  
720
void rb_overlay_module(NODE*, VALUE, VALUE);
721

  
720 722
#if defined __GNUC__ && __GNUC__ >= 4
721 723
#pragma GCC visibility push(default)
722 724
#endif
vm_method.c
711 711
    }
712 712

  
713 713
    if (!RTEST(rb_class_inherited_p(klass, me->klass))) {
714
	VALUE mod = rb_module_new();
715
	rb_overlay_module(cref, klass, mod);
716
	klass = mod;
714
	if (FL_TEST(me->klass, RMODULE_HAS_NESTED_METHODS)) {
715
	    klass = me->klass;
716
	}
717
	else {
718
	    VALUE mod = rb_module_new();
719
	    rb_overlay_module(cref, klass, mod);
720
	    klass = mod;
721
	}
717 722
    }
718 723
    rb_add_method(klass, id, VM_METHOD_TYPE_UNDEF, 0, NOEX_PUBLIC);
719 724