def analyse_ref_expr(self, e): result = None node = e.node if isinstance(node, Var): # Variable or constant reference. v = node if not v.typ: # Implicit dynamic type. result = Any() else: # Local or global variable. result = v.typ.typ elif isinstance(node, FuncDef): # Reference to a global function. f = node result = function_type(f) elif isinstance(node, OverloadedFuncDef): o = node result = o.typ.typ elif isinstance(node, TypeInfo): # Reference to a type object. result = self.type_object_type(node) else: # Unknown reference; use dynamic type implicitly to avoid # generating extra type errors. result = Any() return result
def visit_overloaded_func_def(self, defn): t = [] for f in defn.items: f.is_overload = True f.accept(self) t.append(function_type(f)) defn.typ = Annotation(Overloaded(t)) defn.typ.set_line(defn.line) if self.typ: self.typ.methods[defn.name()] = defn defn.info = self.typ
def make_overload_check(self, f, fixed_args, rest_args): a = [] i = 0 if rest_args: a.append(self.make_argument_count_check(f, len(fixed_args), rest_args)) for t in function_type(f).arg_types: if not isinstance(t, Any) and (t.repr or isinstance(t, Callable)): a.append(self.make_argument_check( self.argument_ref(i, fixed_args, rest_args), t)) i += 1 return ' and '.join(a)
def visit_func_expr(self, e): """Type check lambda expression.""" inferred_type = self.infer_lambda_type(e) self.chk.check_func_item(e, type_override=inferred_type) ret_type = self.chk.type_map[e.expr()] if inferred_type: return replace_callable_return_type(inferred_type, ret_type) elif e.typ: return replace_callable_return_type(e.typ.typ, ret_type) else: # Use default type for lambda. # TODO infer return type? return function_type(e)
def check_func_item(self, defn, type_override=None): # We may be checking a function definition or an anonymous function. In # the first case, set up another reference with the precise type. fdef = None if isinstance(defn, FuncDef): fdef = defn self.dynamic_funcs.append(defn.typ is None and not type_override) if fdef: self.errors.set_function(fdef.name()) typ = function_type(defn) if type_override: typ = type_override if isinstance(typ, Callable): self.check_func_def(defn, typ) else: raise RuntimeError('Not supported') if fdef: self.errors.set_function(None) self.dynamic_funcs.pop()
Typ analyse_ref_expr(self, RefExpr e): Typ result node = e.node if isinstance(node, Var): # Variable or constant reference. v = (Var)node if not v.typ: # Implicit dynamic type. result = Any() else: # Local or global variable. result = v.typ.typ elif isinstance(node, FuncDef): # Reference to a global function. f = (FuncDef)node result = function_type(f) elif isinstance(node, OverloadedFuncDef): o = (OverloadedFuncDef)node result = o.typ.typ elif isinstance(node, TypeInfo): # Reference to a type object. result = self.type_object_type((TypeInfo)node) else: # Unknown reference; use dynamic type implicitly to avoid # generating extra type errors. result = Any() return result Typ analyse_direct_member_access(self, str name, TypeInfo info, bool is_lvalue, Context context): """Analyse direct member access via a name expression
bool is_simple_override(FuncDef fdef, TypeInfo info): """Is function an override with the same type precision as the original? Compare to the original method in the superclass of info. """ # If this is not an override, this can't be a simple override either. # Generic inheritance is not currently supported, since we need to map # type variables between types; in the future this restriction can be # lifted. if info.base is None or info.base.type_vars != []: return False orig = info.base.get_method(fdef.name()) # Ignore the first argument (self) when determining type sameness. # TODO overloads newtype = (Callable)function_type(fdef) newtype = replace_self_type(newtype, Any()) origtype = (Callable)function_type(orig) origtype = replace_self_type(origtype, Any()) return is_same_type(newtype, origtype) str tvar_slot_name(int n, any is_alt=False): """Return the name of the member that holds the runtime value of the given type variable slot. """ if is_alt != BOUND_VAR: if n == 0: return '__tv' else: return '__tv{}'.format(n + 1)