diff options
Diffstat (limited to 'class.c')
-rw-r--r-- | class.c | 45 |
1 files changed, 35 insertions, 10 deletions
@@ -894,12 +894,21 @@ add_refined_method_entry_i(ID key, VALUE value, void *data) static void ensure_origin(VALUE klass); +static enum rb_id_table_iterator_result +clear_module_cache_i(ID id, VALUE val, void *data) +{ + VALUE klass = (VALUE)data; + rb_clear_method_cache(klass, id); + return ID_TABLE_CONTINUE; +} + static int include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super) { VALUE p, iclass; int method_changed = 0, constant_changed = 0; struct rb_id_table *const klass_m_tbl = RCLASS_M_TBL(RCLASS_ORIGIN(klass)); + VALUE original_klass = klass; if (FL_TEST(module, RCLASS_REFINED_BY_ANY)) { ensure_origin(module); @@ -912,7 +921,7 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super) if (klass_m_tbl && klass_m_tbl == RCLASS_M_TBL(module)) return -1; /* ignore if the module included already in superclasses */ - for (p = RCLASS_SUPER(klass); p; p = RCLASS_SUPER(p)) { + for (p = RCLASS_SUPER(klass); p; p = RCLASS_SUPER(p)) { int type = BUILTIN_TYPE(p); if (type == T_ICLASS) { if (RCLASS_M_TBL(p) == RCLASS_M_TBL(module)) { @@ -924,37 +933,53 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super) } else if (type == T_CLASS) { if (!search_super) break; - superclass_seen = TRUE; + superclass_seen = TRUE; } } - iclass = rb_include_class_new(module, RCLASS_SUPER(c)); + + VALUE super_class = RCLASS_SUPER(c); + + // invalidate inline method cache + tbl = RMODULE_M_TBL(module); + if (tbl && rb_id_table_size(tbl)) { + if (search_super) { // include + if (super_class && !RB_TYPE_P(super_class, T_MODULE)) { + rb_id_table_foreach(tbl, clear_module_cache_i, (void *)super_class); + } + } + else { // prepend + if (!RB_TYPE_P(original_klass, T_MODULE)) { + rb_id_table_foreach(tbl, clear_module_cache_i, (void *)original_klass); + } + } + method_changed = 1; + } + + // setup T_ICLASS for the include/prepend module + iclass = rb_include_class_new(module, super_class); c = RCLASS_SET_SUPER(c, iclass); RCLASS_SET_INCLUDER(iclass, klass); { VALUE m = module; - if (BUILTIN_TYPE(m) == T_ICLASS) m = RBASIC(m)->klass; - rb_module_add_to_subclasses_list(m, iclass); + if (BUILTIN_TYPE(m) == T_ICLASS) m = RBASIC(m)->klass; + rb_module_add_to_subclasses_list(m, iclass); } if (FL_TEST(klass, RMODULE_IS_REFINEMENT)) { VALUE refined_class = rb_refinement_module_get_refined_class(klass); - rb_id_table_foreach(RMODULE_M_TBL(module), add_refined_method_entry_i, (void *)refined_class); + rb_id_table_foreach(RMODULE_M_TBL(module), add_refined_method_entry_i, (void *)refined_class); FL_SET(c, RMODULE_INCLUDED_INTO_REFINEMENT); } - tbl = RMODULE_M_TBL(module); - if (tbl && rb_id_table_size(tbl)) method_changed = 1; - tbl = RMODULE_CONST_TBL(module); if (tbl && rb_id_table_size(tbl)) constant_changed = 1; skip: module = RCLASS_SUPER(module); } - if (method_changed) rb_clear_method_cache_by_class(klass); if (constant_changed) rb_clear_constant_cache(); return method_changed; |