diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb index d55c05557..1df239278 100644 --- a/mrbgems/mruby-metaprog/test/metaprog.rb +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -193,6 +193,18 @@ assert('Module#class_variable_defined?', '15.2.2.4.16') do assert_true Test4ClassVariableDefined.class_variable_defined?(:@@cv) assert_false Test4ClassVariableDefined.class_variable_defined?(:@@noexisting) assert_raise(NameError) { Test4ClassVariableDefined.class_variable_defined?("@@2") } + + # shared empty iv_tbl (include) + m = Module.new + c = Class.new{include m} + m.class_variable_set(:@@cv2, 2) + assert_true c.class_variable_defined?(:@@cv2) + + # shared empty iv_tbl (prepend) + m = Module.new + c = Class.new{prepend m} + m.class_variable_set(:@@cv2, 2) + assert_true c.class_variable_defined?(:@@cv2) end assert('Module#class_variable_get', '15.2.2.4.17') do @@ -205,6 +217,26 @@ assert('Module#class_variable_get', '15.2.2.4.17') do %w[@@a? @@! @a a].each do |n| assert_raise(NameError) { Test4ClassVariableGet.class_variable_get(n) } end + + # shared empty iv_tbl (include) + m = Module.new + class Test4ClassVariableGet end + Test4ClassVariableGet.include m + m.class_variable_set(:@@cv2, 2) + assert_equal 2, Test4ClassVariableGet.class_variable_get(:@@cv2) + class Test4ClassVariableGet + assert_equal 2, @@cv2 + end + + # shared empty iv_tbl (prepend) + m = Module.new + class Test4ClassVariableGet end + Test4ClassVariableGet.prepend m + m.class_variable_set(:@@cv2, 2) + assert_equal 2, Test4ClassVariableGet.class_variable_get(:@@cv2) + class Test4ClassVariableGet + assert_equal 2, @@cv2 + end end assert('Module#class_variable_set', '15.2.2.4.18') do @@ -241,6 +273,18 @@ assert('Module#class_variables', '15.2.2.4.19') do assert_equal [:@@var1], Test4ClassVariables1.class_variables assert_equal [:@@var2, :@@var1], Test4ClassVariables2.class_variables + + # shared empty iv_tbl (include) + m = Module.new + c = Class.new{include m} + m.class_variable_set(:@@var3, 3) + assert_equal [:@@var3], c.class_variables + + # shared empty iv_tbl (prepend) + m = Module.new + c = Class.new{prepend m} + m.class_variable_set(:@@var3, 3) + assert_equal [:@@var3], c.class_variables end assert('Module#constants', '15.2.2.4.24') do @@ -256,6 +300,18 @@ assert('Module#constants', '15.2.2.4.24') do assert_equal [ :C ], TestA.constants assert_equal [ :C, :C2 ], $n + + # shared empty iv_tbl (include) + m = Module.new + TestC = Class.new{include m} + m::C3 = 1 + assert_equal [ :C3 ], TestC.constants + + # shared empty iv_tbl (prepend) + m = Module.new + TestC = Class.new{prepend m} + m::C3 = 1 + assert_equal [ :C3 ], TestC.constants end assert('Module#included_modules', '15.2.2.4.30') do diff --git a/src/class.c b/src/class.c index cca5f768c..dd614ff56 100644 --- a/src/class.c +++ b/src/class.c @@ -1401,7 +1401,6 @@ include_class_new(mrb_state *mrb, struct RClass *m, struct RClass *super) m = m->c; } MRB_CLASS_ORIGIN(m); - ic->iv = m->iv; ic->mt = m->mt; ic->super = super; if (m->tt == MRB_TT_ICLASS) { @@ -1526,7 +1525,6 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) c->super = origin; origin->mt = c->mt; c->mt = NULL; - origin->iv = c->iv; mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)origin); c->flags |= MRB_FL_CLASS_IS_PREPENDED; } diff --git a/src/variable.c b/src/variable.c index 3bae38c18..2afbfd93e 100644 --- a/src/variable.c +++ b/src/variable.c @@ -296,6 +296,12 @@ obj_iv_p(mrb_value obj) } } +static iv_tbl* +class_iv_ptr(struct RClass *c) +{ + return c->tt == MRB_TT_ICLASS ? c->c->iv : c->iv; +} + MRB_API mrb_value mrb_obj_iv_get(mrb_state *mrb, struct RObject *obj, mrb_sym sym) { @@ -593,7 +599,7 @@ mrb_mod_class_variables(mrb_state *mrb, mrb_value mod) ary = mrb_ary_new(mrb); c = mrb_class_ptr(mod); while (c) { - iv_foreach(mrb, c->iv, cv_i, &ary); + iv_foreach(mrb, class_iv_ptr(c), cv_i, &ary); if (!inherit) break; c = c->super; } @@ -608,7 +614,7 @@ mrb_mod_cv_get(mrb_state *mrb, struct RClass *c, mrb_sym sym) int given = FALSE; while (c) { - if (c->iv && iv_get(mrb, c->iv, sym, &v)) { + if (iv_get(mrb, class_iv_ptr(c), sym, &v)) { given = TRUE; } c = c->super; @@ -622,7 +628,7 @@ mrb_mod_cv_get(mrb_state *mrb, struct RClass *c, mrb_sym sym) if (c->tt == MRB_TT_CLASS || c->tt == MRB_TT_MODULE) { given = FALSE; while (c) { - if (c->iv && iv_get(mrb, c->iv, sym, &v)) { + if (iv_get(mrb, class_iv_ptr(c), sym, &v)) { given = TRUE; } c = c->super; @@ -647,7 +653,7 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) struct RClass * cls = c; while (c) { - iv_tbl *t = c->iv; + iv_tbl *t = class_iv_ptr(c); int pos = iv_get(mrb, t, sym, NULL); if (pos) { @@ -674,7 +680,10 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) break; } } - else{ + else if (cls && cls->tt == MRB_TT_ICLASS) { + c = cls->c; + } + else { c = cls; } @@ -697,7 +706,7 @@ mrb_bool mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym) { while (c) { - iv_tbl *t = c->iv; + iv_tbl *t = class_iv_ptr(c); if (iv_get(mrb, t, sym, NULL)) return TRUE; c = c->super; } @@ -765,7 +774,7 @@ const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym, mrb_bool skip) if (skip) c = c->super; L_RETRY: while (c) { - if (!MRB_FLAG_TEST(c, MRB_FL_CLASS_IS_PREPENDED) && c->iv && iv_get(mrb, c->iv, sym, &v)) { + if (!MRB_FLAG_TEST(c, MRB_FL_CLASS_IS_PREPENDED) && iv_get(mrb, class_iv_ptr(c), sym, &v)) { return v; } c = c->super; @@ -801,14 +810,14 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym) c = MRB_PROC_TARGET_CLASS(proc); if (!c) c = mrb->object_class; - if (iv_get(mrb, c->iv, sym, &v)) { + if (iv_get(mrb, class_iv_ptr(c), sym, &v)) { return v; } c2 = c; while (c2 && c2->tt == MRB_TT_SCLASS) { mrb_value klass; - if (!iv_get(mrb, c2->iv, MRB_SYM(__attached__), &klass)) { + if (!iv_get(mrb, class_iv_ptr(c2), MRB_SYM(__attached__), &klass)) { c2 = NULL; break; } @@ -819,7 +828,7 @@ mrb_vm_const_get(mrb_state *mrb, mrb_sym sym) while (proc) { c2 = MRB_PROC_TARGET_CLASS(proc); if (!c2) c2 = mrb->object_class; - if (c2 && iv_get(mrb, c2->iv, sym, &v)) { + if (c2 && iv_get(mrb, class_iv_ptr(c2), sym, &v)) { return v; } proc = proc->upper; @@ -912,7 +921,7 @@ mrb_mod_constants(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "|b", &inherit); ary = mrb_ary_new(mrb); while (c) { - iv_foreach(mrb, c->iv, const_i, &ary); + iv_foreach(mrb, class_iv_ptr(c), const_i, &ary); if (!inherit) break; c = c->super; if (c == mrb->object_class) break; @@ -988,7 +997,7 @@ const_defined_0(mrb_state *mrb, mrb_value mod, mrb_sym id, mrb_bool exclude, mrb tmp = klass; retry: while (tmp) { - if (iv_get(mrb, tmp->iv, id, NULL)) { + if (iv_get(mrb, class_iv_ptr(tmp), id, NULL)) { return TRUE; } if (!recurse && (klass != mrb->object_class)) break; @@ -1047,7 +1056,7 @@ find_class_sym(mrb_state *mrb, struct RClass *outer, struct RClass *c) if (outer == c) return 0; arg.c = c; arg.sym = 0; - iv_foreach(mrb, outer->iv, csym_i, &arg); + iv_foreach(mrb, class_iv_ptr(outer), csym_i, &arg); return arg.sym; } diff --git a/test/t/module.rb b/test/t/module.rb index c18276a9f..ef25f01e2 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -231,6 +231,18 @@ assert('Module#const_defined?', '15.2.2.4.20') do assert_true Test4ConstDefined.const_defined?(:Const4Test4ConstDefined) assert_false Test4ConstDefined.const_defined?(:NotExisting) assert_wrong_const_name{ Test4ConstDefined.const_defined?(:wrong_name) } + + # shared empty iv_tbl (include) + m = Module.new + c = Class.new{include m} + m::CONST = 1 + assert_true c.const_defined?(:CONST) + + # shared empty iv_tbl (prepend) + m = Module.new + c = Class.new{prepend m} + m::CONST = 1 + assert_true c.const_defined?(:CONST) end assert('Module#const_get', '15.2.2.4.21') do @@ -246,6 +258,18 @@ assert('Module#const_get', '15.2.2.4.21') do assert_uninitialized_const{ Test4ConstGet.const_get(:I_DO_NOT_EXIST) } assert_uninitialized_const{ Test4ConstGet.const_get("I_DO_NOT_EXIST::ME_NEITHER") } assert_wrong_const_name{ Test4ConstGet.const_get(:wrong_name) } + + # shared empty iv_tbl (include) + m = Module.new + c = Class.new{include m} + m::CONST = 1 + assert_equal 1, c.const_get(:CONST) + + # shared empty iv_tbl (prepend) + m = Module.new + c = Class.new{prepend m} + m::CONST = 1 + assert_equal 1, c.const_get(:CONST) end assert('Module#const_set', '15.2.2.4.23') do @@ -779,7 +803,7 @@ end assert('module to return the last value') do m = module M; :m end - assert_equal(m, :m) + assert_equal(:m, m) end assert('module to return nil if body is empty') do @@ -796,3 +820,25 @@ assert('get constant of parent module in singleton class; issue #3568') do assert_equal("value", actual) end + +assert('shared empty iv_tbl (include)') do + m1 = Module.new + m2 = Module.new{include m1} + c = Class.new{include m2} + m1::CONST1 = 1 + assert_equal 1, m2::CONST1 + assert_equal 1, c::CONST1 + m2::CONST2 = 2 + assert_equal 2, c::CONST2 +end + +assert('shared empty iv_tbl (prepend)') do + m1 = Module.new + m2 = Module.new{prepend m1} + c = Class.new{include m2} + m1::CONST1 = 1 + assert_equal 1, m2::CONST1 + assert_equal 1, c::CONST1 + m2::CONST2 = 2 + assert_equal 2, c::CONST2 +end