summaryrefslogtreecommitdiff
path: root/class.c
diff options
context:
space:
mode:
Diffstat (limited to 'class.c')
-rw-r--r--class.c50
1 files changed, 39 insertions, 11 deletions
diff --git a/class.c b/class.c
index b4aeb59e25..308033d2cb 100644
--- a/class.c
+++ b/class.c
@@ -956,25 +956,48 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super)
return method_changed;
}
+typedef struct tuple {
+ struct RClass *klass;
+ struct RClass *origin;
+} tuple;
+
+static enum rb_id_table_iterator_result
+inject_refined_method(ID *key, VALUE *value, void *data, int _)
+{
+ const tuple *ptr = data;
+ const rb_method_entry_t *me = *(rb_method_entry_t **) value;
+ const rb_method_entry_t *orig_me = me->def->body.refined.orig_me;
+ rb_method_entry_t *new_me =
+ rb_method_entry_create(
+ me->called_id,
+ me->owner,
+ me->defined_class,
+ rb_method_definition_create(
+ me->def->type,
+ me->def->original_id,
+ &(rb_method_refined_t) {
+ .orig_me = NULL,
+ .owner = me->def->body.refined.owner, }));
+ METHOD_ENTRY_FLAGS_COPY(new_me, me);
+ rb_id_table_insert(RCLASS_M_TBL(ptr->klass), *key, (VALUE)new_me);
+ RB_OBJ_WRITTEN(ptr->klass, Qundef, new_me);
+ *value = (VALUE)rb_method_entry_clone(orig_me);
+ RB_OBJ_WRITTEN(ptr->origin, Qundef, orig_me);
+ return ID_TABLE_CONTINUE;
+}
+
static enum rb_id_table_iterator_result
move_refined_method(ID key, VALUE value, void *data)
{
+ const tuple *ptr = data;
rb_method_entry_t *me = (rb_method_entry_t *) value;
- VALUE klass = (VALUE)data;
- struct rb_id_table *tbl = RCLASS_M_TBL(klass);
if (me->def->type == VM_METHOD_TYPE_REFINED) {
if (me->def->body.refined.orig_me) {
- const rb_method_entry_t *orig_me = me->def->body.refined.orig_me, *new_me;
- RB_OBJ_WRITE(me, &me->def->body.refined.orig_me, NULL);
- new_me = rb_method_entry_clone(me);
- rb_id_table_insert(tbl, key, (VALUE)new_me);
- RB_OBJ_WRITTEN(klass, Qundef, new_me);
- rb_method_entry_copy(me, orig_me);
- return ID_TABLE_CONTINUE;
+ return ID_TABLE_REPLACE;
}
else {
- rb_id_table_insert(tbl, key, (VALUE)me);
+ rb_id_table_insert(RCLASS_M_TBL(ptr->klass), key, (VALUE)me);
return ID_TABLE_DELETE;
}
}
@@ -1000,7 +1023,12 @@ rb_prepend_module(VALUE klass, VALUE module)
RCLASS_SET_ORIGIN(klass, origin);
RCLASS_M_TBL(origin) = RCLASS_M_TBL(klass);
RCLASS_M_TBL_INIT(klass);
- rb_id_table_foreach(RCLASS_M_TBL(origin), move_refined_method, (void *)klass);
+ rb_id_table_foreach_with_replace_with_key(
+ RCLASS_M_TBL(origin),
+ move_refined_method,
+ inject_refined_method,
+ &(tuple) { RCLASS(klass), RCLASS(origin), },
+ true);
}
changed = include_modules_at(klass, klass, module, FALSE);
if (changed < 0)