Exemple #1
0
        def add_method(funcname: str,
                       ret: Type,
                       args: List[Argument],
                       name: Optional[str] = None,
                       is_classmethod: bool = False,
                       is_new: bool = False,
                       ) -> None:
            if is_classmethod or is_new:
                first = [Argument(Var('cls'), TypeType.make_normalized(selftype), None, ARG_POS)]
            else:
                first = [Argument(Var('self'), selftype, None, ARG_POS)]
            args = first + args

            types = [arg.type_annotation for arg in args]
            items = [arg.variable.name() for arg in args]
            arg_kinds = [arg.kind for arg in args]
            assert None not in types
            signature = CallableType(cast(List[Type], types), arg_kinds, items, ret,
                                     function_type)
            signature.variables = [tvd]
            func = FuncDef(funcname, args, Block([]))
            func.info = info
            func.is_class = is_classmethod
            func.type = set_callable_name(signature, func)
            func._fullname = info.fullname() + '.' + funcname
            if is_classmethod:
                v = Var(funcname, func.type)
                v.is_classmethod = True
                v.info = info
                v._fullname = func._fullname
                dec = Decorator(func, [NameExpr('classmethod')], v)
                info.names[funcname] = SymbolTableNode(MDEF, dec)
            else:
                info.names[funcname] = SymbolTableNode(MDEF, func)
Exemple #2
0
def add_method(
        ctx: ClassDefContext,
        name: str,
        args: List[Argument],
        return_type: Type,
        self_type: Optional[Type] = None,
        tvar_def: Optional[TypeVarDef] = None,
) -> None:
    """Adds a new method to a class.
    """
    info = ctx.cls.info
    self_type = self_type or fill_typevars(info)
    function_type = ctx.api.named_type('__builtins__.function')

    args = [Argument(Var('self'), self_type, None, ARG_POS)] + args
    arg_types, arg_names, arg_kinds = [], [], []
    for arg in args:
        assert arg.type_annotation, 'All arguments must be fully typed.'
        arg_types.append(arg.type_annotation)
        arg_names.append(arg.variable.name())
        arg_kinds.append(arg.kind)

    signature = CallableType(arg_types, arg_kinds, arg_names, return_type, function_type)
    if tvar_def:
        signature.variables = [tvar_def]

    func = FuncDef(name, args, Block([PassStmt()]))
    func.info = info
    func.type = set_callable_name(signature, func)
    func._fullname = info.fullname() + '.' + name
    func.line = info.line

    info.names[name] = SymbolTableNode(MDEF, func, plugin_generated=True)
    info.defn.defs.body.append(func)
Exemple #3
0
    def add_method(self,
                   method_name: str, args: List[Argument], ret_type: Type,
                   self_type: Optional[Type] = None,
                   tvd: Optional[TypeVarDef] = None) -> None:
        """Add a method: def <method_name>(self, <args>) -> <ret_type>): ... to info.

        self_type: The type to use for the self argument or None to use the inferred self type.
        tvd: If the method is generic these should be the type variables.
        """
        from mypy.semanal import set_callable_name
        self_type = self_type if self_type is not None else self.self_type
        args = [Argument(Var('self'), self_type, None, ARG_POS)] + args
        arg_types = [arg.type_annotation for arg in args]
        arg_names = [arg.variable.name() for arg in args]
        arg_kinds = [arg.kind for arg in args]
        assert None not in arg_types
        signature = CallableType(cast(List[Type], arg_types), arg_kinds, arg_names,
                                 ret_type, self.function_type)
        if tvd:
            signature.variables = [tvd]
        func = FuncDef(method_name, args, Block([PassStmt()]))
        func.info = self.info
        func.type = set_callable_name(signature, func)
        func._fullname = self.info.fullname() + '.' + method_name
        func.line = self.info.line
        self.info.names[method_name] = SymbolTableNode(MDEF, func)
        # Add the created methods to the body so that they can get further semantic analysis.
        # e.g. Forward Reference Resolution.
        self.info.defn.defs.body.append(func)
Exemple #4
0
    def make_setter_wrapper(self, name, typ):
        """Create a setter wrapper for a data attribute.

        The setter will be of this form:
        
        . void set$name(C self, typ name):
        .     self.name! = name
        """
        scope = self.make_scope()
        selft = self.self_type()
        selfv = scope.add('self', selft)
        namev = scope.add(name, typ)
        
        lvalue = MemberExpr(scope.name_expr('self'), name, direct=True)
        rvalue = scope.name_expr(name)
        ret = AssignmentStmt([lvalue], rvalue)

        wrapper_name = 'set$' + name
        sig = Callable([selft, typ],
                       [nodes.ARG_POS, nodes.ARG_POS],
                       [None, None],
                       Void(), False)
        fdef = FuncDef(wrapper_name,
                       [selfv, namev],
                       [nodes.ARG_POS, nodes.ARG_POS],
                       [None, None],
                       Block([ret]), sig)
        fdef.info = self.tf.type_context()
        return fdef
Exemple #5
0
 def visit_func_def(self, node: FuncDef) -> None:
     if not self.recurse_into_functions:
         return
     node.expanded = []
     node.type = node.unanalyzed_type
     with self.enter_method(node.info) if node.info else nothing():
         super().visit_func_def(node)
Exemple #6
0
 def visit_func_def(self, o: FuncDef) -> None:
     if self.is_private_name(o.name()):
         return
     if self.is_not_in_all(o.name()):
         return
     if self.is_recorded_name(o.name()):
         return
     if not self._indent and self._state not in (EMPTY, FUNC):
         self.add('\n')
     if not self.is_top_level():
         self_inits = find_self_initializers(o)
         for init in self_inits:
             init_code = self.get_init(init)
             if init_code:
                 self.add(init_code)
     self.add("%sdef %s(" % (self._indent, o.name()))
     self.record_name(o.name())
     args = []  # type: List[str]
     for i, arg_ in enumerate(o.arguments):
         var = arg_.variable
         kind = arg_.kind
         name = var.name()
         init_stmt = arg_.initialization_statement
         if init_stmt:
             if kind == ARG_NAMED and '*' not in args:
                 args.append('*')
             arg = '%s=' % name
             rvalue = init_stmt.rvalue
             if isinstance(rvalue, IntExpr):
                 arg += str(rvalue.value)
             elif isinstance(rvalue, StrExpr):
                 arg += "''"
             elif isinstance(rvalue, BytesExpr):
                 arg += "b''"
             elif isinstance(rvalue, FloatExpr):
                 arg += "0.0"
             elif isinstance(rvalue, UnaryExpr) and isinstance(rvalue.expr, IntExpr):
                 arg += '-%s' % rvalue.expr.value
             elif isinstance(rvalue, NameExpr) and rvalue.name in ('None', 'True', 'False'):
                 arg += rvalue.name
             else:
                 arg += '...'
         elif kind == ARG_STAR:
             arg = '*%s' % name
         elif kind == ARG_STAR2:
             arg = '**%s' % name
         else:
             arg = name
         args.append(arg)
     self.add(', '.join(args))
     self.add("): ...\n")
     self._state = FUNC
Exemple #7
0
 def visit_func_def(self, node: FuncDef) -> None:
     if not self.recurse_into_functions:
         return
     node.expanded = []
     node.type = node.unanalyzed_type
     # Type variable binder binds tvars before the type is analyzed.
     # It should be refactored, before that we just undo this change here.
     # TODO: this will be not necessary when #4814 is fixed.
     if node.type:
         assert isinstance(node.type, CallableType)
         node.type.variables = []
     with self.enter_method(node.info) if node.info else nothing():
         super().visit_func_def(node)
Exemple #8
0
 def visit_func_def(self, func: FuncDef) -> None:
     sem = self.sem
     if sem.type is not None:
         # Don't process methods during pass 1.
         return
     func.is_conditional = sem.block_depth[-1] > 0
     func._fullname = sem.qualified_name(func.name())
     at_module = sem.is_module_scope()
     if at_module and func.name() in sem.globals:
         # Already defined in this module.
         original_sym = sem.globals[func.name()]
         if original_sym.kind == UNBOUND_IMPORTED:
             # Ah this is an imported name. We can't resolve them now, so we'll postpone
             # this until the main phase of semantic analysis.
             return
         if not sem.set_original_def(original_sym.node, func):
             # Report error.
             sem.check_no_global(func.name(), func)
     else:
         if at_module:
             sem.globals[func.name()] = SymbolTableNode(GDEF, func)
         # Also analyze the function body (needed in case there are unreachable
         # conditional imports).
         sem.function_stack.append(func)
         sem.errors.push_function(func.name())
         sem.enter()
         func.body.accept(self)
         sem.leave()
         sem.errors.pop_function()
         sem.function_stack.pop()
Exemple #9
0
 def visit_func_def(self, node: FuncDef) -> None:
     if not self.recurse_into_functions:
         return
     node.expanded = []
     node.type = node.unanalyzed_type
     if node.type:
         # Type variable binder binds type variables before the type is analyzed,
         # this causes unanalyzed_type to be modified in place. We needed to revert this
         # in order to get the state exactly as it was before semantic analysis.
         # See also #4814.
         assert isinstance(node.type, CallableType)
         node.type.variables = []
     with self.enter_method(node.info) if node.info else nothing():
         super().visit_func_def(node)
Exemple #10
0
def set_callable_name(sig: Type, fdef: FuncDef) -> Type:
    if isinstance(sig, FunctionLike):
        if fdef.info:
            if fdef.info.fullname() in TPDICT_FB_NAMES:
                # Avoid exposing the internal _TypedDict name.
                class_name = 'TypedDict'
            else:
                class_name = fdef.info.name()
            return sig.with_name(
                '{} of {}'.format(fdef.name(), class_name))
        else:
            return sig.with_name(fdef.name())
    else:
        return sig
Exemple #11
0
    def make_generic_wrapper_init(self, info: TypeInfo) -> FuncDef:
        """Build constructor of a generic wrapper class."""
        nslots = num_slots(info)
        
        cdefs = [] # type: List[Node]
        
        # Build superclass constructor call.
        base = info.mro[1]
        if base.fullname() != 'builtins.object' and self.tf.is_java:
            s = SuperExpr('__init__')
            cargs = [NameExpr('__o')] # type: List[Node]
            for n in range(num_slots(base)):
                cargs.append(NameExpr(tvar_arg_name(n + 1)))
            for n in range(num_slots(base)):
                cargs.append(NameExpr(tvar_arg_name(n + 1, BOUND_VAR)))
            c = CallExpr(s, cargs, [nodes.ARG_POS] * len(cargs))
            cdefs.append(ExpressionStmt(c))
        
        # Create initialization of the wrapped object.
        cdefs.append(AssignmentStmt([MemberExpr(
                                         self_expr(),
                                         self.object_member_name(info),
                                         direct=True)],
                                    NameExpr('__o')))
        
        # Build constructor arguments.
        args = [Var('self'), Var('__o')]
        init = [None, None] # type: List[Node]
        
        for alt in [False, BOUND_VAR]:
            for n in range(nslots):
                args.append(Var(tvar_arg_name(n + 1, alt)))
                init.append(None)

        nargs = nslots * 2 + 2
        fdef = FuncDef('__init__',
                       args,
                       [nodes.ARG_POS] * nargs,
                       init,
                       Block(cdefs),
                       Callable( [AnyType()] * nargs,
                                [nodes.ARG_POS] * nargs, [None] * nargs,
                                Void(),
                                is_type_obj=False))
        fdef.info = info
        
        self.make_wrapper_slot_initializer(fdef)
        
        return fdef
Exemple #12
0
    def visit_func_def(self, defn: FuncDef) -> None:
        start_line = defn.get_line() - 1
        start_indent = self.indentation_level(start_line)
        cur_line = start_line + 1
        end_line = cur_line
        # After this loop, function body will be lines [start_line, end_line)
        while cur_line < len(self.source):
            cur_indent = self.indentation_level(cur_line)
            if cur_indent is None:
                # Consume the line, but don't mark it as belonging to the function yet.
                cur_line += 1
            elif cur_indent > start_indent:
                # A non-blank line that belongs to the function.
                cur_line += 1
                end_line = cur_line
            else:
                # We reached a line outside the function definition.
                break

        is_typed = defn.type is not None
        for line in range(start_line, end_line):
            old_indent, _ = self.lines_covered[line]
            assert start_indent > old_indent
            self.lines_covered[line] = (start_indent, is_typed)

        # Visit the body, in case there are nested functions
        super().visit_func_def(defn)
Exemple #13
0
 def enter_function_scope(self, fdef: FuncDef) -> str:
     """Enter a function target scope."""
     target = '%s.%s' % (self.full_target_stack[-1], fdef.name())
     self.target_stack.append(target)
     self.full_target_stack.append(target)
     self.scope_stack.append(fdef)
     return target
Exemple #14
0
 def visit_func_def(self, fdef: FuncDef) -> None:
     if not self.recurse_into_functions:
         return
     self.errors.push_function(fdef.name())
     self.analyze(fdef.type, fdef)
     super().visit_func_def(fdef)
     self.errors.pop_function()
Exemple #15
0
    def try_type(self, func: FuncDef, typ: Type) -> List[str]:
        """Recheck a function while assuming it has type typ.

        Return all error messages.
        """
        old = func.unanalyzed_type
        # During reprocessing, unanalyzed_type gets copied to type (by aststrip).
        # We don't modify type because it isn't necessary and it
        # would mess up the snapshotting.
        func.unanalyzed_type = typ
        try:
            res = self.fgmanager.trigger(func.fullname())
            # if res:
            #     print('\n'.join(res))
            return res
        finally:
            func.unanalyzed_type = old
Exemple #16
0
 def visit_func_def(self, func: FuncDef) -> None:
     if self.current_info is not None:
         func.info = self.current_info
     if func.type is not None:
         func.type.accept(self.type_fixer)
     for arg in func.arguments:
         if arg.type_annotation is not None:
             arg.type_annotation.accept(self.type_fixer)
Exemple #17
0
 def transform_method_implementation(self, fdef, name):
     """Transform the implementation of a method (i.e. unwrapped)."""
     args = fdef.args
     arg_kinds = fdef.arg_kinds
     
     typ = function_type(fdef)
     init = fdef.init_expressions()
     
     if fdef.name() == '__init__' and is_generic(fdef):
         args, arg_kinds, init, typ = self.add_constructor_tvar_args(
             fdef, typ, args, arg_kinds, init)
     
     fdef2 = FuncDef(name, args, arg_kinds, init, fdef.body, typ)
     fdef2.info = fdef.info
     
     self.tf.prepend_generic_function_tvar_args(fdef2)
     
     return fdef2
Exemple #18
0
    def visit_func_def(self, node: FuncDef) -> FuncDef:
        # Note that a FuncDef must be transformed to a FuncDef.
        new = FuncDef(node.name(),
                      [self.copy_argument(arg) for arg in node.arguments],
                      self.block(node.body),
                      cast(FunctionLike, self.optional_type(node.type)))

        self.copy_function_attributes(new, node)

        new._fullname = node._fullname
        new.is_decorated = node.is_decorated
        new.is_conditional = node.is_conditional
        new.is_abstract = node.is_abstract
        new.is_static = node.is_static
        new.is_class = node.is_class
        new.is_property = node.is_property
        new.original_def = node.original_def
        return new
Exemple #19
0
    def transform_method(self, fdef: FuncDef) -> List[FuncDef]:
        """Transform a method.

        The result is one or more methods.
        """
        # Transform the body of the method.
        self.tf.transform_function_body(fdef)
        
        res = Undefined # type: List[FuncDef]
        
        if fdef.is_constructor():
            # The method is a constructor. Constructors are transformed to one
            # method.
            res = [self.transform_method_implementation(fdef, fdef.name())]
        else:
            # Normal methods are transformed to 1-3 variants. The
            # first is the main implementation of the method, and the
            # second is the dynamically-typed wrapper. The third
            # variant is for method overrides, and represents the
            # overridden supertype method.
            
            res = [self.transform_method_implementation(
                fdef, fdef.name() + self.tf.type_suffix(fdef))]
            
            if fdef.info.bases and fdef.info.mro[1].has_method(fdef.name()):
                # Override.
                # TODO do not assume single inheritance
                
                # Is is an override with a different signature? For
                # trivial overrides we can inherit wrappers.
                if not is_simple_override(fdef, fdef.info):
                    # Create a wrapper for overridden superclass method.
                    res.append(self.override_method_wrapper(fdef))
                    # Create a dynamically-typed method wrapper.
                    res.append(self.dynamic_method_wrapper(fdef))
            else:
                # Not an override.
                
                # Create a dynamically-typed method wrapper.
                res.append(self.dynamic_method_wrapper(fdef))
        
        return res
Exemple #20
0
    def build_newtype_typeinfo(self, name: str, old_type: Type, base_type: Instance) -> TypeInfo:
        info = self.api.basic_new_typeinfo(name, base_type)
        info.is_newtype = True

        # Add __init__ method
        args = [Argument(Var('self'), NoneTyp(), None, ARG_POS),
                self.make_argument('item', old_type)]
        signature = CallableType(
            arg_types=[Instance(info, []), old_type],
            arg_kinds=[arg.kind for arg in args],
            arg_names=['self', 'item'],
            ret_type=NoneTyp(),
            fallback=self.api.named_type('__builtins__.function'),
            name=name)
        init_func = FuncDef('__init__', args, Block([]), typ=signature)
        init_func.info = info
        init_func._fullname = self.api.qualified_name(name) + '.__init__'
        info.names['__init__'] = SymbolTableNode(MDEF, init_func)

        return info
Exemple #21
0
    def visit_func_def(self, node: FuncDef) -> FuncDef:
        # Note that a FuncDef must be transformed to a FuncDef.
        new = FuncDef(node.name(),
                      [self.visit_var(var) for var in node.args],
                      node.arg_kinds[:],
                      [None] * len(node.init),
                      self.block(node.body),
                      self.optional_type(node.type))

        self.copy_function_attributes(new, node)

        new._fullname = node._fullname
        new.is_decorated = node.is_decorated
        new.is_conditional = node.is_conditional
        new.is_abstract = node.is_abstract
        new.is_static = node.is_static
        new.is_class = node.is_class
        new.is_property = node.is_property
        new.original_def = node.original_def
        return new
Exemple #22
0
    def visit_func_def(self, node: FuncDef) -> FuncDef:
        # Note that a FuncDef must be transformed to a FuncDef.

        # These contortions are needed to handle the case of recursive
        # references inside the function being transformed.
        # Set up placholder nodes for references within this function
        # to other functions defined inside it.
        # Don't create an entry for this function itself though,
        # since we want self-references to point to the original
        # function if this is the top-level node we are transforming.
        init = FuncMapInitializer(self)
        for stmt in node.body.body:
            stmt.accept(init)

        new = FuncDef(node.name(),
                      [self.copy_argument(arg) for arg in node.arguments],
                      self.block(node.body),
                      cast(FunctionLike, self.optional_type(node.type)))

        self.copy_function_attributes(new, node)

        new._fullname = node._fullname
        new.is_decorated = node.is_decorated
        new.is_conditional = node.is_conditional
        new.is_abstract = node.is_abstract
        new.is_static = node.is_static
        new.is_class = node.is_class
        new.is_property = node.is_property
        new.original_def = node.original_def

        if node in self.func_placeholder_map:
            # There is a placeholder definition for this function. Replace
            # the attributes of the placeholder with those form the transformed
            # function. We know that the classes will be identical (otherwise
            # this wouldn't work).
            result = self.func_placeholder_map[node]
            result.__dict__ = new.__dict__
            return result
        else:
            return new
Exemple #23
0
    def call_wrapper(self, fdef: FuncDef, is_dynamic: bool,
                     is_wrapper_class: bool, target_ann: Callable,
                     cur_ann: Callable, target_suffix: str,
                     bound_sig: Callable) -> Node:
        """Return the body of wrapper method.

        The body contains only a call to the wrapped method and a
        return statement (if the call returns a value). Arguments are coerced
        to the target signature.
        """        
        args = self.call_args(fdef.args, target_ann, cur_ann, is_dynamic,
                              is_wrapper_class, bound_sig,
                              ismethod=fdef.is_method())
        selfarg = args[0]
        args = args[1:]
        
        member = fdef.name() + target_suffix
        if not is_wrapper_class:
            callee = MemberExpr(selfarg, member)
        else:
            callee = MemberExpr(
                MemberExpr(self_expr(), self.tf.object_member_name()), member)
        
        call = CallExpr(callee,
                        args,
                        [nodes.ARG_POS] * len(args),
                        [None] * len(args)) # type: Node
        if bound_sig:
            call = self.tf.coerce(call, bound_sig.ret_type,
                                  target_ann.ret_type, self.tf.type_context(),
                                  is_wrapper_class)
            call = self.tf.coerce(call, cur_ann.ret_type, bound_sig.ret_type,
                                  self.tf.type_context(), is_wrapper_class)
        else:
            call = self.tf.coerce(call, cur_ann.ret_type, target_ann.ret_type,
                                  self.tf.type_context(), is_wrapper_class)
        if not isinstance(target_ann.ret_type, Void):
            return ReturnStmt(call)
        else:
            return ExpressionStmt(call)
Exemple #24
0
    def get_callsites(self, func: FuncDef) -> Tuple[List[Callsite], List[str]]:
        """Find all call sites of a function."""
        new_type = self.get_trivial_type(func)

        collector_plugin = SuggestionPlugin(func.fullname())

        self.plugin._plugins.insert(0, collector_plugin)
        try:
            errors = self.try_type(func, new_type)
        finally:
            self.plugin._plugins.pop(0)

        return collector_plugin.mystery_hits, errors
Exemple #25
0
    def visit_func_def(self, fdef: FuncDef) -> int:
        if fdef.name().endswith("*"):
            # Wrapper functions are not supported yet.
            return -1

        self.enter()

        for arg in fdef.args:
            self.add_local(arg)
        fdef.body.accept(self)
        self.add_implicit_return(cast(Callable, fdef.type))

        if fdef.info:
            name = "%s.%s" % (fdef.info.name(), fdef.name())
        else:
            name = fdef.name()

        self.generated[name] = FuncIcode(len(fdef.args), self.blocks, self.register_types)

        self.leave()

        return -1
Exemple #26
0
    def visit_FunctionDef(self, n: ast35.FunctionDef) -> Node:
        args = self.transform_args(n.args, n.lineno)

        arg_kinds = [arg.kind for arg in args]
        arg_names = [arg.variable.name() for arg in args]
        arg_types = None  # type: List[Type]
        if n.type_comment is not None:
            try:
                func_type_ast = ast35.parse(n.type_comment, '<func_type>', 'func_type')
            except SyntaxError:
                raise TypeCommentParseError(TYPE_COMMENT_SYNTAX_ERROR, n.lineno)
            assert isinstance(func_type_ast, ast35.FunctionType)
            # for ellipsis arg
            if (len(func_type_ast.argtypes) == 1 and
                    isinstance(func_type_ast.argtypes[0], ast35.Ellipsis)):
                arg_types = [a.type_annotation if a.type_annotation is not None else AnyType()
                             for a in args]
            else:
                arg_types = [a if a is not None else AnyType() for
                            a in TypeConverter(line=n.lineno).visit_list(func_type_ast.argtypes)]
            return_type = TypeConverter(line=n.lineno).visit(func_type_ast.returns)

            # add implicit self type
            if self.in_class() and len(arg_types) < len(args):
                arg_types.insert(0, AnyType())
        else:
            arg_types = [a.type_annotation for a in args]
            return_type = TypeConverter(line=n.lineno).visit(n.returns)

        if isinstance(return_type, UnboundType):
            return_type.is_ret_type = True

        func_type = None
        if any(arg_types) or return_type:
            func_type = CallableType([a if a is not None else AnyType() for a in arg_types],
                                     arg_kinds,
                                     arg_names,
                                     return_type if return_type is not None else AnyType(),
                                     None)

        func_def = FuncDef(n.name,
                       args,
                       self.as_block(n.body, n.lineno),
                       func_type)
        if func_type is not None:
            func_type.definition = func_def
            func_type.line = n.lineno

        if n.decorator_list:
            var = Var(func_def.name())
            var.is_ready = False
            var.set_line(n.decorator_list[0].lineno)

            func_def.is_decorated = True
            func_def.set_line(n.lineno + len(n.decorator_list))
            func_def.body.set_line(func_def.get_line())
            return Decorator(func_def, self.visit_list(n.decorator_list), var)
        else:
            return func_def
Exemple #27
0
    def visit_func_def(self, o: FuncDef) -> None:
        if self.is_private_name(o.name()):
            return
        if self.is_not_in_all(o.name()):
            return
        if self.is_recorded_name(o.name()):
            return
        if not self._indent and self._state not in (EMPTY, FUNC):
            self.add('\n')
        if not self.is_top_level():
            self_inits = find_self_initializers(o)
            for init, value in self_inits:
                init_code = self.get_init(init, value)
                if init_code:
                    self.add(init_code)
        self.add("%sdef %s(" % (self._indent, o.name()))
        self.record_name(o.name())
        args = []  # type: List[str]
        for i, arg_ in enumerate(o.arguments):
            var = arg_.variable
            kind = arg_.kind
            name = var.name()
            annotated_type = o.type.arg_types[i] if isinstance(o.type, CallableType) else None
            if annotated_type and not (
                    i == 0 and name == 'self' and isinstance(annotated_type, AnyType)):
                annotation = ": {}".format(self.print_annotation(annotated_type))
            else:
                annotation = ""
            if arg_.initializer:
                initializer = '...'
                if kind in (ARG_NAMED, ARG_NAMED_OPT) and not any(arg.startswith('*')
                                                                  for arg in args):
                    args.append('*')
                if not annotation:
                    typename = self.get_str_type_of_node(arg_.initializer, True)
                    annotation = ': {} = ...'.format(typename)
                else:
                    annotation += '={}'.format(initializer)
                arg = name + annotation
            elif kind == ARG_STAR:
                arg = '*%s%s' % (name, annotation)
            elif kind == ARG_STAR2:
                arg = '**%s%s' % (name, annotation)
            else:
                arg = name + annotation
            args.append(arg)
        retname = None
        if isinstance(o.type, CallableType):
            retname = self.print_annotation(o.type.ret_type)
        elif o.name() == '__init__' or not has_return_statement(o):
            retname = 'None'
        retfield = ''
        if retname is not None:
            retfield = ' -> ' + retname

        self.add(', '.join(args))
        self.add("){}: ...\n".format(retfield))
        self._state = FUNC
Exemple #28
0
    def visit_func_def(self, func: FuncDef, decorated: bool = False) -> None:
        """Process a func def.

        decorated is true if we are processing a func def in a
        Decorator that needs a _fullname and to have its body analyzed but
        does not need to be added to the symbol table.
        """
        sem = self.sem
        if sem.type is not None:
            # Don't process methods during pass 1.
            return
        func.is_conditional = sem.block_depth[-1] > 0
        func._fullname = sem.qualified_name(func.name())
        at_module = sem.is_module_scope() and not decorated
        if (at_module and func.name() == '__getattr__' and
                self.sem.cur_mod_node.is_package_init_file() and self.sem.cur_mod_node.is_stub):
            if isinstance(func.type, CallableType):
                ret = func.type.ret_type
                if isinstance(ret, UnboundType) and not ret.args:
                    sym = self.sem.lookup_qualified(ret.name, func, suppress_errors=True)
                    # We only interpret a package as partial if the __getattr__ return type
                    # is either types.ModuleType of Any.
                    if sym and sym.node and sym.node.fullname() in ('types.ModuleType',
                                                                    'typing.Any'):
                        self.sem.cur_mod_node.is_partial_stub_package = True
        if at_module and func.name() in sem.globals:
            # Already defined in this module.
            original_sym = sem.globals[func.name()]
            if (original_sym.kind == UNBOUND_IMPORTED or
                    isinstance(original_sym.node, ImportedName)):
                # Ah this is an imported name. We can't resolve them now, so we'll postpone
                # this until the main phase of semantic analysis.
                return
            if not sem.set_original_def(original_sym.node, func):
                # Report error.
                sem.check_no_global(func.name(), func)
        else:
            if at_module:
                sem.globals[func.name()] = SymbolTableNode(GDEF, func)
            # Also analyze the function body (needed in case there are unreachable
            # conditional imports).
            sem.function_stack.append(func)
            sem.scope.enter_function(func)
            sem.enter()
            func.body.accept(self)
            sem.leave()
            sem.scope.leave()
            sem.function_stack.pop()
Exemple #29
0
 def visit_func_def(self, node: FuncDef) -> None:
     old_global_scope = self.is_global_scope
     self.is_global_scope = False
     super().visit_func_def(node)
     self.is_global_scope = old_global_scope
     file_node = self.cur_mod_node
     if (self.is_global_scope
             and file_node.is_stub
             and node.name() == '__getattr__'
             and file_node.is_package_init_file()):
         # __init__.pyi with __getattr__ means that any submodules are assumed
         # to exist, even if there is no stub. Note that we can't verify that the
         # return type is compatible, since we haven't bound types yet.
         file_node.is_partial_stub_package = True
Exemple #30
0
 def visit_func_def(self, o: FuncDef) -> None:
     self.line = o.line
     if len(o.expanded) > 1 and o.expanded != [o] * len(o.expanded):
         if o in o.expanded:
             print('{}:{}: ERROR: cycle in function expansion; skipping'.format(self.filename,
                                                                                o.get_line()))
             return
         for defn in o.expanded:
             self.visit_func_def(cast(FuncDef, defn))
     else:
         if o.type:
             sig = cast(CallableType, o.type)
             arg_types = sig.arg_types
             if (sig.arg_names and sig.arg_names[0] == 'self' and
                     not self.inferred):
                 arg_types = arg_types[1:]
             for arg in arg_types:
                 self.type(arg)
             self.type(sig.ret_type)
         elif self.all_nodes:
             self.record_line(self.line, TYPE_ANY)
         if not o.is_dynamic() or self.visit_untyped_defs:
             super().visit_func_def(o)
Exemple #31
0
    def do_func_def(self,
                    n: Union[ast35.FunctionDef, ast35.AsyncFunctionDef],
                    is_coroutine: bool = False) -> Union[FuncDef, Decorator]:
        """Helper shared between visit_FunctionDef and visit_AsyncFunctionDef."""
        args = self.transform_args(n.args, n.lineno)

        arg_kinds = [arg.kind for arg in args]
        arg_names = [arg.variable.name()
                     for arg in args]  # type: List[Optional[str]]
        arg_names = [
            None if argument_elide_name(name) else name for name in arg_names
        ]
        if special_function_elide_names(n.name):
            arg_names = [None] * len(arg_names)
        arg_types = None  # type: List[Type]
        if n.type_comment is not None:
            try:
                func_type_ast = ast35.parse(n.type_comment, '<func_type>',
                                            'func_type')
            except SyntaxError:
                raise TypeCommentParseError(TYPE_COMMENT_SYNTAX_ERROR,
                                            n.lineno, n.col_offset)
            assert isinstance(func_type_ast, ast35.FunctionType)
            # for ellipsis arg
            if (len(func_type_ast.argtypes) == 1
                    and isinstance(func_type_ast.argtypes[0], ast35.Ellipsis)):
                arg_types = [
                    a.type_annotation
                    if a.type_annotation is not None else AnyType()
                    for a in args
                ]
            else:
                translated_args = (TypeConverter(
                    line=n.lineno).translate_expr_list(func_type_ast.argtypes))
                arg_types = [
                    a if a is not None else AnyType() for a in translated_args
                ]
            return_type = TypeConverter(line=n.lineno).visit(
                func_type_ast.returns)

            # add implicit self type
            if self.in_class() and len(arg_types) < len(args):
                arg_types.insert(0, AnyType())
        else:
            arg_types = [a.type_annotation for a in args]
            return_type = TypeConverter(line=n.lineno).visit(n.returns)

        for arg, arg_type in zip(args, arg_types):
            self.set_type_optional(arg_type, arg.initializer)

        if isinstance(return_type, UnboundType):
            return_type.is_ret_type = True

        func_type = None
        if any(arg_types) or return_type:
            if len(arg_types) > len(arg_kinds):
                raise FastParserError('Type signature has too many arguments',
                                      n.lineno,
                                      offset=0)
            if len(arg_types) < len(arg_kinds):
                raise FastParserError('Type signature has too few arguments',
                                      n.lineno,
                                      offset=0)
            func_type = CallableType(
                [
                    a if a is not None else AnyType(implicit=True)
                    for a in arg_types
                ], arg_kinds, arg_names,
                return_type if return_type is not None else AnyType(
                    implicit=True), None)

        func_def = FuncDef(n.name, args, self.as_block(n.body, n.lineno),
                           func_type)
        if is_coroutine:
            # A coroutine is also a generator, mostly for internal reasons.
            func_def.is_generator = func_def.is_coroutine = True
        if func_type is not None:
            func_type.definition = func_def
            func_type.line = n.lineno

        if n.decorator_list:
            var = Var(func_def.name())
            var.is_ready = False
            var.set_line(n.decorator_list[0].lineno)

            func_def.is_decorated = True
            func_def.set_line(n.lineno + len(n.decorator_list))
            func_def.body.set_line(func_def.get_line())
            return Decorator(func_def,
                             self.translate_expr_list(n.decorator_list), var)
        else:
            return func_def
Exemple #32
0
 def visit_func_def(self, node: FuncDef) -> None:
     if node not in self.transformer.func_placeholder_map:
         # Haven't seen this FuncDef before, so create a placeholder node.
         self.transformer.func_placeholder_map[node] = FuncDef(
             node.name(), node.arguments, node.body, None)
     super().visit_func_def(node)
Exemple #33
0
    def do_func_def(self,
                    n: Union[ast3.FunctionDef, ast3.AsyncFunctionDef],
                    is_coroutine: bool = False) -> Union[FuncDef, Decorator]:
        """Helper shared between visit_FunctionDef and visit_AsyncFunctionDef."""
        no_type_check = bool(
            n.decorator_list
            and any(is_no_type_check_decorator(d) for d in n.decorator_list))

        args = self.transform_args(n.args,
                                   n.lineno,
                                   no_type_check=no_type_check)

        arg_kinds = [arg.kind for arg in args]
        arg_names = [arg.variable.name()
                     for arg in args]  # type: List[Optional[str]]
        arg_names = [
            None if argument_elide_name(name) else name for name in arg_names
        ]
        if special_function_elide_names(n.name):
            arg_names = [None] * len(arg_names)
        arg_types = []  # type: List[Optional[Type]]
        if no_type_check:
            arg_types = [None] * len(args)
            return_type = None
        elif n.type_comment is not None:
            try:
                func_type_ast = ast3.parse(n.type_comment, '<func_type>',
                                           'func_type')
                assert isinstance(func_type_ast, ast3.FunctionType)
                # for ellipsis arg
                if (len(func_type_ast.argtypes) == 1 and isinstance(
                        func_type_ast.argtypes[0], ast3.Ellipsis)):
                    if n.returns:
                        # PEP 484 disallows both type annotations and type comments
                        self.fail(errorcode.DUPLICATE_TYPE_SIGNATURES(),
                                  n.lineno, n.col_offset)
                    arg_types = [
                        a.type_annotation if a.type_annotation is not None else
                        AnyType(TypeOfAny.unannotated) for a in args
                    ]
                else:
                    # PEP 484 disallows both type annotations and type comments
                    if n.returns or any(a.type_annotation is not None
                                        for a in args):
                        self.fail(errorcode.DUPLICATE_TYPE_SIGNATURES(),
                                  n.lineno, n.col_offset)
                    translated_args = (TypeConverter(
                        self.errors, line=n.lineno).translate_expr_list(
                            func_type_ast.argtypes))
                    arg_types = [
                        a if a is not None else AnyType(TypeOfAny.unannotated)
                        for a in translated_args
                    ]
                return_type = TypeConverter(self.errors, line=n.lineno).visit(
                    func_type_ast.returns)

                # add implicit self type
                if self.in_class() and len(arg_types) < len(args):
                    arg_types.insert(0, AnyType(TypeOfAny.special_form))
            except SyntaxError:
                self.fail(errorcode.SYNTAX_ERROR_TYPE_COMMENT(), n.lineno,
                          n.col_offset)
                if n.type_comment and n.type_comment[0] != "(":
                    self.note(
                        errorcode.MSG_SHOW(
                            'Suggestion: wrap argument types in parentheses'),
                        n.lineno, n.col_offset)
                arg_types = [AnyType(TypeOfAny.from_error)] * len(args)
                return_type = AnyType(TypeOfAny.from_error)
        else:
            arg_types = [a.type_annotation for a in args]
            return_type = TypeConverter(
                self.errors,
                line=n.returns.lineno if n.returns else n.lineno).visit(
                    n.returns)

        for arg, arg_type in zip(args, arg_types):
            self.set_type_optional(arg_type, arg.initializer)

        func_type = None
        if any(arg_types) or return_type:
            if len(arg_types) != 1 and any(
                    isinstance(t, EllipsisType) for t in arg_types):
                self.fail(
                    errorcode.
                    ELLIPSES_CANNOT_ACC_OTHER_ARG_TYPES_IN_FUNCTION_TYPE_SIGNATURE(
                    ), n.lineno, 0)
            elif len(arg_types) > len(arg_kinds):
                self.fail(errorcode.TYPE_SIGNATURE_HAS_TOO_MANY_ARGUMENTS(),
                          n.lineno, 0)
            elif len(arg_types) < len(arg_kinds):
                self.fail(errorcode.TYPE_SIGNATURE_HAS_TOO_FEW_ARGUMENTS(),
                          n.lineno, 0)
            else:
                func_type = CallableType([
                    a if a is not None else AnyType(TypeOfAny.unannotated)
                    for a in arg_types
                ], arg_kinds, arg_names, return_type if return_type is not None
                                         else AnyType(TypeOfAny.unannotated),
                                         _dummy_fallback)

        func_def = FuncDef(n.name, args,
                           self.as_required_block(n.body, n.lineno), func_type)
        if is_coroutine:
            # A coroutine is also a generator, mostly for internal reasons.
            func_def.is_generator = func_def.is_coroutine = True
        if func_type is not None:
            func_type.definition = func_def
            func_type.line = n.lineno

        if n.decorator_list:
            var = Var(func_def.name())
            var.is_ready = False
            var.set_line(n.decorator_list[0].lineno)

            func_def.is_decorated = True
            func_def.set_line(n.lineno + len(n.decorator_list))
            func_def.body.set_line(func_def.get_line())
            return Decorator(func_def,
                             self.translate_expr_list(n.decorator_list), var)
        else:
            return func_def
Exemple #34
0
def add_method_to_class(
    api: SemanticAnalyzerPluginInterface,
    cls: ClassDef,
    name: str,
    args: List[Argument],
    return_type: Type,
    self_type: Optional[Type] = None,
    tvar_def: Optional[TypeVarDef] = None,
    is_classmethod: bool = False,
) -> None:
    """
    Adds a new method to a class definition.

    NOTE:
    Copied from mypy/plugins/common.py and extended with support for adding
    classmethods based on https://github.com/python/mypy/pull/7796

    """

    info = cls.info

    # First remove any previously generated methods with the same name
    # to avoid clashes and problems in the semantic analyzer.
    if name in info.names:
        sym = info.names[name]
        if sym.plugin_generated and isinstance(sym.node, FuncDef):
            cls.defs.body.remove(sym.node)

    self_type = self_type or fill_typevars(info)

    # Add either self or cls as the first argument
    if is_classmethod:
        first = Argument(Var("cls"), TypeType.make_normalized(self_type), None,
                         ARG_POS)
    else:
        first = Argument(Var("self"), self_type, None, ARG_POS)

    args = [first] + args
    arg_types, arg_names, arg_kinds = [], [], []
    for arg in args:
        assert arg.type_annotation, "All arguments must be fully typed."
        arg_types.append(arg.type_annotation)
        arg_names.append(arg.variable.name)
        arg_kinds.append(arg.kind)

    function_type = api.named_type("__builtins__.function")
    signature = CallableType(arg_types, arg_kinds, arg_names, return_type,
                             function_type)
    if tvar_def:
        signature.variables = [tvar_def]

    func = FuncDef(name, args, Block([PassStmt()]))
    func.info = info
    func.type = set_callable_name(signature, func)
    func._fullname = info.fullname + "." + name  # pylint: disable=protected-access
    func.line = info.line
    func.is_class = is_classmethod

    # NOTE: we would like the plugin generated node to dominate, but we still
    # need to keep any existing definitions so they get semantically analyzed.
    if name in info.names:
        # Get a nice unique name instead.
        r_name = get_unique_redefinition_name(name, info.names)
        info.names[r_name] = info.names[name]

    if is_classmethod:
        func.is_decorated = True
        v = Var(name, func.type)
        v.info = info
        v._fullname = func._fullname  # pylint: disable=protected-access
        v.is_classmethod = True
        dec = Decorator(func, [NameExpr("classmethod")], v)

        dec.line = info.line
        sym = SymbolTableNode(MDEF, dec)
    else:
        sym = SymbolTableNode(MDEF, func)
    sym.plugin_generated = True

    info.names[name] = sym
    info.defn.defs.body.append(func)
Exemple #35
0
def add_method(
    ctx: ClassDefContext,
    name: str,
    args: List[Argument],
    return_type: Type,
    self_type: Optional[Type] = None,
    tvar_def: Optional[TypeVarDef] = None,
    is_classmethod: bool = False,
    is_new: bool = False,
    # is_staticmethod: bool = False,
) -> None:
    """
    Adds a new method to a class.

    This can be dropped if/when https://github.com/python/mypy/issues/7301 is merged
    """
    info = ctx.cls.info

    # First remove any previously generated methods with the same name
    # to avoid clashes and problems in the semantic analyzer.
    if name in info.names:
        sym = info.names[name]
        if sym.plugin_generated and isinstance(sym.node, FuncDef):
            ctx.cls.defs.body.remove(sym.node)

    self_type = self_type or fill_typevars(info)
    if is_classmethod or is_new:
        first = [Argument(Var('_cls'), TypeType.make_normalized(self_type), None, ARG_POS)]
    # elif is_staticmethod:
    #     first = []
    else:
        self_type = self_type or fill_typevars(info)
        first = [Argument(Var('__pydantic_self__'), self_type, None, ARG_POS)]
    args = first + args
    arg_types, arg_names, arg_kinds = [], [], []
    for arg in args:
        assert arg.type_annotation, 'All arguments must be fully typed.'
        arg_types.append(arg.type_annotation)
        arg_names.append(get_name(arg.variable))
        arg_kinds.append(arg.kind)

    function_type = ctx.api.named_type(f'{BUILTINS_NAME}.function')
    signature = CallableType(arg_types, arg_kinds, arg_names, return_type, function_type)
    if tvar_def:
        signature.variables = [tvar_def]

    func = FuncDef(name, args, Block([PassStmt()]))
    func.info = info
    func.type = set_callable_name(signature, func)
    func.is_class = is_classmethod
    # func.is_static = is_staticmethod
    func._fullname = get_fullname(info) + '.' + name
    func.line = info.line

    # NOTE: we would like the plugin generated node to dominate, but we still
    # need to keep any existing definitions so they get semantically analyzed.
    if name in info.names:
        # Get a nice unique name instead.
        r_name = get_unique_redefinition_name(name, info.names)
        info.names[r_name] = info.names[name]

    if is_classmethod:  # or is_staticmethod:
        func.is_decorated = True
        v = Var(name, func.type)
        v.info = info
        v._fullname = func._fullname
        # if is_classmethod:
        v.is_classmethod = True
        dec = Decorator(func, [NameExpr('classmethod')], v)
        # else:
        #     v.is_staticmethod = True
        #     dec = Decorator(func, [NameExpr('staticmethod')], v)

        dec.line = info.line
        sym = SymbolTableNode(MDEF, dec)
    else:
        sym = SymbolTableNode(MDEF, func)
    sym.plugin_generated = True

    info.names[name] = sym
    info.defn.defs.body.append(func)
Exemple #36
0
    def visit_func_def(self, node: FuncDef) -> FuncDef:
        # Note that a FuncDef must be transformed to a FuncDef.
        new = FuncDef(node.name(),
                      [self.copy_argument(arg) for arg in node.arguments],
                      self.block(node.body),
                      cast(FunctionLike, self.optional_type(node.type)))

        self.copy_function_attributes(new, node)

        new._fullname = node._fullname
        new.is_decorated = node.is_decorated
        new.is_conditional = node.is_conditional
        new.is_abstract = node.is_abstract
        new.is_static = node.is_static
        new.is_class = node.is_class
        new.is_property = node.is_property
        new.original_def = node.original_def
        return new
Exemple #37
0
    def visit_func_def(self, node: FuncDef) -> FuncDef:
        # Note that a FuncDef must be transformed to a FuncDef.
        new = FuncDef(node.name(), [self.visit_var(var) for var in node.args],
                      node.arg_kinds[:], [None] * len(node.init),
                      self.block(node.body), self.optional_type(node.type))

        self.copy_function_attributes(new, node)

        new._fullname = node._fullname
        new.is_decorated = node.is_decorated
        new.is_conditional = node.is_conditional
        new.is_abstract = node.is_abstract
        new.is_static = node.is_static
        new.is_class = node.is_class
        new.is_property = node.is_property
        new.original_def = node.original_def
        return new
Exemple #38
0
    def visit_FunctionDef(self, n: ast27.FunctionDef) -> Statement:
        self.class_and_function_stack.append('F')
        lineno = n.lineno
        converter = TypeConverter(self.errors,
                                  line=lineno,
                                  assume_str_is_unicode=self.unicode_literals)
        args, decompose_stmts = self.transform_args(n.args, lineno)

        arg_kinds = [arg.kind for arg in args]
        arg_names = [arg.variable.name()
                     for arg in args]  # type: List[Optional[str]]
        arg_names = [
            None if argument_elide_name(name) else name for name in arg_names
        ]
        if special_function_elide_names(n.name):
            arg_names = [None] * len(arg_names)

        arg_types = []  # type: List[Optional[Type]]
        type_comment = n.type_comment
        if (n.decorator_list and any(
                is_no_type_check_decorator(d) for d in n.decorator_list)):
            arg_types = [None] * len(args)
            return_type = None
        elif type_comment is not None and len(type_comment) > 0:
            try:
                func_type_ast = ast3_parse(type_comment, '<func_type>',
                                           'func_type')
                assert isinstance(func_type_ast, ast3.FunctionType)
                # for ellipsis arg
                if (len(func_type_ast.argtypes) == 1 and isinstance(
                        func_type_ast.argtypes[0], ast3.Ellipsis)):
                    arg_types = [
                        a.type_annotation if a.type_annotation is not None else
                        AnyType(TypeOfAny.unannotated) for a in args
                    ]
                else:
                    # PEP 484 disallows both type annotations and type comments
                    if any(a.type_annotation is not None for a in args):
                        self.fail(message_registry.DUPLICATE_TYPE_SIGNATURES,
                                  lineno, n.col_offset)
                    arg_types = [
                        a if a is not None else AnyType(TypeOfAny.unannotated)
                        for a in converter.translate_expr_list(
                            func_type_ast.argtypes)
                    ]
                return_type = converter.visit(func_type_ast.returns)

                # add implicit self type
                if self.in_method_scope() and len(arg_types) < len(args):
                    arg_types.insert(0, AnyType(TypeOfAny.special_form))
            except SyntaxError:
                stripped_type = type_comment.split("#", 2)[0].strip()
                err_msg = "{} '{}'".format(TYPE_COMMENT_SYNTAX_ERROR,
                                           stripped_type)
                self.fail(err_msg, lineno, n.col_offset)
                arg_types = [AnyType(TypeOfAny.from_error)] * len(args)
                return_type = AnyType(TypeOfAny.from_error)
        else:
            arg_types = [a.type_annotation for a in args]
            return_type = converter.visit(None)

        for arg, arg_type in zip(args, arg_types):
            self.set_type_optional(arg_type, arg.initializer)

        func_type = None
        if any(arg_types) or return_type:
            if len(arg_types) != 1 and any(
                    isinstance(t, EllipsisType) for t in arg_types):
                self.fail(
                    "Ellipses cannot accompany other argument types "
                    "in function type signature.", lineno, 0)
            elif len(arg_types) > len(arg_kinds):
                self.fail('Type signature has too many arguments',
                          lineno,
                          0,
                          blocker=False)
            elif len(arg_types) < len(arg_kinds):
                self.fail('Type signature has too few arguments',
                          lineno,
                          0,
                          blocker=False)
            else:
                any_type = AnyType(TypeOfAny.unannotated)
                func_type = CallableType(
                    [a if a is not None else any_type
                     for a in arg_types], arg_kinds, arg_names,
                    return_type if return_type is not None else any_type,
                    _dummy_fallback)

        body = self.as_required_block(n.body, lineno)
        if decompose_stmts:
            body.body = decompose_stmts + body.body
        func_def = FuncDef(n.name, args, body, func_type)
        if isinstance(func_def.type, CallableType):
            # semanal.py does some in-place modifications we want to avoid
            func_def.unanalyzed_type = func_def.type.copy_modified()
        if func_type is not None:
            func_type.definition = func_def
            func_type.line = lineno

        if n.decorator_list:
            var = Var(func_def.name())
            var.is_ready = False
            var.set_line(n.decorator_list[0].lineno)

            func_def.is_decorated = True
            func_def.set_line(lineno + len(n.decorator_list))
            func_def.body.set_line(func_def.get_line())
            dec = Decorator(func_def,
                            self.translate_expr_list(n.decorator_list), var)
            dec.set_line(lineno, n.col_offset)
            retval = dec  # type: Statement
        else:
            # Overrides set_line -- can't use self.set_line
            func_def.set_line(lineno, n.col_offset)
            retval = func_def
        self.class_and_function_stack.pop()
        return retval
Exemple #39
0
def add_class_method(
    ctx: ClassDefContext,
    name: str,
    args: List[Argument],
    return_type: Type,
    self_type: Optional[Type] = None,
    tvar_def: Optional[TypeVarDef] = None,
) -> None:
    """Adds a new class method to a class.
    """
    info = ctx.cls.info

    # First remove any previously generated methods with the same name
    # to avoid clashes and problems in the semantic analyzer.
    if name in info.names:
        sym = info.names[name]
        if sym.plugin_generated and isinstance(sym.node, FuncDef):
            ctx.cls.defs.body.remove(sym.node)

    self_type = self_type or fill_typevars(info)
    function_type = ctx.api.named_type('__builtins__.function')

    args = [
        Argument(Var('_cls'), TypeType.make_normalized(self_type), None,
                 ARG_POS)
    ] + args
    arg_types, arg_names, arg_kinds = [], [], []
    for arg in args:
        assert arg.type_annotation, 'All arguments must be fully typed.'
        arg_types.append(arg.type_annotation)
        arg_names.append(arg.variable.name)
        arg_kinds.append(arg.kind)

    signature = CallableType(arg_types, arg_kinds, arg_names, return_type,
                             function_type)
    if tvar_def:
        signature.variables = [tvar_def]

    func = FuncDef(name, args, Block([PassStmt()]))
    func.info = info
    func.type = set_callable_name(signature, func)
    func.is_class = True
    func._fullname = info.fullname + '.' + name
    func.line = info.line

    # NOTE: we would like the plugin generated node to dominate, but we still
    # need to keep any existing definitions so they get semantically analyzed.
    if name in info.names:
        # Get a nice unique name instead.
        r_name = get_unique_redefinition_name(name, info.names)
        info.names[r_name] = info.names[name]

    func.is_decorated = True
    v = Var(name, func.type)
    v.info = info
    v._fullname = func._fullname
    v.is_classmethod = True
    dec = Decorator(func, [NameExpr('classmethod')], v)

    dec.line = info.line
    sym = SymbolTableNode(MDEF, dec)

    sym.plugin_generated = True

    info.names[name] = sym
    info.defn.defs.body.append(func)
Exemple #40
0
def get_return_types(typemap: Dict[Expression, Type],
                     func: FuncDef) -> List[Type]:
    """Find all the types returned by return statements in func."""
    finder = ReturnFinder(typemap)
    func.accept(finder)
    return finder.return_types
Exemple #41
0
def deserialize_funcdefs(stmts):
    return [
        FuncDef.deserialize(stmt) for stmt in stmts
        if stmt[".class"] == "FuncDef"
    ]
Exemple #42
0
 def visit_func_def(self, func: FuncDef) -> None:
     if self.current_info is not None:
         func.info = self.current_info
     if func.type is not None:
         func.type.accept(self.type_fixer)
Exemple #43
0
    def visit_FunctionDef(self, n: ast27.FunctionDef) -> Statement:
        converter = TypeConverter(self.errors, line=n.lineno)
        args, decompose_stmts = self.transform_args(n.args, n.lineno)

        arg_kinds = [arg.kind for arg in args]
        arg_names = [arg.variable.name()
                     for arg in args]  # type: List[Optional[str]]
        arg_names = [
            None if argument_elide_name(name) else name for name in arg_names
        ]
        if special_function_elide_names(n.name):
            arg_names = [None] * len(arg_names)

        arg_types = None  # type: List[Type]
        if (n.decorator_list and any(
                is_no_type_check_decorator(d) for d in n.decorator_list)):
            arg_types = [None] * len(args)
            return_type = None
        elif n.type_comment is not None and len(n.type_comment) > 0:
            try:
                func_type_ast = ast3.parse(n.type_comment, '<func_type>',
                                           'func_type')
                assert isinstance(func_type_ast, ast3.FunctionType)
                # for ellipsis arg
                if (len(func_type_ast.argtypes) == 1 and isinstance(
                        func_type_ast.argtypes[0], ast3.Ellipsis)):
                    arg_types = [
                        a.type_annotation
                        if a.type_annotation is not None else AnyType()
                        for a in args
                    ]
                else:
                    # PEP 484 disallows both type annotations and type comments
                    if any(a.type_annotation is not None for a in args):
                        self.fail(messages.DUPLICATE_TYPE_SIGNATURES, n.lineno,
                                  n.col_offset)
                    arg_types = [
                        a if a is not None else AnyType() for a in
                        converter.translate_expr_list(func_type_ast.argtypes)
                    ]
                return_type = converter.visit(func_type_ast.returns)

                # add implicit self type
                if self.in_class() and len(arg_types) < len(args):
                    arg_types.insert(0, AnyType())
            except SyntaxError:
                self.fail(TYPE_COMMENT_SYNTAX_ERROR, n.lineno, n.col_offset)
                arg_types = [AnyType()] * len(args)
                return_type = AnyType()
        else:
            arg_types = [a.type_annotation for a in args]
            return_type = converter.visit(None)

        for arg, arg_type in zip(args, arg_types):
            self.set_type_optional(arg_type, arg.initializer)

        func_type = None
        if any(arg_types) or return_type:
            if len(arg_types) != 1 and any(
                    isinstance(t, EllipsisType) for t in arg_types):
                self.fail(
                    "Ellipses cannot accompany other argument types "
                    "in function type signature.", n.lineno, 0)
            elif len(arg_types) > len(arg_kinds):
                self.fail('Type signature has too many arguments', n.lineno, 0)
            elif len(arg_types) < len(arg_kinds):
                self.fail('Type signature has too few arguments', n.lineno, 0)
            else:
                func_type = CallableType(
                    [a if a is not None else AnyType()
                     for a in arg_types], arg_kinds, arg_names,
                    return_type if return_type is not None else AnyType(),
                    None)

        body = self.as_block(n.body, n.lineno)
        if decompose_stmts:
            body.body = decompose_stmts + body.body
        func_def = FuncDef(n.name, args, body, func_type)
        if func_type is not None:
            func_type.definition = func_def
            func_type.line = n.lineno

        if n.decorator_list:
            var = Var(func_def.name())
            var.is_ready = False
            var.set_line(n.decorator_list[0].lineno)

            func_def.is_decorated = True
            func_def.set_line(n.lineno + len(n.decorator_list))
            func_def.body.set_line(func_def.get_line())
            return Decorator(func_def,
                             self.translate_expr_list(n.decorator_list), var)
        else:
            return func_def
Exemple #44
0
 def visit_func_def(self, node: FuncDef) -> None:
     node.expanded = []
     node.type = node.unanalyzed_type
     with self.enter_class(node.info) if node.info else nothing():
         super().visit_func_def(node)
Exemple #45
0
            'line': self.line,
            'traceback_name': self.traceback_name,
        }

    @classmethod
    def deserialize(cls, data: JsonDict, ctx: DeserMaps) -> 'FuncIR':
        return FuncIR(
            FuncDecl.deserialize(data['decl'], ctx),
            [],
            [],
            data['line'],
            data['traceback_name'],
        )


INVALID_FUNC_DEF: Final = FuncDef("<INVALID_FUNC_DEF>", [], Block([]))


def all_values(args: List[Register], blocks: List[BasicBlock]) -> List[Value]:
    """Return the set of all values that may be initialized in the blocks.

    This omits registers that are only read.
    """
    values: List[Value] = list(args)
    seen_registers = set(args)

    for block in blocks:
        for op in block.ops:
            if not isinstance(op, ControlOp):
                if isinstance(op, (Assign, AssignMulti)):
                    if op.dest not in seen_registers:
Exemple #46
0
 def _add_bool_dunder(self, type_info: TypeInfo) -> None:
     signature = CallableType([], [], [], Instance(self.bool_type_info, []), self.function)
     bool_func = FuncDef('__bool__', [], Block([]))
     bool_func.type = set_callable_name(signature, bool_func)
     type_info.names[bool_func.name] = SymbolTableNode(MDEF, bool_func)
Exemple #47
0
    def visit_func_def(self, node: FuncDef) -> FuncDef:
        # Note that a FuncDef must be transformed to a FuncDef.

        # These contortions are needed to handle the case of recursive
        # references inside the function being transformed.
        # Set up placholder nodes for references within this function
        # to other functions defined inside it.
        # Don't create an entry for this function itself though,
        # since we want self-references to point to the original
        # function if this is the top-level node we are transforming.
        init = FuncMapInitializer(self)
        for stmt in node.body.body:
            stmt.accept(init)

        new = FuncDef(node.name(),
                      [self.copy_argument(arg) for arg in node.arguments],
                      self.block(node.body),
                      cast(FunctionLike, self.optional_type(node.type)))

        self.copy_function_attributes(new, node)

        new._fullname = node._fullname
        new.is_decorated = node.is_decorated
        new.is_conditional = node.is_conditional
        new.is_abstract = node.is_abstract
        new.is_static = node.is_static
        new.is_class = node.is_class
        new.is_property = node.is_property
        new.original_def = node.original_def

        if node in self.func_placeholder_map:
            # There is a placeholder definition for this function. Replace
            # the attributes of the placeholder with those form the transformed
            # function. We know that the classes will be identical (otherwise
            # this wouldn't work).
            result = self.func_placeholder_map[node]
            result.__dict__ = new.__dict__
            return result
        else:
            return new
Exemple #48
0
def _add_method(
    ctx: ClassDefContext,
    name: str,
    args: List[Argument],
    return_type: mypy.types.Type,
    self_type: Optional[mypy.types.Type] = None,
    tvar_def: Optional[mypy.types.TypeVarDef] = None,
    is_classmethod: bool = False,
) -> None:
    """Adds a new method to a class.
    """
    info = ctx.cls.info

    # First remove any previously generated methods with the same name
    # to avoid clashes and problems in new semantic analyzer.
    if name in info.names:
        sym = info.names[name]
        if sym.plugin_generated and isinstance(sym.node, FuncDef):
            ctx.cls.defs.body.remove(sym.node)

    if is_classmethod:
        first = Argument(
            Var('cls'),
            # Working around python/mypy#5416.
            # This should be: mypy.types.TypeType.make_normalized(self_type)
            mypy.types.AnyType(mypy.types.TypeOfAny.implementation_artifact),
            None,
            ARG_POS)
    else:
        self_type = self_type or fill_typevars(info)
        first = Argument(Var('self'), self_type, None, ARG_POS)

    args = [first] + args

    function_type = ctx.api.named_type('__builtins__.function')

    arg_types, arg_names, arg_kinds = [], [], []
    for arg in args:
        assert arg.type_annotation, 'All arguments must be fully typed.'
        arg_types.append(arg.type_annotation)
        arg_names.append(get_name(arg.variable))
        arg_kinds.append(arg.kind)

    signature = mypy.types.CallableType(arg_types, arg_kinds, arg_names,
                                        return_type, function_type)
    if tvar_def:
        signature.variables = [tvar_def]

    func = FuncDef(name, args, Block([PassStmt()]))
    func.info = info
    func.is_class = is_classmethod
    func.type = set_callable_name(signature, func)
    func._fullname = get_fullname(info) + '.' + name
    func.line = info.line

    # NOTE: we would like the plugin generated node to dominate, but we still
    # need to keep any existing definitions so they get semantically analyzed.
    if name in info.names:
        # Get a nice unique name instead.
        r_name = get_unique_redefinition_name(name, info.names)
        info.names[r_name] = info.names[name]

    info.defn.defs.body.append(func)
    info.names[name] = SymbolTableNode(MDEF, func, plugin_generated=True)
Exemple #49
0
    @property
    def ret_type(self) -> RType:
        return self.sig.ret_type

    def cname(self, names: NameGenerator) -> str:
        name = self.name
        if self.class_name:
            name += '_' + self.class_name
        return names.private_name(self.module_name, name)

    def __str__(self) -> str:
        return '\n'.join(format_func(self))


INVALID_FUNC_DEF = FuncDef('<INVALID_FUNC_DEF>', [], Block([]))

# Some notes on the vtable layout:
# Each concrete class has a vtable that contains function pointers for its
# methods and for getters/setters of its attributes. So that subclasses
# may be efficiently used when their parent class is expected, the layout
# of child vtables must be an extension of their base class's vtable.
#
# This makes multiple inheritance tricky, since obviously we cannot be
# an extension of multiple parent classes. We solve this by requriing
# all but one parent to be "traits", which we can operate on in a
# somewhat less efficient way. For each trait implemented by a class,
# we generate a separate vtable for the methods in that trait.
# We then store an array of (trait type, trait vtable) pointers alongside
# a class's main vtable. When we want to call a trait method, we
# (at runtime!) search the array of trait vtables to find the correct one,
            'line': self.line,
            'traceback_name': self.traceback_name,
        }

    @classmethod
    def deserialize(cls, data: JsonDict, ctx: DeserMaps) -> 'FuncIR':
        return FuncIR(
            FuncDecl.deserialize(data['decl'], ctx),
            [],
            [],
            data['line'],
            data['traceback_name'],
        )


INVALID_FUNC_DEF = FuncDef('<INVALID_FUNC_DEF>', [], Block([]))  # type: Final


def all_values(args: List[Register], blocks: List[BasicBlock]) -> List[Value]:
    """Return the set of all values that may be initialized in the blocks.

    This omits registers that are only read.
    """
    values = list(args)  # type: List[Value]
    seen_registers = set(args)

    for block in blocks:
        for op in block.ops:
            if not isinstance(op, ControlOp):
                if isinstance(op, (Assign, AssignMulti)):
                    if op.dest not in seen_registers:
Exemple #51
0
    def visit_FunctionDef(self, n: ast27.FunctionDef) -> Node:
        converter = TypeConverter(line=n.lineno)
        args = self.transform_args(n.args, n.lineno)

        arg_kinds = [arg.kind for arg in args]
        arg_names = [arg.variable.name() for arg in args]
        arg_types = None  # type: List[Type]
        if n.type_comment is not None and len(n.type_comment) > 0:
            try:
                func_type_ast = ast35.parse(n.type_comment, '<func_type>',
                                            'func_type')
            except SyntaxError:
                raise TypeCommentParseError(TYPE_COMMENT_SYNTAX_ERROR,
                                            n.lineno)
            assert isinstance(func_type_ast, ast35.FunctionType)
            # for ellipsis arg
            if (len(func_type_ast.argtypes) == 1
                    and isinstance(func_type_ast.argtypes[0], ast35.Ellipsis)):
                arg_types = [
                    a.type_annotation
                    if a.type_annotation is not None else AnyType()
                    for a in args
                ]
            else:
                arg_types = [
                    a if a is not None else AnyType()
                    for a in converter.visit_list(func_type_ast.argtypes)
                ]
            return_type = converter.visit(func_type_ast.returns)

            # add implicit self type
            if self.in_class() and len(arg_types) < len(args):
                arg_types.insert(0, AnyType())
        else:
            arg_types = [a.type_annotation for a in args]
            return_type = converter.visit(None)

        for arg, arg_type in zip(args, arg_types):
            self.set_type_optional(arg_type, arg.initializer)

        if isinstance(return_type, UnboundType):
            return_type.is_ret_type = True

        func_type = None
        if any(arg_types) or return_type:
            func_type = CallableType(
                [a if a is not None else AnyType()
                 for a in arg_types], arg_kinds, arg_names,
                return_type if return_type is not None else AnyType(), None)

        func_def = FuncDef(n.name, args, self.as_block(n.body, n.lineno),
                           func_type)
        if func_type is not None:
            func_type.definition = func_def
            func_type.line = n.lineno

        if n.decorator_list:
            var = Var(func_def.name())
            var.is_ready = False
            var.set_line(n.decorator_list[0].lineno)

            func_def.is_decorated = True
            func_def.set_line(n.lineno + len(n.decorator_list))
            func_def.body.set_line(func_def.get_line())
            return Decorator(func_def, self.visit_list(n.decorator_list), var)
        else:
            return func_def
Exemple #52
0
def add_classmethod_to_class(
    api: SemanticAnalyzerPluginInterface,
    cls: ClassDef,
    name: str,
    args: List[Argument],
    return_type: Type,
    cls_type: Optional[Type] = None,
    tvar_def: Optional[Any] = None,
) -> None:
    """
	Adds a new classmethod to a class definition.

	:param api:
	:param cls:
	:param name:
	:param args:
	:param return_type:
	:param cls_type:
	:param tvar_def:
	"""

    info = cls.info

    # First remove any previously generated methods with the same name
    # to avoid clashes and problems in the semantic analyzer.
    if name in info.names:
        sym = info.names[name]
        if sym.plugin_generated and isinstance(sym.node, FuncDef):
            cls.defs.body.remove(sym.node)

    cls_type = cls_type or fill_typevars(info)
    function_type = api.named_type(f"{_builtins}.function")

    args = [Argument(Var("cls"), cls_type, None, ARG_POS)] + args
    arg_types, arg_names, arg_kinds = [], [], []
    for arg in args:
        assert arg.type_annotation, "All arguments must be fully typed."
        arg_types.append(arg.type_annotation)
        arg_names.append(arg.variable.name)
        arg_kinds.append(arg.kind)

    signature = CallableType(arg_types, arg_kinds, arg_names, return_type,
                             function_type)
    if tvar_def:
        signature.variables = [tvar_def]

    func = FuncDef(name, args, Block([PassStmt()]))
    func.is_class = True
    func.info = info
    func.type = set_callable_name(signature, func)
    func._fullname = info.fullname + '.' + name
    func.line = info.line

    # NOTE: we would like the plugin generated node to dominate, but we still
    # need to keep any existing definitions so they get semantically analyzed.
    if name in info.names:
        # Get a nice unique name instead.
        r_name = get_unique_redefinition_name(name, info.names)
        info.names[r_name] = info.names[name]

    info.names[name] = SymbolTableNode(MDEF, func, plugin_generated=True)
    info.defn.defs.body.append(func)
Exemple #53
0
    def make_init_wrapper(self, tdef: ClassDef) -> 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 []
Exemple #54
0
    def visit_func_def(self, o: FuncDef) -> None:
        if self.is_private_name(o.name()):
            return
        if self.is_not_in_all(o.name()):
            return
        if self.is_recorded_name(o.name()):
            return
        if not self._indent and self._state not in (EMPTY, FUNC):
            self.add('\n')
        if not self.is_top_level():
            self_inits = find_self_initializers(o)
            for init, value in self_inits:
                init_code = self.get_init(init, value)
                if init_code:
                    self.add(init_code)
        self.add("%sdef %s(" % (self._indent, o.name()))
        self.record_name(o.name())
        args = []  # type: List[str]
        for i, arg_ in enumerate(o.arguments):
            var = arg_.variable
            kind = arg_.kind
            name = var.name()
            annotated_type = o.type.arg_types[i] if isinstance(o.type, CallableType) else None
            is_self_arg = i == 0 and name == 'self'
            is_cls_arg = i == 0 and name == 'cls'
            if (annotated_type is None
                    and not arg_.initializer
                    and not is_self_arg
                    and not is_cls_arg):
                self.add_typing_import("Any")
                annotation = ": Any"
            elif annotated_type and not is_self_arg:
                annotation = ": {}".format(self.print_annotation(annotated_type))
            else:
                annotation = ""
            if arg_.initializer:
                initializer = '...'
                if kind in (ARG_NAMED, ARG_NAMED_OPT) and not any(arg.startswith('*')
                                                                  for arg in args):
                    args.append('*')
                if not annotation:
                    typename = self.get_str_type_of_node(arg_.initializer, True)
                    annotation = ': {} = ...'.format(typename)
                else:
                    annotation += '={}'.format(initializer)
                arg = name + annotation
            elif kind == ARG_STAR:
                arg = '*%s%s' % (name, annotation)
            elif kind == ARG_STAR2:
                arg = '**%s%s' % (name, annotation)
            else:
                arg = name + annotation
            args.append(arg)
        retname = None
        if isinstance(o.type, CallableType):
            retname = self.print_annotation(o.type.ret_type)
        elif o.name() == '__init__' or not has_return_statement(o):
            retname = 'None'
        retfield = ''
        if retname is not None:
            retfield = ' -> ' + retname

        self.add(', '.join(args))
        self.add("){}: ...\n".format(retfield))
        self._state = FUNC
Exemple #55
0
    def do_func_def(self,
                    n: Union[ast3.FunctionDef, ast3.AsyncFunctionDef],
                    is_coroutine: bool = False) -> Union[FuncDef, Decorator]:
        """Helper shared between visit_FunctionDef and visit_AsyncFunctionDef."""
        no_type_check = bool(
            n.decorator_list
            and any(is_no_type_check_decorator(d) for d in n.decorator_list))

        args = self.transform_args(n.args,
                                   n.lineno,
                                   no_type_check=no_type_check)

        arg_kinds = [arg.kind for arg in args]
        arg_names = [arg.variable.name()
                     for arg in args]  # type: List[Optional[str]]
        arg_names = [
            None if argument_elide_name(name) else name for name in arg_names
        ]
        if special_function_elide_names(n.name):
            arg_names = [None] * len(arg_names)
        arg_types = None  # type: List[Type]
        if no_type_check:
            arg_types = [None] * len(args)
            return_type = None
        elif n.type_comment is not None:
            try:
                func_type_ast = ast3.parse(n.type_comment, '<func_type>',
                                           'func_type')
                assert isinstance(func_type_ast, ast3.FunctionType)
                # for ellipsis arg
                if (len(func_type_ast.argtypes) == 1 and isinstance(
                        func_type_ast.argtypes[0], ast3.Ellipsis)):
                    if n.returns:
                        # PEP 484 disallows both type annotations and type comments
                        self.fail(messages.DUPLICATE_TYPE_SIGNATURES, n.lineno,
                                  n.col_offset)
                    arg_types = [
                        a.type_annotation if a.type_annotation is not None else
                        AnyType(TypeOfAny.implicit) for a in args
                    ]
                else:
                    # PEP 484 disallows both type annotations and type comments
                    if n.returns or any(a.type_annotation is not None
                                        for a in args):
                        self.fail(messages.DUPLICATE_TYPE_SIGNATURES, n.lineno,
                                  n.col_offset)
                    translated_args = (TypeConverter(
                        self.errors, line=n.lineno).translate_expr_list(
                            func_type_ast.argtypes))
                    arg_types = [
                        a if a is not None else AnyType(TypeOfAny.implicit)
                        for a in translated_args
                    ]
                return_type = TypeConverter(self.errors, line=n.lineno).visit(
                    func_type_ast.returns)

                # add implicit self type
                if self.in_class() and len(arg_types) < len(args):
                    arg_types.insert(0, AnyType(TypeOfAny.special_form))
            except SyntaxError:
                self.fail(TYPE_COMMENT_SYNTAX_ERROR, n.lineno, n.col_offset)
                arg_types = [AnyType(TypeOfAny.from_error)] * len(args)
                return_type = AnyType(TypeOfAny.from_error)
        else:
            arg_types = [a.type_annotation for a in args]
            return_type = TypeConverter(
                self.errors,
                line=n.returns.lineno if n.returns else n.lineno).visit(
                    n.returns)

        for arg, arg_type in zip(args, arg_types):
            self.set_type_optional(arg_type, arg.initializer)

        func_type = None
        if any(arg_types) or return_type:
            if len(arg_types) != 1 and any(
                    isinstance(t, EllipsisType) for t in arg_types):
                self.fail(
                    "Ellipses cannot accompany other argument types "
                    "in function type signature.", n.lineno, 0)
            elif len(arg_types) > len(arg_kinds):
                self.fail('Type signature has too many arguments', n.lineno, 0)
            elif len(arg_types) < len(arg_kinds):
                self.fail('Type signature has too few arguments', n.lineno, 0)
            else:
                func_type = CallableType([
                    a if a is not None else AnyType(TypeOfAny.implicit)
                    for a in arg_types
                ], arg_kinds, arg_names, return_type if return_type is not None
                                         else AnyType(TypeOfAny.implicit),
                                         None)

        func_def = FuncDef(n.name, args, self.as_block(n.body, n.lineno),
                           func_type)
        if is_coroutine:
            # A coroutine is also a generator, mostly for internal reasons.
            func_def.is_generator = func_def.is_coroutine = True
        if func_type is not None:
            func_type.definition = func_def
            func_type.line = n.lineno

        if n.decorator_list:
            var = Var(func_def.name())
            var.is_ready = False
            var.set_line(n.decorator_list[0].lineno)

            func_def.is_decorated = True
            func_def.set_line(n.lineno + len(n.decorator_list))
            func_def.body.set_line(func_def.get_line())
            return Decorator(func_def,
                             self.translate_expr_list(n.decorator_list), var)
        else:
            return func_def
Exemple #56
0
 def visit_func_def(self, fdef: FuncDef) -> None:
     self.errors.push_function(fdef.name())
     self.analyze(fdef.type, fdef)
     super().visit_func_def(fdef)
     self.errors.pop_function()