diff options
-rw-r--r-- | object.c | 38 |
1 files changed, 29 insertions, 9 deletions
@@ -817,18 +817,38 @@ rb_obj_is_kind_of(VALUE obj, VALUE c) // class without checking type and can return immediately. if (cl == c) return Qtrue; - // Fast path: Both are T_CLASS - if (LIKELY(RB_TYPE_P(c, T_CLASS))) { - return class_search_class_ancestor(cl, c); - } - // Note: YJIT needs this function to never allocate and never raise when // `c` is a class or a module. - c = class_or_module_required(c); - c = RCLASS_ORIGIN(c); - // Slow path: check each ancestor in the linked list and its method table - return RBOOL(class_search_ancestor(cl, c)); + if (LIKELY(RB_TYPE_P(c, T_CLASS))) { + // Fast path: Both are T_CLASS + return class_search_class_ancestor(cl, c); + } + else if (RB_TYPE_P(c, T_ICLASS)) { + // First check if we inherit the includer + // If we do we can return true immediately + VALUE includer = RCLASS_INCLUDER(c); + if (cl == includer) return Qtrue; + + // Usually includer is a T_CLASS here, except when including into an + // already included Module. + // If it is a class, attempt the fast class-to-class check and return + // true if there is a match. + if (RB_TYPE_P(includer, T_CLASS) && class_search_class_ancestor(cl, includer)) + return Qtrue; + + // We don't include the ICLASS directly, so must check if we inherit + // the module via another include + return RBOOL(class_search_ancestor(cl, RCLASS_ORIGIN(c))); + } + else if (RB_TYPE_P(c, T_MODULE)) { + // Slow path: check each ancestor in the linked list and its method table + return RBOOL(class_search_ancestor(cl, RCLASS_ORIGIN(c))); + } + else { + rb_raise(rb_eTypeError, "class or module required"); + UNREACHABLE_RETURN(Qfalse); + } } |