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()
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)
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)
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()
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)
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()
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.
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)