def add_field(var: Var, is_initialized_in_class: bool = False, is_property: bool = False) -> None: var.info = info var.is_initialized_in_class = is_initialized_in_class var.is_property = is_property var._fullname = '%s.%s' % (info.fullname(), var.name()) info.names[var.name()] = SymbolTableNode(MDEF, var)
def make_accessors(self, n: Var) -> List[Node]: if n.type: t = n.type else: t = AnyType() return [self.make_getter_wrapper(n.name(), t), self.make_setter_wrapper(n.name(), t), self.make_dynamic_getter_wrapper(n.name(), t), self.make_dynamic_setter_wrapper(n.name(), t)]
def _make_frozen(ctx: 'mypy.plugin.ClassDefContext', attributes: List[Attribute]) -> None: """Turn all the attributes into properties to simulate frozen classes.""" for attribute in attributes: if attribute.name in ctx.cls.info.names: # This variable belongs to this class so we can modify it. node = ctx.cls.info.names[attribute.name].node assert isinstance(node, Var) node.is_property = True else: # This variable belongs to a super class so create new Var so we # can modify it. var = Var(attribute.name, ctx.cls.info[attribute.name].type) var.info = ctx.cls.info var._fullname = '%s.%s' % (ctx.cls.info.fullname(), var.name()) ctx.cls.info.names[var.name()] = SymbolTableNode(MDEF, var) var.is_property = True
def analyze_var( name: str, var: Var, itype: Instance, info: TypeInfo, node: Context, is_lvalue: bool, msg: MessageBuilder, not_ready_callback: Callable[[str, Context], None], ) -> Type: """Analyze access to an attribute via a Var node. This is conceptually part of analyze_member_access and the arguments are similar. """ # Found a member variable. itype = map_instance_to_supertype(itype, var.info) typ = var.type if typ: if isinstance(typ, PartialType): return handle_partial_attribute_type(typ, is_lvalue, msg, var) t = expand_type_by_instance(typ, itype) if is_lvalue and var.is_property and not var.is_settable_property: # TODO allow setting attributes in subclass (although it is probably an error) msg.read_only_property(name, info, node) if var.is_initialized_in_class and isinstance(t, FunctionLike): if is_lvalue: if var.is_property: if not var.is_settable_property: msg.read_only_property(name, info, node) else: msg.cant_assign_to_method(node) if not var.is_staticmethod: # Class-level function objects and classmethods become bound # methods: the former to the instance, the latter to the # class. functype = t check_method_type(functype, itype, var.is_classmethod, node, msg) signature = method_type(functype) if var.is_property: # A property cannot have an overloaded type => the cast # is fine. return cast(CallableType, signature).ret_type else: return signature return t else: if not var.is_ready: not_ready_callback(var.name(), node) # Implicit 'Any' type. return AnyType()
def analyse_lvalue(self, lval, nested=False, add_defs=False): if isinstance(lval, NameExpr): n = lval nested_global = not self.locals and self.block_depth > 0 and not self.type if (add_defs or nested_global) and n.name not in self.globals: # Define new global name. v = Var(n.name) v._full_name = self.qualified_name(n.name) v.is_ready = False # Type not inferred yet n.node = v n.is_def = True n.kind = GDEF n.full_name = v._full_name self.globals[n.name] = SymbolTableNode(GDEF, v, self.cur_mod_id) elif isinstance(n.node, Var) and n.is_def: v = n.node self.module_names[v.name()] = SymbolTableNode(GDEF, v, self.cur_mod_id) elif self.locals and n.name not in self.locals[-1] and n.name not in self.global_decls[-1]: # Define new local name. v = Var(n.name) n.node = v n.is_def = True n.kind = LDEF self.add_local(v, n) elif not self.locals and (self.type and n.name not in self.type.vars): # Define a new attribute. v = Var(n.name) v.info = self.type v.is_initialized_in_class = True n.node = v n.is_def = True self.type.vars[n.name] = v else: # Bind to an existing name. lval.accept(self) elif isinstance(lval, MemberExpr): if not add_defs: self.analyse_member_lvalue(lval) elif isinstance(lval, IndexExpr): if not add_defs: lval.accept(self) elif isinstance(lval, ParenExpr): self.analyse_lvalue((lval).expr, nested, add_defs) elif (isinstance(lval, TupleExpr) or isinstance(lval, ListExpr)) and not nested: items = (lval).items for i in items: self.analyse_lvalue(i, True, add_defs) else: self.fail("Invalid assignment target", lval)
def visit_var(self, node: Var) -> Var: # Note that a Var must be transformed to a Var. if node in self.var_map: return self.var_map[node] new = Var(node.name(), self.optional_type(node.type)) new.line = node.line new._fullname = node._fullname new.info = node.info new.is_self = node.is_self new.is_ready = node.is_ready new.is_initialized_in_class = node.is_initialized_in_class new.is_staticmethod = node.is_staticmethod new.is_property = node.is_property new.set_line(node.line) self.var_map[node] = new return new
def analyze_var( name: str, var: Var, itype: Instance, info: TypeInfo, node: Context, is_lvalue: bool, msg: MessageBuilder ) -> Type: """Analyze access to an attribute via a Var node. This is conceptually part of analyze_member_access and the arguments are similar. """ # Found a member variable. itype = map_instance_to_supertype(itype, var.info) if var.type: t = expand_type_by_instance(var.type, itype) if var.is_initialized_in_class and isinstance(t, FunctionLike): if is_lvalue: if var.is_property: if not var.is_settable_property: msg.read_only_property(name, info, node) else: msg.cant_assign_to_method(node) if not var.is_staticmethod: # Class-level function objects and classmethods become bound # methods: the former to the instance, the latter to the # class. functype = cast(FunctionLike, t) check_method_type(functype, itype, node, msg) signature = method_type(functype) if var.is_property: # A property cannot have an overloaded type => the cast # is fine. return cast(CallableType, signature).ret_type else: return signature return t else: if not var.is_ready: msg.cannot_determine_type(var.name(), node) # Implicit 'Any' type. return AnyType()
def analyze_var(name: str, var: Var, itype: Instance, info: TypeInfo, mx: MemberContext, *, implicit: bool = False) -> Type: """Analyze access to an attribute via a Var node. This is conceptually part of analyze_member_access and the arguments are similar. itype is the class object in which var is defined original_type is the type of E in the expression E.var if implicit is True, the original Var was created as an assignment to self """ # Found a member variable. itype = map_instance_to_supertype(itype, var.info) typ = var.type if typ: if isinstance(typ, PartialType): return mx.chk.handle_partial_var_type(typ, mx.is_lvalue, var, mx.context) t = expand_type_by_instance(typ, itype) if mx.is_lvalue and var.is_property and not var.is_settable_property: # TODO allow setting attributes in subclass (although it is probably an error) mx.msg.read_only_property(name, itype.type, mx.context) if mx.is_lvalue and var.is_classvar: mx.msg.cant_assign_to_classvar(name, mx.context) result = t if var.is_initialized_in_class and isinstance(t, FunctionLike) and not t.is_type_obj(): if mx.is_lvalue: if var.is_property: if not var.is_settable_property: mx.msg.read_only_property(name, itype.type, mx.context) else: mx.msg.cant_assign_to_method(mx.context) if not var.is_staticmethod: # Class-level function objects and classmethods become bound methods: # the former to the instance, the latter to the class. functype = t # Use meet to narrow original_type to the dispatched type. # For example, assume # * A.f: Callable[[A1], None] where A1 <: A (maybe A1 == A) # * B.f: Callable[[B1], None] where B1 <: B (maybe B1 == B) # * x: Union[A1, B1] # In `x.f`, when checking `x` against A1 we assume x is compatible with A # and similarly for B1 when checking agains B dispatched_type = meet.meet_types(mx.original_type, itype) check_self_arg(functype, dispatched_type, var.is_classmethod, mx.context, name, mx.msg) signature = bind_self(functype, mx.original_type, var.is_classmethod) if var.is_property: # A property cannot have an overloaded type => the cast is fine. assert isinstance(signature, CallableType) result = signature.ret_type else: result = signature else: if not var.is_ready: mx.not_ready_callback(var.name(), mx.context) # Implicit 'Any' type. result = AnyType(TypeOfAny.special_form) fullname = '{}.{}'.format(var.info.fullname(), name) hook = mx.chk.plugin.get_attribute_hook(fullname) if result and not mx.is_lvalue and not implicit: result = analyze_descriptor_access(mx.original_type, result, mx.builtin_type, mx.msg, mx.context, chk=mx.chk) if hook: result = hook(AttributeContext(mx.original_type, result, mx.context, mx.chk)) return result
def make_init_arg(var: Var) -> Argument: default = default_items.get(var.name(), None) kind = ARG_POS if default is None else ARG_OPT return Argument(var, var.type, default, kind)
def analyze_var(name: str, var: Var, itype: Instance, info: TypeInfo, mx: MemberContext, *, implicit: bool = False) -> Type: """Analyze access to an attribute via a Var node. This is conceptually part of analyze_member_access and the arguments are similar. itype is the class object in which var is defined original_type is the type of E in the expression E.var if implicit is True, the original Var was created as an assignment to self """ # Found a member variable. itype = map_instance_to_supertype(itype, var.info) typ = var.type if typ: if isinstance(typ, PartialType): return mx.chk.handle_partial_var_type(typ, mx.is_lvalue, var, mx.context) t = expand_type_by_instance(typ, itype) if mx.is_lvalue and var.is_property and not var.is_settable_property: # TODO allow setting attributes in subclass (although it is probably an error) mx.msg.read_only_property(name, itype.type, mx.context) if mx.is_lvalue and var.is_classvar: mx.msg.cant_assign_to_classvar(name, mx.context) result = t if var.is_initialized_in_class and isinstance( t, FunctionLike) and not t.is_type_obj(): if mx.is_lvalue: if var.is_property: if not var.is_settable_property: mx.msg.read_only_property(name, itype.type, mx.context) else: mx.msg.cant_assign_to_method(mx.context) if not var.is_staticmethod: # Class-level function objects and classmethods become bound methods: # the former to the instance, the latter to the class. functype = t # Use meet to narrow original_type to the dispatched type. # For example, assume # * A.f: Callable[[A1], None] where A1 <: A (maybe A1 == A) # * B.f: Callable[[B1], None] where B1 <: B (maybe B1 == B) # * x: Union[A1, B1] # In `x.f`, when checking `x` against A1 we assume x is compatible with A # and similarly for B1 when checking agains B dispatched_type = meet.meet_types(mx.original_type, itype) check_self_arg(functype, dispatched_type, var.is_classmethod, mx.context, name, mx.msg) signature = bind_self(functype, mx.self_type, var.is_classmethod) if var.is_property: # A property cannot have an overloaded type => the cast is fine. assert isinstance(signature, CallableType) result = signature.ret_type else: result = signature else: if not var.is_ready: mx.not_ready_callback(var.name(), mx.context) # Implicit 'Any' type. result = AnyType(TypeOfAny.special_form) fullname = '{}.{}'.format(var.info.fullname(), name) hook = mx.chk.plugin.get_attribute_hook(fullname) if result and not mx.is_lvalue and not implicit: result = analyze_descriptor_access(mx.original_type, result, mx.builtin_type, mx.msg, mx.context, chk=mx.chk) if hook: result = hook( AttributeContext(mx.original_type, result, mx.context, mx.chk)) return result