def transform_type_def(self, tdef: TypeDef) -> List[Node]: """Transform a type definition. The result may be one or two definitions. The first is the transformation of the original TypeDef. The second is a wrapper type, which is generated for generic types only. """ defs = [] # type: List[Node] if tdef.info.type_vars: # This is a generic type. Insert type variable slots in # the class definition for new type variables, i.e. type # variables not mapped to superclass type variables. defs.extend(self.make_tvar_representation(tdef.info)) # Iterate over definitions and transform each of them. vars = set() # type: Set[Var] for d in tdef.defs.body: if isinstance(d, FuncDef): # Implicit cast from FuncDef[] to Node[] is safe below. defs.extend(Any(self.func_tf.transform_method(d))) elif isinstance(d, VarDef): defs.extend(self.transform_var_def(d)) for n in d.items: vars.add(n) elif isinstance(d, AssignmentStmt): self.transform_assignment(d) defs.append(d) # Add accessors for implicitly defined attributes. for node in tdef.info.names.values(): if isinstance(node.node, Var): v = cast(Var, node.node) if v.info == tdef.info and v not in vars: defs.extend(self.make_accessors(v)) # For generic classes, add an implicit __init__ wrapper. defs.extend(self.make_init_wrapper(tdef)) if tdef.is_generic() or (tdef.info.bases and tdef.info.mro[1].is_generic()): self.make_instance_tvar_initializer( cast(FuncDef, tdef.info.get_method('__init__'))) if not defs: defs.append(PassStmt()) if tdef.is_generic(): gen_wrapper = self.generic_class_wrapper(tdef) tdef.defs = Block(defs) dyn_wrapper = self.make_type_object_wrapper(tdef) if not tdef.is_generic(): return [tdef, dyn_wrapper] else: return [tdef, dyn_wrapper, gen_wrapper]
def make_init_wrapper(self, tdef: TypeDef) -> List[Node]: """Make and return an implicit __init__ if class needs it. Otherwise, return an empty list. We include an implicit __init__ if the class is generic or if it extends a generic class and if it does not define __init__. The __init__ of a generic class requires one or more extra type variable arguments. The inherited __init__ may not accept these. For example, assume these definitions: . class A(Generic[T]): pass . class B(A[int]): pass The constructor for B will be (equivalent to) . def __init__(self: B) -> None: . self.__tv = <int> . super().__init__(<int>) """ # FIX overloading, default args / varargs, keyword args info = tdef.info if '__init__' not in info.names and ( tdef.is_generic() or (info.bases and info.mro[1].is_generic())): # Generic class with no explicit __init__ method # (i.e. __init__ inherited from superclass). Generate a # wrapper that initializes type variable slots and calls # the superclass __init__ method. base = info.mro[1] selftype = self_type(info) callee_type = cast(Callable, analyse_member_access( '__init__', selftype, None, False, True, None, None, base)) # Now the callee type may contain the type variables of a # grandparent as bound type variables, but we want the # type variables of the parent class. Explicitly set the # bound type variables. callee_type = self.fix_bound_init_tvars(callee_type, map_instance_to_supertype(selftype, base)) super_init = cast(FuncDef, base.get_method('__init__')) # Build argument list. args = [Var('self')] for i in range(1, len(super_init.args)): args.append(Var(super_init.args[i].name())) args[-1].type = callee_type.arg_types[i - 1] selft = self_type(self.tf.type_context()) callee_type = prepend_arg_type(callee_type, selft) creat = FuncDef('__init__', args, super_init.arg_kinds, [None] * len(args), Block([])) creat.info = tdef.info creat.type = callee_type creat.is_implicit = False tdef.info.names['__init__'] = SymbolTableNode(MDEF, creat, typ=creat.type) # Insert a call to superclass constructor. If the # superclass is object, the constructor does nothing => # omit the call. if base.fullname() != 'builtins.object': creat.body.body.append( self.make_superclass_constructor_call(tdef.info, callee_type)) # Implicit cast from FuncDef[] to Node[] is safe below. return Any(self.func_tf.transform_method(creat)) else: return []