def make_type_info(name: str, is_abstract: bool = False, mro: List[TypeInfo] = None, bases: List[Instance] = None, typevars: List[str] = None) -> TypeInfo: """Make a TypeInfo suitable for use in unit tests.""" type_def = TypeDef(name, Block([]), None, []) type_def.fullname = name if typevars: v = [] # type: List[TypeVarDef] id = 1 for n in typevars: v.append(TypeVarDef(n, id, None)) id += 1 type_def.type_vars = v info = TypeInfo(SymbolTable(), type_def) if mro is None: mro = [] info.mro = [info] + mro if bases is None: if mro: # By default, assume that there is a single non-generic base. bases = [Instance(mro[0], [])] else: bases = [] info.bases = bases return info
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 visit_type_def(self, node: TypeDef) -> Node: new = TypeDef(node.name, self.block(node.defs), node.type_vars, self.types(node.base_types), node.metaclass) new.fullname = node.fullname new.info = node.info return new
def generic_class_wrapper(self, tdef: TypeDef) -> TypeDef: """Construct a wrapper class for a generic type.""" # FIX semanal meta-info for nodes + TypeInfo defs = [] # type: List[Node] # Does the type have a superclass, other than builtins.object? base = tdef.info.mro[1] has_proper_superclass = base.fullname() != 'builtins.object' if not has_proper_superclass or self.tf.is_java: # Generate member variables for wrapper object. defs.extend(self.make_generic_wrapper_member_vars(tdef)) for alt in [False, BOUND_VAR]: defs.extend(self.make_tvar_representation(tdef.info, alt)) # Generate constructor. defs.append(self.make_generic_wrapper_init(tdef.info)) # Generate method wrappers. for d in tdef.defs.body: if isinstance(d, FuncDef): if not d.is_constructor(): defs.extend(self.func_tf.generic_method_wrappers(d)) elif isinstance(d, AssignmentStmt): defs.extend(self.generic_accessor_wrappers(d)) elif not isinstance(d, PassStmt): raise RuntimeError( 'Definition {} at line {} not supported'.format( type(d), d.line)) base_type = self.tf.named_type('builtins.object') # type: Type # Inherit superclass wrapper if there is one. if has_proper_superclass: base = self.find_generic_base_class(tdef.info) if base: # TODO bind the type somewhere base_type = UnboundType(base.defn.name + self.tf.wrapper_class_suffix()) # Build the type definition. wrapper = TypeDef(tdef.name + self.tf.wrapper_class_suffix(), Block(defs), None, [base_type]) # FIX fullname self.tf.add_line_mapping(tdef, wrapper) return 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 []
# class M1 implements GF<A> self.m1i = make_type_info('M1', (INTERFACES, [self.gfi]), (BASE_DEFS, [Instance(self.gfi, [self.a])])) self.gfa = Instance(self.gfi, [self.a]) # GF<A> self.gfb = Instance(self.gfi, [self.b]) # GF<B> self.m1 = Instance(self.m1i, []) # M1 TypeInfo make_type_info(any name, any *args): """Make a TypeInfo suitable for use in unit tests.""" map = dict(args) type_def = TypeDef(name, Block([]), None, []) type_def.fullname = name if VARS in map: TypeVarDef[] v = [] id = 1 for n in map[VARS]: v.append(TypeVarDef(n, id)) id += 1 type_def.type_vars = TypeVars(v) info = TypeInfo(SymbolTable(), type_def) info.base = map.get(BASE, None) info.bases = map.get(BASE_DEFS, []) info.interfaces = map.get(INTERFACES, []) # TODO fix