Repository URL to install this package:
|
Version:
0.630 ▾
|
mypy
/
sametypes.py
|
|---|
from typing import Sequence
from mypy.types import (
Type, UnboundType, AnyType, NoneTyp, TupleType, TypedDictType,
UnionType, CallableType, TypeVarType, Instance, TypeVisitor, ErasedType,
Overloaded, PartialType, DeletedType, UninhabitedType, TypeType
)
def is_same_type(left: Type, right: Type) -> bool:
"""Is 'left' the same type as 'right'?"""
if isinstance(right, UnboundType):
# Make unbound types same as anything else to reduce the number of
# generated spurious error messages.
return True
else:
# Simplify types to canonical forms.
#
# There are multiple possible union types that represent the same type,
# such as Union[int, bool, str] and Union[int, str]. Also, some union
# types can be simplified to non-union types such as Union[int, bool]
# -> int. It would be nice if we always had simplified union types but
# this is currently not the case, though it often is.
left = simplify_union(left)
right = simplify_union(right)
return left.accept(SameTypeVisitor(right))
def simplify_union(t: Type) -> Type:
if isinstance(t, UnionType):
return UnionType.make_simplified_union(t.items)
return t
def is_same_types(a1: Sequence[Type], a2: Sequence[Type]) -> bool:
if len(a1) != len(a2):
return False
for i in range(len(a1)):
if not is_same_type(a1[i], a2[i]):
return False
return True
class SameTypeVisitor(TypeVisitor[bool]):
"""Visitor for checking whether two types are the 'same' type."""
def __init__(self, right: Type) -> None:
self.right = right
# visit_x(left) means: is left (which is an instance of X) the same type as
# right?
def visit_unbound_type(self, left: UnboundType) -> bool:
return True
def visit_any(self, left: AnyType) -> bool:
return isinstance(self.right, AnyType)
def visit_none_type(self, left: NoneTyp) -> bool:
return isinstance(self.right, NoneTyp)
def visit_uninhabited_type(self, t: UninhabitedType) -> bool:
return isinstance(self.right, UninhabitedType)
def visit_erased_type(self, left: ErasedType) -> bool:
# We can get here when isinstance is used inside a lambda
# whose type is being inferred. In any event, we have no reason
# to think that an ErasedType will end up being the same as
# any other type, except another ErasedType (for protocols).
return isinstance(self.right, ErasedType)
def visit_deleted_type(self, left: DeletedType) -> bool:
return isinstance(self.right, DeletedType)
def visit_instance(self, left: Instance) -> bool:
return (isinstance(self.right, Instance) and
left.type == self.right.type and
is_same_types(left.args, self.right.args))
def visit_type_var(self, left: TypeVarType) -> bool:
return (isinstance(self.right, TypeVarType) and
left.id == self.right.id)
def visit_callable_type(self, left: CallableType) -> bool:
# FIX generics
if isinstance(self.right, CallableType):
cright = self.right
return (is_same_type(left.ret_type, cright.ret_type) and
is_same_types(left.arg_types, cright.arg_types) and
left.arg_names == cright.arg_names and
left.arg_kinds == cright.arg_kinds and
left.is_type_obj() == cright.is_type_obj() and
left.is_ellipsis_args == cright.is_ellipsis_args)
else:
return False
def visit_tuple_type(self, left: TupleType) -> bool:
if isinstance(self.right, TupleType):
return (is_same_type(left.fallback, self.right.fallback)
and is_same_types(left.items, self.right.items))
else:
return False
def visit_typeddict_type(self, left: TypedDictType) -> bool:
if isinstance(self.right, TypedDictType):
if left.items.keys() != self.right.items.keys():
return False
for (_, left_item_type, right_item_type) in left.zip(self.right):
if not is_same_type(left_item_type, right_item_type):
return False
return True
else:
return False
def visit_union_type(self, left: UnionType) -> bool:
if isinstance(self.right, UnionType):
# Check that everything in left is in right
for left_item in left.items:
if not any(is_same_type(left_item, right_item) for right_item in self.right.items):
return False
# Check that everything in right is in left
for right_item in self.right.items:
if not any(is_same_type(right_item, left_item) for left_item in left.items):
return False
return True
else:
return False
def visit_overloaded(self, left: Overloaded) -> bool:
if isinstance(self.right, Overloaded):
return is_same_types(left.items(), self.right.items())
else:
return False
def visit_partial_type(self, left: PartialType) -> bool:
# A partial type is not fully defined, so the result is indeterminate. We shouldn't
# get here.
raise RuntimeError
def visit_type_type(self, left: TypeType) -> bool:
if isinstance(self.right, TypeType):
return is_same_type(left.item, self.right.item)
else:
return False