Preview Ruby 4.1 is a preview. It can change before the final release. Switch to Ruby 4.0 →
instance method
Method#super_method
() -> ::Method?
meth.super_method → method
proc.c
View on GitHub ↗
static VALUE
method_super_method(VALUE method)
{
const struct METHOD *data;
VALUE super_class, iclass;
ID mid;
const rb_method_entry_t *me;
TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
iclass = data->iclass;
if (!iclass) return Qnil;
bool is_refinement_method = refinement_module_p(data->me->owner);
if (data->me->def->type == VM_METHOD_TYPE_ALIAS && data->me->defined_class) {
super_class = RCLASS_SUPER(rb_find_defined_class_by_owner(data->me->defined_class,
data->me->def->body.alias.original_me->owner));
mid = data->me->def->body.alias.original_me->def->original_id;
}
else if (is_refinement_method) {
if (RICLASS_FOR_REFINEMENT_P(iclass)) {
do {
super_class = RCLASS_SUPER(iclass);
iclass = super_class;
} while (RICLASS_FOR_REFINEMENT_P(super_class));
}
else {
super_class = find_refined_target_ancestor(iclass, rb_refinement_module_get_refined_class(data->me->owner));
if (!super_class) {
super_class = RCLASS_SUPER(data->me->owner);
}
}
mid = data->me->def->original_id;
}
else {
VALUE klass = iclass;
if (RICLASS_FOR_REFINEMENT_P(klass)) {
// Refined methods need this check before superclass determination
klass = RBASIC(klass)->klass;
}
super_class = RCLASS_SUPER(RCLASS_ORIGIN(klass));
mid = data->me->def->original_id;
}
if (!super_class) return Qnil;
// For refined methods, skip refinements for the same definition, but consider
// refinements for superclass methods
const rb_method_definition_t *skip_def = is_refinement_method ? data->me->def : NULL;
// Use the CREF of the Method/UnboundMethod, not the CREF of the caller of super_method.
// We must avoid the use of rb_callable_method_entry_with_refinements, as that will
// implicitly use the refinements activated in of the caller of super_method.
const rb_cref_t *cref = NULL;
switch (data->me->def->type) {
case VM_METHOD_TYPE_ISEQ:
cref = data->me->def->body.iseq.cref;
break;
case VM_METHOD_TYPE_BMETHOD: {
const rb_proc_t *proc;
GetProcPtr(data->me->def->body.bmethod.proc, proc);
const struct rb_block *block = &proc->block;
if (vm_block_type(block) == block_type_iseq)
cref = rb_vm_get_cref(block->as.captured.ep);
break;
}
default:
break;
}
VALUE klass = super_class;
me = NULL;
while (klass) {
const rb_callable_method_entry_t *cme = rb_callable_method_entry(klass, mid);
if (!cme) break;
if (cme->def->type != VM_METHOD_TYPE_REFINED) {
me = (rb_method_entry_t *)cme;
iclass = cme->defined_class;
break;
}
// Look through all CREF scopes for a refinement for cme->owner, mirroring
// the loop in search_refined_method.
const rb_cref_t *c;
for (c = cref; c; c = CREF_NEXT(c)) {
VALUE refs = CREF_REFINEMENTS(c);
if (NIL_P(refs)) continue;
VALUE r = rb_hash_lookup(refs, cme->owner);
if (NIL_P(r)) continue;
r = rb_vm_refinement_iclass_for_cme(r, cme);
const rb_callable_method_entry_t *ref_cme = rb_callable_method_entry(r, mid);
if (!ref_cme) break;
if (ref_cme->def->type == VM_METHOD_TYPE_REFINED) continue;
if (skip_def && rb_method_definition_eq(ref_cme->def, skip_def)) continue;
me = (rb_method_entry_t *)ref_cme;
iclass = ref_cme->defined_class;
break;
}
if (me) break;
// No refined method found. Use orig_me if available, or normal method lookup
// in superclass otherwise.
const rb_method_entry_t *orig_me = cme->def->body.refined.orig_me;
if (orig_me) {
me = (rb_method_entry_t *)orig_me;
iclass = cme->defined_class;
break;
}
klass = RCLASS_SUPER(cme->defined_class);
}
if (!me) return Qnil;
return mnew_internal(me, me->owner, iclass, data->recv, mid, rb_obj_class(method), FALSE, FALSE);
}
Returns a Method of superclass which would be called when super is used or nil if there is no method on superclass.
See also
#source_range
#syntax_tree
#source_location
#to_proc
also in
4.0 · 3.4 · 3.3 · 3.2 · 3.1 · 3.0