def visit_instance(self, t: Instance) -> Type: if isinstance(self.s, Instance): si = self.s if t.type == si.type: if is_subtype(t, self.s) or is_subtype(self.s, t): # Combine type arguments. We could have used join below # equivalently. args = [] # type: List[Type] for i in range(len(t.args)): args.append(self.meet(t.args[i], si.args[i])) return Instance(t.type, args) else: if experiments.STRICT_OPTIONAL: return UninhabitedType() else: return NoneTyp() else: if is_subtype(t, self.s): return t elif is_subtype(self.s, t): # See also above comment. return self.s else: if experiments.STRICT_OPTIONAL: return UninhabitedType() else: return NoneTyp() elif isinstance(self.s, TypeType): return meet_types(t, self.s) else: return self.default(self.s)
def test_is_proper_subtype_and_subtype_literal_types(self) -> None: fx = self.fx lit1 = LiteralType(1, fx.a) lit2 = LiteralType("foo", fx.d) lit3 = LiteralType("bar", fx.d) assert_true(is_proper_subtype(lit1, fx.a)) assert_false(is_proper_subtype(lit1, fx.d)) assert_false(is_proper_subtype(fx.a, lit1)) assert_true(is_proper_subtype(fx.uninhabited, lit1)) assert_false(is_proper_subtype(lit1, fx.uninhabited)) assert_true(is_proper_subtype(lit1, lit1)) assert_false(is_proper_subtype(lit1, lit2)) assert_false(is_proper_subtype(lit2, lit3)) assert_true(is_subtype(lit1, fx.a)) assert_false(is_subtype(lit1, fx.d)) assert_false(is_subtype(fx.a, lit1)) assert_true(is_subtype(fx.uninhabited, lit1)) assert_false(is_subtype(lit1, fx.uninhabited)) assert_true(is_subtype(lit1, lit1)) assert_false(is_subtype(lit1, lit2)) assert_false(is_subtype(lit2, lit3)) assert_false(is_proper_subtype(lit1, fx.anyt)) assert_false(is_proper_subtype(fx.anyt, lit1)) assert_true(is_subtype(lit1, fx.anyt)) assert_true(is_subtype(fx.anyt, lit1))
def join_simple(declaration: Type, s: Type, t: Type) -> Type: """Return a simple least upper bound given the declared type.""" if isinstance(s, AnyType): return s if isinstance(s, NoneTyp) and not isinstance(t, Void): return t if isinstance(s, ErasedType): return t if is_subtype(s, t): return t if is_subtype(t, s): return s if isinstance(declaration, UnionType): return UnionType.make_simplified_union([s, t]) value = t.accept(TypeJoinVisitor(s)) if value is None: # XXX this code path probably should be avoided. # It seems to happen when a line (x = y) is a type error, and # it's not clear that assuming that x is arbitrary afterward # is a good idea. return declaration if declaration is None or is_subtype(value, declaration): return value return declaration
def join_instances(t: Instance, s: Instance) -> Type: """Calculate the join of two instance types. If allow_interfaces is True, also consider interface-type results for non-interface types. Return ErrorType if the result is ambiguous. """ if t.type == s.type: # Simplest case: join two types with the same base type (but # potentially different arguments). if is_subtype(t, s) or is_subtype(s, t): # Compatible; combine type arguments. args = [] # type: List[Type] for i in range(len(t.args)): args.append(join_types(t.args[i], s.args[i])) return Instance(t.type, args) else: # Incompatible; return trivial result object. return object_from_instance(t) elif t.type.bases and is_subtype_ignoring_tvars(t, s): return join_instances_via_supertype(t, s) else: # Now t is not a subtype of s, and t != s. Now s could be a subtype # of t; alternatively, we need to find a common supertype. This works # in of the both cases. return join_instances_via_supertype(s, t)
def array_constructor_callback(ctx: 'mypy.plugin.FunctionContext') -> Type: """Callback to provide an accurate signature for the ctypes.Array constructor.""" # Extract the element type from the constructor's return type, i. e. the type of the array # being constructed. et = _get_array_element_type(ctx.default_return_type) if et is not None: allowed = _autoconvertible_to_cdata(et, ctx.api) assert len(ctx.arg_types) == 1, \ "The stub of the ctypes.Array constructor should have a single vararg parameter" for arg_num, (arg_kind, arg_type) in enumerate(zip(ctx.arg_kinds[0], ctx.arg_types[0]), 1): if arg_kind == nodes.ARG_POS and not is_subtype(arg_type, allowed): ctx.api.msg.fail( 'Array constructor argument {} of type "{}"' ' is not convertible to the array element type "{}"' .format(arg_num, arg_type, et), ctx.context) elif arg_kind == nodes.ARG_STAR: ty = ctx.api.named_generic_type("typing.Iterable", [allowed]) if not is_subtype(arg_type, ty): ctx.api.msg.fail( 'Array constructor argument {} of type "{}"' ' is not convertible to the array element type "Iterable[{}]"' .format(arg_num, arg_type, et), ctx.context) return ctx.default_return_type
def join_instances(t: Instance, s: Instance, allow_interfaces: bool, basic: BasicTypes) -> Type: """Calculate the join of two instance types. If allow_interfaces is True, also consider interface-type results for non-interface types. Return ErrorType if the result is ambiguous. """ if t.type == s.type: # Simplest case: join two types with the same base type (but # potentially different arguments). if is_subtype(t, s): # Compatible; combine type arguments. args = [] # type: List[Type] for i in range(len(t.args)): args.append(join_types(t.args[i], s.args[i], basic)) return Instance(t.type, args) else: # Incompatible; return trivial result object. return basic.object elif t.type.bases and is_subtype(t, s): return join_instances_via_supertype(t, s, allow_interfaces, basic) elif s.type.bases: return join_instances_via_supertype(s, t, allow_interfaces, basic) elif allow_interfaces: return join_instances_as_interface(t, s, basic) else: return basic.object
def meet_simple_away(s: Type, t: Type) -> Type: if isinstance(s, UnionType): return UnionType.make_simplified_union([x for x in s.items if not is_subtype(x, t)]) elif not isinstance(s, AnyType) and is_subtype(s, t): return Void() else: return s
def assert_simple_join(self, s: Type, t: Type, join: Type) -> None: result = join_types(s, t) actual = str(result) expected = str(join) assert_equal(actual, expected, 'join({}, {}) == {{}} ({{}} expected)'.format(s, t)) assert_true(is_subtype(s, result), '{} not subtype of {}'.format(s, result)) assert_true(is_subtype(t, result), '{} not subtype of {}'.format(t, result))
def assert_simple_meet(self, s: Type, t: Type, meet: Type) -> None: result = meet_types(s, t) actual = str(result) expected = str(meet) assert_equal(actual, expected, 'meet({}, {}) == {{}} ({{}} expected)'.format(s, t)) assert_true(is_subtype(result, s), '{} not subtype of {}'.format(result, s)) assert_true(is_subtype(result, t), '{} not subtype of {}'.format(result, t))
def assert_simple_meet(self, s, t, meet): result = meet_types(s, t) actual = str(result) expected = str(meet) assert_equal(actual, expected, 'meet({}, {}) == {{}} ({{}} expected)'.format(s, t)) if not isinstance(s, ErrorType) and not isinstance(result, ErrorType): assert_true(is_subtype(result, s), '{} not subtype of {}'.format(result, s)) if not isinstance(t, ErrorType) and not isinstance(result, ErrorType): assert_true(is_subtype(result, t), '{} not subtype of {}'.format(result, t))
def assert_simple_join(self, s, t, join): result = join_types(s, t) actual = str(result) expected = str(join) assert_equal(actual, expected, 'join({}, {}) == {{}} ({{}} expected)'.format(s, t)) if not isinstance(s, ErrorType) and not isinstance(result, ErrorType): assert_true(is_subtype(s, result), '{} not subtype of {}'.format(s, result)) if not isinstance(t, ErrorType) and not isinstance(result, ErrorType): assert_true(is_subtype(t, result), '{} not subtype of {}'.format(t, result))
def check_method_type(functype: FunctionLike, itype: Instance, is_classmethod: bool, context: Context, msg: MessageBuilder) -> None: for item in functype.items(): if not item.arg_types or item.arg_kinds[0] not in (ARG_POS, ARG_STAR): # No positional first (self) argument (*args is okay). msg.invalid_method_type(item, context) elif not is_classmethod: # Check that self argument has type 'Any' or valid instance type. selfarg = item.arg_types[0] # If this is a method of a tuple class, correct for the fact that # we passed to typ.fallback in analyze_member_access. See #1432. if isinstance(selfarg, TupleType): selfarg = selfarg.fallback if not subtypes.is_subtype(selfarg, itype): msg.invalid_method_type(item, context) else: # Check that cls argument has type 'Any' or valid class type. # (This is sufficient for the current treatment of @classmethod, # but probably needs to be revisited when we implement Type[C] # or advanced variants of it like Type[<args>, C].) clsarg = item.arg_types[0] if isinstance(clsarg, CallableType) and clsarg.is_type_obj(): if not subtypes.is_equivalent(clsarg.ret_type, itype): msg.invalid_class_method_type(item, context) else: if not subtypes.is_equivalent(clsarg, AnyType()): msg.invalid_class_method_type(item, context)
def solve_constraints(vars, constraints, basic): """Solve type constraints. Return lower bound for each type variable or None if the variable could not be solved. """ # Collect a list of constraints for each type variable. cmap = {} for con in constraints: a = cmap.get(con.type_var, []) a.append(con) cmap[con.type_var] = a res = [] # Solve each type variable separately. for tvar in vars: bottom = None top = None # Process each contraint separely, and calculate the lower and upper # bounds based on constraints. Note that we assume that the contraint # targets do not have contraint references. for c in cmap.get(tvar, []): if c.op == SUPERTYPE_OF: if bottom is None: bottom = c.target else: bottom = join_types(bottom, c.target, basic) else: if top is None: top = c.target else: top = meet_types(top, c.target, basic) if top is None: if isinstance(bottom, Void): top = Void() else: top = basic.object if bottom is None: if isinstance(top, Void): bottom = Void() else: bottom = NoneTyp() if isinstance(top, Any) or isinstance(bottom, Any): top = Any() bottom = Any() # Pick the most specific type if it satisfies the constraints. if (not top or not bottom or is_subtype(bottom, top)) and ( not isinstance(top, ErrorType) and not isinstance(bottom, ErrorType)): res.append(bottom) else: res.append(None) return res
def _infer_type_from_left_and_inferred_right( api: SemanticAnalyzerPluginInterface, node: Var, left_hand_explicit_type: Optional[types.Type], python_type_for_type: Union[Instance, UnionType], ) -> Optional[Union[Instance, UnionType]]: """Validate type when a left hand annotation is present and we also could infer the right hand side:: attrname: SomeType = Column(SomeDBType) """ if not is_subtype(left_hand_explicit_type, python_type_for_type): descriptor = api.lookup("__sa_Mapped", node) effective_type = Instance(descriptor.node, [python_type_for_type]) msg = ("Left hand assignment '{}: {}' not compatible " "with ORM mapped expression of type {}") util.fail( api, msg.format( node.name, format_type(left_hand_explicit_type), format_type(effective_type), ), node, ) return left_hand_explicit_type
def visit_instance(self, t): if isinstance(self.s, Instance): return join_instances(t, self.s, True, self.basic) elif t.type == self.basic.std_type.type and is_subtype(self.s, t): return t else: return self.default(self.s)
def typed_dict_setdefault_callback(ctx: MethodContext) -> Type: """Type check TypedDict.setdefault and infer a precise return type.""" if (isinstance(ctx.type, TypedDictType) and len(ctx.arg_types) == 2 and len(ctx.arg_types[0]) == 1 and len(ctx.arg_types[1]) == 1): keys = try_getting_str_literals(ctx.args[0][0], ctx.arg_types[0][0]) if keys is None: ctx.api.fail(message_registry.TYPEDDICT_KEY_MUST_BE_STRING_LITERAL, ctx.context) return AnyType(TypeOfAny.from_error) default_type = ctx.arg_types[1][0] value_types = [] for key in keys: value_type = ctx.type.items.get(key) if value_type is None: ctx.api.msg.typeddict_key_not_found(ctx.type, key, ctx.context) return AnyType(TypeOfAny.from_error) # The signature_callback above can't always infer the right signature # (e.g. when the expression is a variable that happens to be a Literal str) # so we need to handle the check ourselves here and make sure the provided # default can be assigned to all key-value pairs we're updating. if not is_subtype(default_type, value_type): ctx.api.msg.typeddict_setdefault_arguments_inconsistent( default_type, value_type, ctx.context) return AnyType(TypeOfAny.from_error) value_types.append(value_type) return make_simplified_union(value_types) return ctx.default_return_type
def assign_type(self, expr: Expression, type: Type, declared_type: Type, restrict_any: bool = False) -> None: if not expr.literal: return self.invalidate_dependencies(expr) if declared_type is None: # Not sure why this happens. It seems to mainly happen in # member initialization. return if not is_subtype(type, declared_type): # Pretty sure this is only happens when there's a type error. # Ideally this function wouldn't be called if the # expression has a type error, though -- do other kinds of # errors cause this function to get called at invalid # times? return # If x is Any and y is int, after x = y we do not infer that x is int. # This could be changed. if isinstance(self.most_recent_enclosing_type(expr, type), AnyType) and not restrict_any: pass elif isinstance(type, AnyType): self.push(expr, declared_type) else: self.push(expr, type) for i in self.try_frames: # XXX This should probably not copy the entire frame, but # just copy this variable into a single stored frame. self.allow_jump(i)
def visit_instance(self, t: Instance) -> None: # Type argument counts were checked in the main semantic analyzer pass. We assume # that the counts are correct here. info = t.type for (i, arg), tvar in zip(enumerate(t.args), info.defn.type_vars): if tvar.values: if isinstance(arg, TypeVarType): arg_values = arg.values if not arg_values: self.fail('Type variable "{}" not valid as type ' 'argument value for "{}"'.format( arg.name, info.name), t, code=codes.TYPE_VAR) continue else: arg_values = [arg] self.check_type_var_values(info, arg_values, tvar.name, tvar.values, i + 1, t) if not is_subtype(arg, tvar.upper_bound): self.fail('Type argument "{}" of "{}" must be ' 'a subtype of "{}"'.format(arg, info.name, tvar.upper_bound), t, code=codes.TYPE_VAR) super().visit_instance(t)
def check_self_arg(functype: FunctionLike, dispatched_arg_type: Type, is_classmethod: bool, context: Context, name: str, msg: MessageBuilder) -> None: """For x.f where A.f: A1 -> T, check that meet(type(x), A) <: A1 for each overload. dispatched_arg_type is meet(B, A) in the following example def g(x: B): x.f class A: f: Callable[[A1], None] """ # TODO: this is too strict. We can return filtered overloads for matching definitions for item in functype.items(): if not item.arg_types or item.arg_kinds[0] not in (ARG_POS, ARG_STAR): # No positional first (self) argument (*args is okay). msg.no_formal_self(name, item, context) else: selfarg = item.arg_types[0] if is_classmethod: dispatched_arg_type = TypeType.make_normalized( dispatched_arg_type) if not subtypes.is_subtype(dispatched_arg_type, erase_to_bound(selfarg)): msg.incompatible_self_argument(name, dispatched_arg_type, item, is_classmethod, context)
def make_simplified_union(items: List[Type], line: int = -1) -> Type: while any(isinstance(typ, UnionType) for typ in items): all_items = [] # type: List[Type] for typ in items: if isinstance(typ, UnionType): all_items.extend(typ.items) else: all_items.append(typ) items = all_items if any(isinstance(typ, AnyType) for typ in items): return AnyType() from mypy.subtypes import is_subtype removed = set() # type: Set[int] for i in range(len(items)): if any( is_subtype(items[i], items[j]) for j in range(len(items)) if j not in removed and j != i): removed.add(i) simplified_set = [ items[i] for i in range(len(items)) if i not in removed ] return UnionType.make_union(simplified_set)
def perform_special_format_checks(self, spec: ConversionSpecifier, call: CallExpr, repl: Expression, actual_type: Type, expected_type: Type) -> None: # TODO: try refactoring to combine this logic with % formatting. if spec.type == 'c': if isinstance(repl, (StrExpr, BytesExpr)) and len(repl.value) != 1: self.msg.requires_int_or_char(call, format_call=True) c_typ = get_proper_type(self.chk.type_map[repl]) if isinstance(c_typ, Instance) and c_typ.last_known_value: c_typ = c_typ.last_known_value if isinstance(c_typ, LiteralType) and isinstance(c_typ.value, str): if len(c_typ.value) != 1: self.msg.requires_int_or_char(call, format_call=True) if (not spec.type or spec.type == 's') and not spec.conversion: if self.chk.options.python_version >= (3, 0): if has_type_component(actual_type, 'builtins.bytes'): self.msg.fail( "On Python 3 '{}'.format(b'abc') produces \"b'abc'\";" " use !r if this is a desired behavior", call, code=codes.STR_BYTES_PY3) if spec.flags: numeric_types = UnionType([ self.named_type('builtins.int'), self.named_type('builtins.float') ]) if (spec.type and spec.type not in NUMERIC_TYPES_NEW or not spec.type and not is_subtype(actual_type, numeric_types) and not custom_special_method(actual_type, '__format__')): self.msg.fail( 'Numeric flags are only allowed for numeric types', call, code=codes.STRING_FORMATTING)
def visit_literal_type(self, t: LiteralType) -> Type: if isinstance(self.s, LiteralType) and self.s == t: return t elif isinstance(self.s, Instance) and is_subtype(t.fallback, self.s): return t else: return self.default(self.s)
def register_function(ctx: PluginContext, singledispatch_obj: Instance, func: Type, register_arg: Optional[Type] = None) -> None: """Register a function""" func = get_proper_type(func) if not isinstance(func, CallableType): return metadata = get_singledispatch_info(singledispatch_obj) if metadata is None: # if we never added the fallback to the type variables, we already reported an error, so # just don't do anything here return dispatch_type = get_dispatch_type(func, register_arg) if dispatch_type is None: # TODO: report an error here that singledispatch requires at least one argument # (might want to do the error reporting in get_dispatch_type) return fallback = metadata.fallback fallback_dispatch_type = fallback.arg_types[0] if not is_subtype(dispatch_type, fallback_dispatch_type): fail(ctx, 'Dispatch type {} must be subtype of fallback function first argument {}'.format( format_type(dispatch_type), format_type(fallback_dispatch_type) ), func.definition) return return
def visit_mapping_pattern(self, o: MappingPattern) -> PatternType: current_type = get_proper_type(self.type_context[-1]) can_match = True captures: Dict[Expression, Type] = {} for key, value in zip(o.keys, o.values): inner_type = self.get_mapping_item_type(o, current_type, key) if inner_type is None: can_match = False inner_type = self.chk.named_type("builtins.object") pattern_type = self.accept(value, inner_type) if is_uninhabited(pattern_type.type): can_match = False else: self.update_type_map(captures, pattern_type.captures) if o.rest is not None: mapping = self.chk.named_type("typing.Mapping") if is_subtype(current_type, mapping) and isinstance(current_type, Instance): mapping_inst = map_instance_to_supertype(current_type, mapping.type) dict_typeinfo = self.chk.lookup_typeinfo("builtins.dict") dict_type = fill_typevars(dict_typeinfo) rest_type = expand_type_by_instance(dict_type, mapping_inst) else: object_type = self.chk.named_type("builtins.object") rest_type = self.chk.named_generic_type("builtins.dict", [object_type, object_type]) captures[o.rest] = rest_type if can_match: # We can't narrow the type here, as Mapping key is invariant. new_type = self.type_context[-1] else: new_type = UninhabitedType() return PatternType(new_type, current_type, captures)
def construct_sequence_child(self, outer_type: Type, inner_type: Type) -> Type: """ If outer_type is a child class of typing.Sequence returns a new instance of outer_type, that is a Sequence of inner_type. If outer_type is not a child class of typing.Sequence just returns a Sequence of inner_type For example: construct_sequence_child(List[int], str) = List[str] """ proper_type = get_proper_type(outer_type) if isinstance(proper_type, UnionType): types = [ self.construct_sequence_child(item, inner_type) for item in proper_type.items if self.can_match_sequence(get_proper_type(item)) ] return make_simplified_union(types) sequence = self.chk.named_generic_type("typing.Sequence", [inner_type]) if is_subtype(outer_type, self.chk.named_type("typing.Sequence")): proper_type = get_proper_type(outer_type) assert isinstance(proper_type, Instance) empty_type = fill_typevars(proper_type.type) partial_type = expand_type_by_instance(empty_type, sequence) return expand_type_by_instance(partial_type, proper_type) else: return sequence
def make_simplified_union(items: List[Type], line: int = -1) -> Type: while any(isinstance(typ, UnionType) for typ in items): all_items = [] # type: List[Type] for typ in items: if isinstance(typ, UnionType): all_items.extend(typ.items) else: all_items.append(typ) items = all_items if any(isinstance(typ, AnyType) for typ in items): return AnyType() from mypy.subtypes import is_subtype removed = set() # type: Set[int] for i, ti in enumerate(items): if i in removed: continue # Keep track of the truishness info for deleted subtypes which can be relevant cbt = cbf = False for j, tj in enumerate(items): if i != j and is_subtype(tj, ti): removed.add(j) cbt = cbt or tj.can_be_true cbf = cbf or tj.can_be_false # if deleted subtypes had more general truthiness, use that if not ti.can_be_true and cbt: items[i] = true_or_false(ti) elif not ti.can_be_false and cbf: items[i] = true_or_false(ti) simplified_set = [items[i] for i in range(len(items)) if i not in removed] return UnionType.make_union(simplified_set)
def visit_literal_type(self, t: LiteralType) -> Type: if isinstance(self.s, LiteralType): return LiteralType(self.join(self.s.base, t.base), line=t.line) elif is_subtype(self.s, t.base): return t.base else: return self.join(self.s, t.base)
def class_callable(init_type: CallableType, info: TypeInfo, type_type: Instance, special_sig: Optional[str], is_new: bool, orig_self_type: Optional[Type] = None) -> CallableType: """Create a type object type based on the signature of __init__.""" variables = [] # type: List[TypeVarDef] variables.extend(info.defn.type_vars) variables.extend(init_type.variables) from mypy.subtypes import is_subtype init_ret_type = get_proper_type(init_type.ret_type) orig_self_type = get_proper_type(orig_self_type) default_ret_type = fill_typevars(info) explicit_type = init_ret_type if is_new else orig_self_type if (isinstance(explicit_type, (Instance, TupleType)) # Only use the declared return type from __new__ or declared self in __init__ # if it is actually returning a subtype of what we would return otherwise. and is_subtype( explicit_type, default_ret_type, ignore_type_params=True)): ret_type = explicit_type # type: Type else: ret_type = default_ret_type callable_type = init_type.copy_modified(ret_type=ret_type, fallback=type_type, name=None, variables=variables, special_sig=special_sig) c = callable_type.with_name(info.name) return c
def visit_instance(self, t: Instance) -> Type: if isinstance(self.s, Instance): return join_instances(t, cast(Instance, self.s), self.basic) elif t.type == self.basic.type_type.type and is_subtype(self.s, t): return t else: return self.default(self.s)
def check_self_arg(functype: FunctionLike, dispatched_arg_type: Type, is_classmethod: bool, context: Context, name: str, msg: MessageBuilder) -> None: """For x.f where A.f: A1 -> T, check that meet(type(x), A) <: A1 for each overload. dispatched_arg_type is meet(B, A) in the following example def g(x: B): x.f class A: f: Callable[[A1], None] """ # TODO: this is too strict. We can return filtered overloads for matching definitions for item in functype.items(): if not item.arg_types or item.arg_kinds[0] not in (ARG_POS, ARG_STAR): # No positional first (self) argument (*args is okay). msg.no_formal_self(name, item, context) else: selfarg = item.arg_types[0] if is_classmethod: dispatched_arg_type = TypeType.make_normalized(dispatched_arg_type) if not subtypes.is_subtype(dispatched_arg_type, erase_to_bound(selfarg)): msg.incompatible_self_argument(name, dispatched_arg_type, item, is_classmethod, context)
def visit_instance(self, t: Instance) -> Type: if isinstance(self.s, Instance): return join_instances(t, cast(Instance, self.s)) elif t.type.fullname() == 'builtins.type' and is_subtype(self.s, t): return t else: return self.default(self.s)
def visit_instance(self, t: Instance) -> None: # Type argument counts were checked in the main semantic analyzer pass. We assume # that the counts are correct here. info = t.type if isinstance(info, FakeInfo): return # https://github.com/python/mypy/issues/11079 for (i, arg), tvar in zip(enumerate(t.args), info.defn.type_vars): if isinstance(tvar, TypeVarType): if isinstance(arg, ParamSpecType): # TODO: Better message self.fail(f'Invalid location for ParamSpec "{arg.name}"', t) continue if tvar.values: if isinstance(arg, TypeVarType): arg_values = arg.values if not arg_values: self.fail(message_registry. INVALID_TYPEVAR_AS_TYPEARG.format( arg.name, info.name), t, code=codes.TYPE_VAR) continue else: arg_values = [arg] self.check_type_var_values(info, arg_values, tvar.name, tvar.values, i + 1, t) if not is_subtype(arg, tvar.upper_bound): self.fail( message_registry.INVALID_TYPEVAR_ARG_BOUND.format( format_type(arg), info.name, format_type(tvar.upper_bound)), t, code=codes.TYPE_VAR) super().visit_instance(t)
def check_exception_type(self, info, context): t = Instance(info, []) if is_subtype(t, self.named_type('builtins.BaseException')): return t else: self.fail(messages.INVALID_EXCEPTION_TYPE, context) return Any()
def visit_instance(self, t: Instance) -> ProperType: if isinstance(self.s, Instance): si = self.s if t.type == si.type: if is_subtype(t, self.s) or is_subtype(self.s, t): # Combine type arguments. We could have used join below # equivalently. args = [] # type: List[Type] # N.B: We use zip instead of indexing because the lengths might have # mismatches during daemon reprocessing. for ta, sia in zip(t.args, si.args): args.append(self.meet(ta, sia)) return Instance(t.type, args) else: if state.strict_optional: return UninhabitedType() else: return NoneType() else: if is_subtype(t, self.s): return t elif is_subtype(self.s, t): # See also above comment. return self.s else: if state.strict_optional: return UninhabitedType() else: return NoneType() elif isinstance(self.s, FunctionLike) and t.type.is_protocol: call = unpack_callback_protocol(t) if call: return meet_types(call, self.s) elif isinstance(self.s, FunctionLike) and self.s.is_type_obj( ) and t.type.is_metaclass(): if is_subtype(self.s.fallback, t): return self.s return self.default(self.s) elif isinstance(self.s, TypeType): return meet_types(t, self.s) elif isinstance(self.s, TupleType): return meet_types(t, self.s) elif isinstance(self.s, LiteralType): return meet_types(t, self.s) elif isinstance(self.s, TypedDictType): return meet_types(t, self.s) return self.default(self.s)
def solve_constraints(vars: List[TypeVarId], constraints: List[Constraint], strict: bool =True) -> List[Type]: """Solve type constraints. Return the best type(s) for type variables; each type can be None if the value of the variable could not be solved. If a variable has no constraints, if strict=True then arbitrarily pick NoneTyp as the value of the type variable. If strict=False, pick AnyType. """ # Collect a list of constraints for each type variable. cmap = defaultdict(list) # type: Dict[TypeVarId, List[Constraint]] for con in constraints: cmap[con.type_var].append(con) res = [] # type: List[Type] # Solve each type variable separately. for tvar in vars: bottom = None # type: Type top = None # type: Type # Process each constraint separately, and calculate the lower and upper # bounds based on constraints. Note that we assume that the constraint # targets do not have constraint references. for c in cmap.get(tvar, []): if c.op == SUPERTYPE_OF: if bottom is None: bottom = c.target else: bottom = join_types(bottom, c.target) else: if top is None: top = c.target else: top = meet_types(top, c.target) if isinstance(top, AnyType) or isinstance(bottom, AnyType): res.append(AnyType()) continue elif bottom is None: if top: candidate = top else: # No constraints for type variable -- 'UninhabitedType' is the most specific type. if strict: candidate = UninhabitedType() else: candidate = AnyType() elif top is None: candidate = bottom elif is_subtype(bottom, top): candidate = bottom else: candidate = None res.append(candidate) return res
def join_instances_via_supertype(t: Instance, s: Instance) -> Type: # Give preference to joins via duck typing relationship, so that # join(int, float) == float, for example. if t.type._promote and is_subtype(t.type._promote, s): return join_types(t.type._promote, s) elif s.type._promote and is_subtype(s.type._promote, t): return join_types(t, s.type._promote) res = s mapped = map_instance_to_supertype(t, t.type.bases[0].type) join = join_instances(mapped, res) # If the join failed, fail. This is a defensive measure (this might # never happen). if isinstance(join, ErrorType): return join # Now the result must be an Instance, so the cast below cannot fail. res = cast(Instance, join) return res
def most_recent_enclosing_type(self, expr: Node, type: Type) -> Type: if isinstance(type, AnyType): return self.get_declaration(expr) key = expr.literal_hash enclosers = ([self.get_declaration(expr)] + [f[key] for f in self.frames if key in f and is_subtype(type, f[key])]) return enclosers[-1]
def check_subtype(self, subtype, supertype, context, msg=messages.INCOMPATIBLE_TYPES): """Generate an error if the subtype is not compatible with supertype.""" if not is_subtype(subtype, supertype): if isinstance(subtype, Void): self.msg.does_not_return_value(subtype, context) else: self.fail(msg, context)
def most_recent_enclosing_type(self, expr: Expression, type: Type) -> Type: if isinstance(type, AnyType): return self.get_declaration(expr) key = expr.literal_hash enclosers = [self.get_declaration(expr)] + [ f[key] for f in self.frames if key in f and is_subtype(type, f[key]) ] return enclosers[-1]
def should_self_match(self, typ: Type) -> bool: typ = get_proper_type(typ) if isinstance(typ, Instance) and typ.type.is_named_tuple: return False for other in self.self_match_types: if is_subtype(typ, other): return True return False
def check_simple_str_interpolation(self, specifiers: List[ConversionSpecifier], replacements: Expression, expr: FormatStringExpr) -> None: """Check % string interpolation with positional specifiers '%s, %d' % ('yes, 42').""" checkers = self.build_replacement_checkers(specifiers, replacements, expr) if checkers is None: return rhs_type = get_proper_type(self.accept(replacements)) rep_types: List[Type] = [] if isinstance(rhs_type, TupleType): rep_types = rhs_type.items elif isinstance(rhs_type, AnyType): return elif isinstance( rhs_type, Instance) and rhs_type.type.fullname == 'builtins.tuple': # Assume that an arbitrary-length tuple has the right number of items. rep_types = [rhs_type.args[0]] * len(checkers) elif isinstance(rhs_type, UnionType): for typ in rhs_type.relevant_items(): temp_node = TempNode(typ) temp_node.line = replacements.line self.check_simple_str_interpolation(specifiers, temp_node, expr) return else: rep_types = [rhs_type] if len(checkers) > len(rep_types): # Only check the fix-length Tuple type. Other Iterable types would skip. if (is_subtype(rhs_type, self.chk.named_type("typing.Iterable")) and not isinstance(rhs_type, TupleType)): return else: self.msg.too_few_string_formatting_arguments(replacements) elif len(checkers) < len(rep_types): self.msg.too_many_string_formatting_arguments(replacements) else: if len(checkers) == 1: check_node, check_type = checkers[0] if isinstance(rhs_type, TupleType) and len( rhs_type.items) == 1: check_type(rhs_type.items[0]) else: check_node(replacements) elif (isinstance(replacements, TupleExpr) and not any( isinstance(item, StarExpr) for item in replacements.items)): for checks, rep_node in zip(checkers, replacements.items): check_node, check_type = checks check_node(rep_node) else: for checks, rep_type in zip(checkers, rep_types): check_node, check_type = checks check_type(rep_type)
def solve_constraints(vars: List[int], constraints: List[Constraint], basic: BasicTypes) -> List[Type]: """Solve type constraints. Return the best type(s) for type variables; each type can be None if the value of the variable could not be solved. If a variable has no constraints, arbitrarily pick NoneTyp as the value of the type variable. """ # Collect a list of constraints for each type variable. cmap = Dict[int, List[Constraint]]() for con in constraints: a = cmap.get(con.type_var, []) a.append(con) cmap[con.type_var] = a res = [] # type: List[Type] # Solve each type variable separately. for tvar in vars: bottom = None # type: Type top = None # type: Type # Process each contraint separely, and calculate the lower and upper # bounds based on constraints. Note that we assume that the constraint # targets do not have constraint references. for c in cmap.get(tvar, []): if c.op == SUPERTYPE_OF: if bottom is None: bottom = c.target else: bottom = join_types(bottom, c.target, basic) else: if top is None: top = c.target else: top = meet_types(top, c.target, basic) if isinstance(top, AnyType) or isinstance(bottom, AnyType): res.append(AnyType()) continue elif bottom is None: if top: candidate = top else: # No constraints for type variable -- type 'None' is the most specific type. candidate = NoneTyp() elif top is None: candidate = bottom elif is_subtype(bottom, top): candidate = bottom else: candidate = None if isinstance(candidate, ErrorType): res.append(None) else: res.append(candidate) return res
def visit_instance(self, t: Instance) -> ProperType: if isinstance(self.s, Instance): si = self.s if t.type == si.type: if is_subtype(t, self.s) or is_subtype(self.s, t): # Combine type arguments. We could have used join below # equivalently. args = [] # type: List[Type] for i in range(len(t.args)): args.append(self.meet(t.args[i], si.args[i])) return Instance(t.type, args) else: if state.strict_optional: return UninhabitedType() else: return NoneType() else: if is_subtype(t, self.s): return t elif is_subtype(self.s, t): # See also above comment. return self.s else: if state.strict_optional: return UninhabitedType() else: return NoneType() elif isinstance(self.s, FunctionLike) and t.type.is_protocol: call = unpack_callback_protocol(t) if call: return meet_types(call, self.s) elif isinstance(self.s, FunctionLike) and self.s.is_type_obj( ) and t.type.is_metaclass(): if is_subtype(self.s.fallback, t): return self.s return self.default(self.s) elif isinstance(self.s, TypeType): return meet_types(t, self.s) elif isinstance(self.s, TupleType): return meet_types(t, self.s) elif isinstance(self.s, LiteralType): return meet_types(t, self.s) elif isinstance(self.s, TypedDictType): return meet_types(t, self.s) return self.default(self.s)
def join_instances_via_supertype(t: Instance, s: Instance) -> Type: # Give preference to joins via duck typing relationship, so that # join(int, float) == float, for example. if t.type._promote and is_subtype(t.type._promote, s): return join_types(t.type._promote, s) elif s.type._promote and is_subtype(s.type._promote, t): return join_types(t, s.type._promote) # Compute the "best" supertype of t when joined with s. # The definition of "best" may evolve; for now it is the one with # the longest MRO. Ties are broken by using the earlier base. best = None # type: Optional[Type] for base in t.type.bases: mapped = map_instance_to_supertype(t, base.type) res = join_instances(mapped, s) if best is None or is_better(res, best): best = res assert best is not None return best
def is_ndarray_of_bools(typ: Type): if not isinstance(typ, Instance): return False return is_subtype( typ, API.named_generic_type( 'numpy.ndarray', args=[bool_type(), API.named_type('numpy._Dimension')])) and ( not is_same_type(typ.args[1], AnyType(TypeOfAny.unannotated)))
def join_instances_via_supertype(t: Instance, s: Instance) -> Type: # Give preference to joins via duck typing relationship, so that # join(int, float) == float, for example. if t.type._promote and is_subtype(t.type._promote, s): return join_types(t.type._promote, s) elif s.type._promote and is_subtype(s.type._promote, t): return join_types(t, s.type._promote) # Compute the "best" supertype of t when joined with s. # The definition of "best" may evolve; for now it is the one with # the longest MRO. Ties are broken by using the earlier base. best = None # type: Type for base in t.type.bases: mapped = map_instance_to_supertype(t, base.type) res = join_instances(mapped, s) if best is None or is_better(res, best): best = res assert best is not None return best
def visit_overloaded(self, t: Overloaded) -> Type: # TODO: Implement a better algorithm that covers at least the same cases # as TypeJoinVisitor.visit_overloaded(). s = self.s if isinstance(s, FunctionLike): if s.items() == t.items(): return Overloaded(t.items()) elif is_subtype(s, t): return s elif is_subtype(t, s): return t else: return meet_types(t.fallback, s.fallback) elif isinstance(self.s, Instance) and self.s.type.is_protocol: call = unpack_callback_protocol(self.s) if call: return meet_types(t, call) return meet_types(t.fallback, s)
def visit_instance(self, t: Instance) -> None: info = t.type # Check type argument count. if len(t.args) != len(info.type_vars): if len(t.args) == 0: from_builtins = t.type.fullname() in nongen_builtins and not t.from_generic_builtin if ('generics' in self.options.disallow_any and not self.is_typeshed_stub and from_builtins): alternative = nongen_builtins[t.type.fullname()] self.fail(messages.IMPLICIT_GENERIC_ANY_BUILTIN.format(alternative), t) # Insert implicit 'Any' type arguments. any_type = AnyType(from_omitted_generics=not from_builtins, line=t.line, column=t.line) t.args = [any_type] * len(info.type_vars) return # Invalid number of type parameters. n = len(info.type_vars) s = '{} type arguments'.format(n) if n == 0: s = 'no type arguments' elif n == 1: s = '1 type argument' act = str(len(t.args)) if act == '0': act = 'none' self.fail('"{}" expects {}, but {} given'.format( info.name(), s, act), t) # Construct the correct number of type arguments, as # otherwise the type checker may crash as it expects # things to be right. t.args = [AnyType() for _ in info.type_vars] t.invalid = True elif info.defn.type_vars: # Check type argument values. for (i, arg), tvar in zip(enumerate(t.args), info.defn.type_vars): if tvar.values: if isinstance(arg, TypeVarType): arg_values = arg.values if not arg_values: self.fail('Type variable "{}" not valid as type ' 'argument value for "{}"'.format( arg.name, info.name()), t) continue else: arg_values = [arg] self.check_type_var_values(info, arg_values, tvar.values, i + 1, t) if not is_subtype(arg, tvar.upper_bound): self.fail('Type argument "{}" of "{}" must be ' 'a subtype of "{}"'.format( arg, info.name(), tvar.upper_bound), t) for arg in t.args: arg.accept(self) if info.is_newtype: for base in info.bases: base.accept(self)
def most_recent_enclosing_type(self, expr: BindableExpression, type: Type) -> Optional[Type]: if isinstance(type, AnyType): return get_declaration(expr) key = literal_hash(expr) assert key is not None enclosers = ([get_declaration(expr)] + [f[key] for f in self.frames if key in f and is_subtype(type, f[key])]) return enclosers[-1]
def join_instances(self, t: Instance, s: Instance) -> ProperType: if (t, s) in self.seen_instances or (s, t) in self.seen_instances: return object_from_instance(t) self.seen_instances.append((t, s)) """Calculate the join of two instance types.""" if t.type == s.type: # Simplest case: join two types with the same base type (but # potentially different arguments). # Combine type arguments. args: List[Type] = [] # N.B: We use zip instead of indexing because the lengths might have # mismatches during daemon reprocessing. for ta, sa, type_var in zip(t.args, s.args, t.type.defn.type_vars): ta_proper = get_proper_type(ta) sa_proper = get_proper_type(sa) new_type: Optional[Type] = None if isinstance(ta_proper, AnyType): new_type = AnyType(TypeOfAny.from_another_any, ta_proper) elif isinstance(sa_proper, AnyType): new_type = AnyType(TypeOfAny.from_another_any, sa_proper) elif type_var.variance == COVARIANT: new_type = join_types(ta, sa, self) if len(type_var.values ) != 0 and new_type not in type_var.values: self.seen_instances.pop() return object_from_instance(t) if not is_subtype(new_type, type_var.upper_bound): self.seen_instances.pop() return object_from_instance(t) elif type_var.variance == CONTRAVARIANT: new_type = meet.meet_types(ta, sa) if len(type_var.values ) != 0 and new_type not in type_var.values: self.seen_instances.pop() return object_from_instance(t) # No need to check subtype, as ta and sa already have to be subtypes of # upper_bound elif type_var.variance == INVARIANT: new_type = join_types(ta, sa) if not is_equivalent(ta, sa): self.seen_instances.pop() return object_from_instance(t) assert new_type is not None args.append(new_type) result: ProperType = Instance(t.type, args) elif t.type.bases and is_subtype_ignoring_tvars(t, s): result = self.join_instances_via_supertype(t, s) else: # Now t is not a subtype of s, and t != s. Now s could be a subtype # of t; alternatively, we need to find a common supertype. This works # in of the both cases. result = self.join_instances_via_supertype(s, t) self.seen_instances.pop() return result
def most_recent_enclosing_type(self, expr: BindableExpression, type: Type) -> Optional[Type]: if isinstance(type, AnyType): return get_declaration(expr) key = literal_hash(expr) assert key is not None enclosers = ([get_declaration(expr)] + [f.types[key] for f in self.frames if key in f.types and is_subtype(type, f.types[key])]) return enclosers[-1]
def visit_overloaded(self, t: Overloaded) -> ProperType: # TODO: Implement a better algorithm that covers at least the same cases # as TypeJoinVisitor.visit_overloaded(). s = self.s if isinstance(s, FunctionLike): if s.items() == t.items(): return Overloaded(t.items()) elif is_subtype(s, t): return s elif is_subtype(t, s): return t else: return meet_types(t.fallback, s.fallback) elif isinstance(self.s, Instance) and self.s.type.is_protocol: call = unpack_callback_protocol(self.s) if call: return meet_types(t, call) return meet_types(t.fallback, s)
def is_ndarray(typ: Type): if not isinstance(typ, Instance): return False return is_subtype( typ, API.named_generic_type('numpy.ndarray', args=[ AnyType(TypeOfAny.unannotated), AnyType(TypeOfAny.unannotated) ]))
def join_simple(declaration: Type, s: Type, t: Type) -> Type: """Return a simple least upper bound given the declared type.""" if (s.can_be_true, s.can_be_false) != (t.can_be_true, t.can_be_false): # if types are restricted in different ways, use the more general versions s = true_or_false(s) t = true_or_false(t) if isinstance(s, AnyType): return s if isinstance(s, ErasedType): return t if is_subtype(s, t): return t if is_subtype(t, s): return s if isinstance(declaration, UnionType): return UnionType.make_simplified_union([s, t]) if isinstance(s, NoneTyp) and not isinstance(t, NoneTyp): s, t = t, s if isinstance(s, UninhabitedType) and not isinstance(t, UninhabitedType): s, t = t, s value = t.accept(TypeJoinVisitor(s)) if value is None: # XXX this code path probably should be avoided. # It seems to happen when a line (x = y) is a type error, and # it's not clear that assuming that x is arbitrary afterward # is a good idea. return declaration if declaration is None or is_subtype(value, declaration): return value return declaration
def visit_callable_type(self, t: CallableType) -> Type: if isinstance(self.s, CallableType) and is_similar_callables( t, cast(CallableType, self.s)): return combine_similar_callables(t, cast(CallableType, self.s)) elif t.is_type_obj() and is_subtype(self.s, t.fallback): return t.fallback elif (t.is_type_obj() and isinstance(self.s, Instance) and cast(Instance, self.s).type == t.fallback): return t.fallback else: return self.default(self.s)