def specialize_parent_vtable(cls: ClassIR, parent: ClassIR) -> VTableEntries: """Generate the part of a vtable corresponding to a parent class or trait""" updated = [] for entry in parent.vtable_entries: if isinstance(entry, VTableMethod): # Find the original method corresponding to this vtable entry. # (This may not be the method in the entry, if it was overridden.) orig_parent_method = entry.cls.get_method(entry.name) assert orig_parent_method method_cls = cls.get_method_and_class(entry.name) if method_cls: child_method, defining_cls = method_cls # TODO: emit a wrapper for __init__ that raises or something if (is_same_method_signature(orig_parent_method.sig, child_method.sig) or orig_parent_method.name == '__init__'): entry = VTableMethod(entry.cls, entry.name, child_method, entry.shadow_method) else: entry = VTableMethod(entry.cls, entry.name, defining_cls.glue_methods[(entry.cls, entry.name)], entry.shadow_method) else: # If it is an attribute from a trait, we need to find out # the real class it got mixed in at and point to that. if parent.is_trait: _, origin_cls = cls.attr_details(entry.name) entry = VTableAttr(origin_cls, entry.name, entry.is_setter) updated.append(entry) return updated
def specialize_parent_vtable(cls: ClassIR, parent: ClassIR) -> VTableEntries: """Generate the part of a vtable corresponding to a parent class or trait""" updated = [] for entry in parent.vtable_entries: # Find the original method corresponding to this vtable entry. # (This may not be the method in the entry, if it was overridden.) orig_parent_method = entry.cls.get_method(entry.name) assert orig_parent_method method_cls = cls.get_method_and_class(entry.name) if method_cls: child_method, defining_cls = method_cls # TODO: emit a wrapper for __init__ that raises or something if (is_same_method_signature(orig_parent_method.sig, child_method.sig) or orig_parent_method.name == '__init__'): entry = VTableMethod(entry.cls, entry.name, child_method, entry.shadow_method) else: entry = VTableMethod( entry.cls, entry.name, defining_cls.glue_methods[(entry.cls, entry.name)], entry.shadow_method) updated.append(entry) return updated
def handle_ext_method(builder: IRBuilder, cdef: ClassDef, fdef: FuncDef) -> None: # Perform the function of visit_method for methods inside extension classes. name = fdef.name class_ir = builder.mapper.type_to_ir[cdef.info] func_ir, func_reg = gen_func_item(builder, fdef, name, builder.mapper.fdef_to_sig(fdef), cdef) builder.functions.append(func_ir) if is_decorated(builder, fdef): # Obtain the the function name in order to construct the name of the helper function. _, _, name = fdef.fullname.rpartition('.') helper_name = decorator_helper_name(name) # Read the PyTypeObject representing the class, get the callable object # representing the non-decorated method typ = builder.load_native_type_object(cdef.fullname) orig_func = builder.py_get_attr(typ, helper_name, fdef.line) # Decorate the non-decorated method decorated_func = load_decorated_func(builder, fdef, orig_func) # Set the callable object representing the decorated method as an attribute of the # extension class. builder.primitive_op(py_setattr_op, [ typ, builder.load_static_unicode(name), decorated_func ], fdef.line) if fdef.is_property: # If there is a property setter, it will be processed after the getter, # We populate the optional setter field with none for now. assert name not in class_ir.properties class_ir.properties[name] = (func_ir, None) elif fdef in builder.prop_setters: # The respective property getter must have been processed already assert name in class_ir.properties getter_ir, _ = class_ir.properties[name] class_ir.properties[name] = (getter_ir, func_ir) class_ir.methods[func_ir.decl.name] = func_ir # If this overrides a parent class method with a different type, we need # to generate a glue method to mediate between them. for base in class_ir.mro[1:]: if (name in base.method_decls and name != '__init__' and not is_same_method_signature(class_ir.method_decls[name].sig, base.method_decls[name].sig)): # TODO: Support contravariant subtyping in the input argument for # property setters. Need to make a special glue method for handling this, # similar to gen_glue_property. f = gen_glue(builder, base.method_decls[name].sig, func_ir, class_ir, base, fdef) class_ir.glue_methods[(base, name)] = f builder.functions.append(f) # If the class allows interpreted children, create glue # methods that dispatch via the Python API. These will go in a # "shadow vtable" that will be assigned to interpreted # children. if class_ir.allow_interpreted_subclasses: f = gen_glue(builder, func_ir.sig, func_ir, class_ir, class_ir, fdef, do_py_ops=True) class_ir.glue_methods[(class_ir, name)] = f builder.functions.append(f)