Exemple #1
0
    def has_no_attr(self, typ: Type, member: str, context: Context) -> Type:
        """Report a missing or non-accessible member.

        The type argument is the base type. If member corresponds to
        an operator, use the corresponding operator name in the
        messages. Return type Any.
        """
        if (isinstance(typ, Instance) and
                (cast(Instance, typ)).type.has_readable_member(member)):
            self.fail('Member "{}" is not assignable'.format(member), context)
        elif isinstance(typ, Void):
            self.check_void(typ, context)
        elif member == '__contains__':
            self.fail('Unsupported right operand type for in ({})'.format(
                self.format(typ)), context)
        elif member in op_methods.values():
            # Access to a binary operator member (e.g. _add). This case does
            # not handle indexing operations.
            for op, method in op_methods.items():
                if method == member:
                    self.unsupported_left_operand(op, typ, context)
                    break
        elif member == '__neg__':
            self.fail('Unsupported operand type for unary - ({})'.format(
                self.format(typ)), context)
        elif member == '__pos__':
            self.fail('Unsupported operand type for unary + ({})'.format(
                self.format(typ)), context)
        elif member == '__invert__':
            self.fail('Unsupported operand type for ~ ({})'.format(
                self.format(typ)), context)
        elif member == '__getitem__':
            # Indexed get.
            self.fail('Value of type {} is not indexable'.format(
                self.format(typ)), context)
        elif member == '__setitem__':
            # Indexed set.
            self.fail('Unsupported target for indexed assignment', context)
        elif member == '__call__':
            self.fail('{} not callable'.format(self.format(typ)), context)
        else:
            # The non-special case: a missing ordinary attribute.
            if not self.disable_type_names:
                failed = False
                if isinstance(typ, Instance) and cast(Instance, typ).type.names:
                    typ = cast(Instance, typ)
                    alternatives = set(typ.type.names.keys())
                    matches = [m for m in COMMON_MISTAKES.get(member, []) if m in alternatives]
                    matches.extend(best_matches(member, alternatives)[:3])
                    if matches:
                        self.fail('{} has no attribute "{}"; maybe {}?'.format(
                            self.format(typ), member, pretty_or(matches)), context)
                        failed = True
                if not failed:
                    self.fail('{} has no attribute "{}"'.format(self.format(typ),
                                                                member), context)
            else:
                self.fail('Some element of union has no attribute "{}"'.format(
                    member), context)
        return AnyType()
Exemple #2
0
    def incompatible_argument(self, n: int, callee: Callable, arg_type: Type,
                              context: Context) -> None:
        """Report an error about an incompatible argument type.

        The argument type is arg_type, argument number is n and the
        callee type is 'callee'. If the callee represents a method
        that corresponds to an operator, use the corresponding
        operator name in the messages.
        """
        target = ''
        if callee.name:
            name = callee.name
            base = extract_type(name)
            
            for op, method in op_methods.items():
                for variant in method, '__r' + method[2:]:
                    if name.startswith('"{}" of'.format(variant)):
                        if op == 'in' or variant != method:
                            # Reversed order of base/argument.
                            self.unsupported_operand_types(op, arg_type, base,
                                                           context)
                        else:
                            self.unsupported_operand_types(op, base, arg_type,
                                                           context)
                        return 
            
            if name.startswith('"__getitem__" of'):
                self.invalid_index_type(arg_type, base, context)
                return 
            
            if name.startswith('"__setitem__" of'):
                if n == 1:
                    self.invalid_index_type(arg_type, base, context)
                else:
                    self.fail(INCOMPATIBLE_TYPES_IN_ASSIGNMENT, context)
                return 
            
            target = 'to {} '.format(name)
        
        msg = ''
        if callee.name == '<list>':
            name = callee.name[1:-1]
            msg = '{} item {} has incompatible type {}'.format(
                name[0].upper() + name[1:], n, self.format_simple(arg_type))
        elif callee.name == '<list-comprehension>':
            msg = 'List comprehension has incompatible type List[{}]'.format(
                                  strip_quotes(self.format(arg_type)))
        elif callee.name == '<generator>':
            msg = 'Generator has incompatible item type {}'.format(
                                              self.format_simple(arg_type))
        else:
            try:
                expected_type = callee.arg_types[n-1]
            except IndexError:  # Varargs callees
                expected_type = callee.arg_types[-1]
            msg = 'Argument {} {}has incompatible type {}; expected {}'.format(
                n, target, self.format(arg_type), self.format(expected_type))
        self.fail(msg, context)
Exemple #3
0
 def incompatible_argument(self, n, callee, arg_type, context):
     """Report an error about an incompatible type arg_type for
     argument n when calling a value with type callee. If the
     callee represents a method that corresponds to an operator,
     use the corresponding operator name in the messages.
     """
     target = ''
     if callee.name:
         name = callee.name
         base = extract_type(name)
         
         for op, method in op_methods.items():
             if name.startswith('"{}" of'.format(method)):
                 if op == 'in':
                     self.unsupported_operand_types(op, arg_type, base,
                                                    context)
                 else:
                     self.unsupported_operand_types(op, base, arg_type,
                                                    context)
                 return 
         
         if name.startswith('"__getitem__" of'):
             self.invalid_index_type(arg_type, base, context)
             return 
         
         if name.startswith('"__setitem__" of'):
             if n == 1:
                 self.invalid_index_type(arg_type, base, context)
             else:
                 self.fail(INCOMPATIBLE_TYPES_IN_ASSIGNMENT, context)
             return 
         
         if name.startswith('method "create" of '):
             name = base
         target = 'to {} '.format(name)
     
     msg = None
     if callee.name == '<list>':
         name = callee.name[1:-1]
         msg = '{} item {} has incompatible type {}'.format(
             name[0].upper() + name[1:], n, self.format_simple(arg_type))
     elif callee.name == '<list-comprehension>':
         msg = 'List comprehension has incompatible type {}[]'.format(
                               strip_quotes(self.format_simple(arg_type)))
     elif callee.name == '<generator>':
         msg = 'Generator has incompatible item type {}'.format(
                                           self.format_simple(arg_type))
     else:
         msg = 'Argument {} {}has incompatible type {}'.format(
             n, target, self.format_simple(arg_type))
     self.fail(msg, context)
Exemple #4
0
    def has_no_attr(self, typ: Type, member: str, context: Context) -> Type:
        """Report a missing or non-accessible member.

        The type argument is the base type. If member corresponds to
        an operator, use the corresponding operator name in the
        messages. Return type Any.
        """
        if (isinstance(typ, Instance) and
                (cast(Instance, typ)).type.has_readable_member(member)):
            self.fail('Member "{}" is not assignable'.format(member), context)
        elif isinstance(typ, Void):
            self.check_void(typ, context)
        elif member == '__contains__':
            self.fail('Unsupported right operand type for in ({})'.format(
                self.format(typ)), context)
        elif member in op_methods.values():
            # Access to a binary operator member (e.g. _add). This case does
            # not handle indexing operations.
            for op, method in op_methods.items():
                if method == member:
                    self.unsupported_left_operand(op, typ, context)
                    break
        elif member == '__neg__':
            self.fail('Unsupported operand type for unary - ({})'.format(
                self.format(typ)), context)
        elif member == '__invert__':
            self.fail('Unsupported operand type for ~ ({})'.format(
                self.format(typ)), context)
        elif member == '__getitem__':
            # Indexed get.
            self.fail('Value of type {} is not indexable'.format(
                self.format(typ)), context)
        elif member == '__setitem__':
            # Indexed set.
            self.fail('Unsupported target for indexed assignment', context)
        else:
            # The non-special case: a missing ordinary attribute.
            self.fail('{} has no attribute "{}"'.format(self.format(typ),
                                                        member), context)
        return AnyType()
Exemple #5
0
    def incompatible_argument(self, n: int, m: int, callee: CallableType, arg_type: Type,
                              arg_kind: int, context: Context) -> None:
        """Report an error about an incompatible argument type.

        The argument type is arg_type, argument number is n and the
        callee type is 'callee'. If the callee represents a method
        that corresponds to an operator, use the corresponding
        operator name in the messages.
        """
        target = ''
        if callee.name:
            name = callee.name
            base = extract_type(name)

            for op, method in op_methods.items():
                for variant in method, '__r' + method[2:]:
                    if name.startswith('"{}" of'.format(variant)):
                        if op == 'in' or variant != method:
                            # Reversed order of base/argument.
                            self.unsupported_operand_types(op, arg_type, base,
                                                           context)
                        else:
                            self.unsupported_operand_types(op, base, arg_type,
                                                           context)
                        return

            if name.startswith('"__getitem__" of'):
                self.invalid_index_type(arg_type, callee.arg_types[n - 1], base, context)
                return

            if name.startswith('"__setitem__" of'):
                if n == 1:
                    self.invalid_index_type(arg_type, callee.arg_types[n - 1], base, context)
                else:
                    msg = '{} (expression has type {}, target has type {})'
                    arg_type_str, callee_type_str = self.format_distinctly(arg_type,
                                                                           callee.arg_types[n - 1])
                    self.fail(msg.format(INCOMPATIBLE_TYPES_IN_ASSIGNMENT,
                                         arg_type_str, callee_type_str),
                              context)
                return

            target = 'to {} '.format(name)

        msg = ''
        if callee.name == '<list>':
            name = callee.name[1:-1]
            n -= 1
            msg = '{} item {} has incompatible type {}'.format(
                name[0].upper() + name[1:], n, self.format_simple(arg_type))
        elif callee.name == '<list-comprehension>':
            msg = 'List comprehension has incompatible type List[{}]'.format(
                strip_quotes(self.format(arg_type)))
        elif callee.name == '<set-comprehension>':
            msg = 'Set comprehension has incompatible type Set[{}]'.format(
                strip_quotes(self.format(arg_type)))
        elif callee.name == '<dictionary-comprehension>':
            msg = ('{} expression in dictionary comprehension has incompatible type {}; '
                   'expected type {}').format(
                'Key' if n == 1 else 'Value',
                self.format(arg_type),
                self.format(callee.arg_types[n - 1]))
        elif callee.name == '<generator>':
            msg = 'Generator has incompatible item type {}'.format(
                self.format_simple(arg_type))
        else:
            try:
                expected_type = callee.arg_types[m - 1]
            except IndexError:  # Varargs callees
                expected_type = callee.arg_types[-1]
            arg_type_str, expected_type_str = self.format_distinctly(arg_type, expected_type)
            if arg_kind == ARG_STAR:
                arg_type_str = '*' + arg_type_str
            elif arg_kind == ARG_STAR2:
                arg_type_str = '**' + arg_type_str
            msg = 'Argument {} {}has incompatible type {}; expected {}'.format(
                n, target, arg_type_str, expected_type_str)
        self.fail(msg, context)
Exemple #6
0
    def has_no_attr(self, typ: Type, member: str, context: Context) -> Type:
        """Report a missing or non-accessible member.

        The type argument is the base type. If member corresponds to
        an operator, use the corresponding operator name in the
        messages. Return type Any.
        """
        if (isinstance(typ, Instance) and
                typ.type.has_readable_member(member)):
            self.fail('Member "{}" is not assignable'.format(member), context)
        elif member == '__contains__':
            self.fail('Unsupported right operand type for in ({})'.format(
                self.format(typ)), context)
        elif member in op_methods.values():
            # Access to a binary operator member (e.g. _add). This case does
            # not handle indexing operations.
            for op, method in op_methods.items():
                if method == member:
                    self.unsupported_left_operand(op, typ, context)
                    break
        elif member == '__neg__':
            self.fail('Unsupported operand type for unary - ({})'.format(
                self.format(typ)), context)
        elif member == '__pos__':
            self.fail('Unsupported operand type for unary + ({})'.format(
                self.format(typ)), context)
        elif member == '__invert__':
            self.fail('Unsupported operand type for ~ ({})'.format(
                self.format(typ)), context)
        elif member == '__getitem__':
            # Indexed get.
            # TODO: Fix this consistently in self.format
            if isinstance(typ, CallableType) and typ.is_type_obj():
                self.fail('The type {} is not generic and not indexable'.format(
                    self.format(typ)), context)
            else:
                self.fail('Value of type {} is not indexable'.format(
                    self.format(typ)), context)
        elif member == '__setitem__':
            # Indexed set.
            self.fail('Unsupported target for indexed assignment', context)
        elif member == '__call__':
            if isinstance(typ, Instance) and (typ.type.fullname() == 'builtins.function'):
                # "'function' not callable" is a confusing error message.
                # Explain that the problem is that the type of the function is not known.
                self.fail('Cannot call function of unknown type', context)
            else:
                self.fail('{} not callable'.format(self.format(typ)), context)
        else:
            # The non-special case: a missing ordinary attribute.
            if not self.disable_type_names:
                failed = False
                if isinstance(typ, Instance) and typ.type.names:
                    alternatives = set(typ.type.names.keys())
                    matches = [m for m in COMMON_MISTAKES.get(member, []) if m in alternatives]
                    matches.extend(best_matches(member, alternatives)[:3])
                    if matches:
                        self.fail('{} has no attribute "{}"; maybe {}?'.format(
                            self.format(typ), member, pretty_or(matches)), context)
                        failed = True
                if not failed:
                    self.fail('{} has no attribute "{}"'.format(self.format(typ),
                                                                member), context)
            else:
                self.fail('Some element of union has no attribute "{}"'.format(
                    member), context)
        return AnyType()
    def has_no_attr(self, original_type: Type, typ: Type, member: str, context: Context) -> Type:
        """Report a missing or non-accessible member.

        original_type is the top-level type on which the error occurred.
        typ is the actual type that is missing the member. These can be
        different, e.g., in a union, original_type will be the union and typ
        will be the specific item in the union that does not have the member
        attribute.

        If member corresponds to an operator, use the corresponding operator
        name in the messages. Return type Any.
        """
        if (isinstance(original_type, Instance) and
                original_type.type.has_readable_member(member)):
            self.fail('Member "{}" is not assignable'.format(member), context)
        elif member == '__contains__':
            self.fail('Unsupported right operand type for in ({})'.format(
                self.format(original_type)), context)
        elif member in op_methods.values():
            # Access to a binary operator member (e.g. _add). This case does
            # not handle indexing operations.
            for op, method in op_methods.items():
                if method == member:
                    self.unsupported_left_operand(op, original_type, context)
                    break
        elif member == '__neg__':
            self.fail('Unsupported operand type for unary - ({})'.format(
                self.format(original_type)), context)
        elif member == '__pos__':
            self.fail('Unsupported operand type for unary + ({})'.format(
                self.format(original_type)), context)
        elif member == '__invert__':
            self.fail('Unsupported operand type for ~ ({})'.format(
                self.format(original_type)), context)
        elif member == '__getitem__':
            # Indexed get.
            # TODO: Fix this consistently in self.format
            if isinstance(original_type, CallableType) and original_type.is_type_obj():
                self.fail('The type {} is not generic and not indexable'.format(
                    self.format(original_type)), context)
            else:
                self.fail('Value of type {} is not indexable'.format(
                    self.format(original_type)), context)
        elif member == '__setitem__':
            # Indexed set.
            self.fail('Unsupported target for indexed assignment', context)
        elif member == '__call__':
            if isinstance(original_type, Instance) and \
                    (original_type.type.fullname() == 'builtins.function'):
                # "'function' not callable" is a confusing error message.
                # Explain that the problem is that the type of the function is not known.
                self.fail('Cannot call function of unknown type', context)
            else:
                self.fail('{} not callable'.format(self.format(original_type)), context)
        else:
            # The non-special case: a missing ordinary attribute.
            if not self.disable_type_names:
                failed = False
                if isinstance(original_type, Instance) and original_type.type.names:
                    alternatives = set(original_type.type.names.keys())
                    matches = [m for m in COMMON_MISTAKES.get(member, []) if m in alternatives]
                    matches.extend(best_matches(member, alternatives)[:3])
                    if matches:
                        self.fail('{} has no attribute "{}"; maybe {}?'.format(
                            self.format(original_type), member, pretty_or(matches)), context)
                        failed = True
                if not failed:
                    self.fail('{} has no attribute "{}"'.format(self.format(original_type),
                                                                member), context)
            elif isinstance(original_type, UnionType):
                # The checker passes "object" in lieu of "None" for attribute
                # checks, so we manually convert it back.
                typ_format = self.format(typ)
                if typ_format == '"object"' and \
                        any(type(item) == NoneTyp for item in original_type.items):
                    typ_format = '"None"'
                self.fail('Item {} of {} has no attribute "{}"'.format(
                    typ_format, self.format(original_type), member), context)
        return AnyType()
Exemple #8
0
 argument is the base type. If member corresponds to an
 operator, use the corresponding operator name in the
 messages. Return type Any.
 """
 if (isinstance(typ, Instance) and
         ((Instance)typ).type.has_readable_member(member)):
     self.fail('Member "{}" is not assignable'.format(member), context)
 elif isinstance(typ, Void):
     self.check_void(typ, context)
 elif member == '__contains__':
     self.fail('Unsupported right operand type for in ({})'.format(
         self.format(typ)), context)
 elif member in op_methods.values():
     # Access to a binary operator member (e.g. _add). This case does
     # not handle indexing operations.
     for op, method in op_methods.items():
         if method == member:
             self.unsupported_left_operand(op, typ, context)
             break
 elif member == '__neg__':
     self.fail('Unsupported operand type for unary - ({})'.format(
         self.format(typ)), context)
 elif member == '__invert__':
     self.fail('Unsupported operand type for ~ ({})'.format(
         self.format(typ)), context)
 elif member == '__getitem__':
     # Indexed get.
     self.fail('Value of type {} is not indexable'.format(
         self.format(typ)), context)
 elif member == '__setitem__':
     # Indexed set.
Exemple #9
0
    def incompatible_argument(
        self, n: int, m: int, callee: CallableType, arg_type: Type, arg_kind: int, context: Context
    ) -> None:
        """Report an error about an incompatible argument type.

        The argument type is arg_type, argument number is n and the
        callee type is 'callee'. If the callee represents a method
        that corresponds to an operator, use the corresponding
        operator name in the messages.
        """
        target = ""
        if callee.name:
            name = callee.name
            base = extract_type(name)

            for op, method in op_methods.items():
                for variant in method, "__r" + method[2:]:
                    if name.startswith('"{}" of'.format(variant)):
                        if op == "in" or variant != method:
                            # Reversed order of base/argument.
                            self.unsupported_operand_types(op, arg_type, base, context)
                        else:
                            self.unsupported_operand_types(op, base, arg_type, context)
                        return

            if name.startswith('"__getitem__" of'):
                self.invalid_index_type(arg_type, base, context)
                return

            if name.startswith('"__setitem__" of'):
                if n == 1:
                    self.invalid_index_type(arg_type, base, context)
                else:
                    self.fail(INCOMPATIBLE_TYPES_IN_ASSIGNMENT, context)
                return

            target = "to {} ".format(name)

        msg = ""
        if callee.name == "<list>":
            name = callee.name[1:-1]
            n -= 1
            msg = "{} item {} has incompatible type {}".format(
                name[0].upper() + name[1:], n, self.format_simple(arg_type)
            )
        elif callee.name == "<list-comprehension>":
            msg = "List comprehension has incompatible type List[{}]".format(strip_quotes(self.format(arg_type)))
        elif callee.name == "<set-comprehension>":
            msg = "Set comprehension has incompatible type Set[{}]".format(strip_quotes(self.format(arg_type)))
        elif callee.name == "<dictionary-comprehension>":
            msg = ("{} expression in dictionary comprehension has incompatible type {}; " "expected type {}").format(
                "Key" if n == 1 else "Value", self.format(arg_type), self.format(callee.arg_types[n - 1])
            )
        elif callee.name == "<generator>":
            msg = "Generator has incompatible item type {}".format(self.format_simple(arg_type))
        else:
            try:
                expected_type = callee.arg_types[m - 1]
            except IndexError:  # Varargs callees
                expected_type = callee.arg_types[-1]
            arg_type_str, expected_type_str = self.format_distinctly(arg_type, expected_type)
            if arg_kind == ARG_STAR:
                arg_type_str = "*" + arg_type_str
            elif arg_kind == ARG_STAR2:
                arg_type_str = "**" + arg_type_str
            msg = "Argument {} {}has incompatible type {}; expected {}".format(
                n, target, arg_type_str, expected_type_str
            )
        self.fail(msg, context)