summaryrefslogtreecommitdiff
path: root/class.c
diff options
context:
space:
mode:
Diffstat (limited to 'class.c')
-rw-r--r--class.c26
1 files changed, 20 insertions, 6 deletions
diff --git a/class.c b/class.c
index 8ac53ee63b..6835d2d728 100644
--- a/class.c
+++ b/class.c
@@ -348,6 +348,8 @@ copy_tables(VALUE clone, VALUE orig)
}
}
+static void ensure_origin(VALUE klass);
+
/* :nodoc: */
VALUE
rb_mod_init_copy(VALUE clone, VALUE orig)
@@ -390,7 +392,7 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
int add_subclass;
VALUE clone_origin;
- rb_ensure_origin(clone);
+ ensure_origin(clone);
clone_origin = RCLASS_ORIGIN(clone);
while (p && p != orig_origin) {
@@ -999,8 +1001,6 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super)
struct rb_id_table *const klass_m_tbl = RCLASS_M_TBL(RCLASS_ORIGIN(klass));
VALUE original_klass = klass;
- rb_ensure_origin(module);
-
while (module) {
int superclass_seen = FALSE;
struct rb_id_table *tbl;
@@ -1112,8 +1112,8 @@ move_refined_method(ID key, VALUE value, void *data)
}
}
-void
-rb_ensure_origin(VALUE klass)
+static void
+ensure_origin(VALUE klass)
{
VALUE origin = RCLASS_ORIGIN(klass);
if (origin == klass) {
@@ -1132,9 +1132,10 @@ void
rb_prepend_module(VALUE klass, VALUE module)
{
int changed = 0;
+ bool klass_had_no_origin = RCLASS_ORIGIN(klass) == klass;
ensure_includable(klass, module);
- rb_ensure_origin(klass);
+ ensure_origin(klass);
changed = include_modules_at(klass, klass, module, FALSE);
if (changed < 0)
rb_raise(rb_eArgError, "cyclic prepend detected");
@@ -1143,7 +1144,20 @@ rb_prepend_module(VALUE klass, VALUE module)
}
if (RB_TYPE_P(klass, T_MODULE)) {
rb_subclass_entry_t *iclass = RCLASS_EXT(klass)->subclasses;
+ VALUE klass_origin = RCLASS_ORIGIN(klass);
+ struct rb_id_table *klass_m_tbl = RCLASS_M_TBL(klass);
+ struct rb_id_table *klass_origin_m_tbl = RCLASS_M_TBL(klass_origin);
while (iclass) {
+ if (klass_had_no_origin && klass_origin_m_tbl == RCLASS_M_TBL(iclass->klass)) {
+ // backfill an origin iclass to handle refinements and future prepends
+ rb_id_table_foreach(RCLASS_M_TBL(iclass->klass), clear_module_cache_i, (void *)iclass->klass);
+ RCLASS_M_TBL(iclass->klass) = klass_m_tbl;
+ VALUE origin = rb_include_class_new(klass_origin, RCLASS_SUPER(iclass->klass));
+ RCLASS_SET_SUPER(iclass->klass, origin);
+ RCLASS_SET_INCLUDER(origin, RCLASS_INCLUDER(iclass->klass));
+ RCLASS_SET_ORIGIN(iclass->klass, origin);
+ RICLASS_SET_ORIGIN_SHARED_MTBL(origin);
+ }
include_modules_at(iclass->klass, iclass->klass, module, FALSE);
iclass = iclass->next;
}