Skip to content

Refactor is_named_instance and refers_to_fullname #11961

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions mypy/constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
TupleType, TypedDictType, UnionType, Overloaded, ErasedType, PartialType, DeletedType,
UninhabitedType, TypeType, TypeVarId, TypeQuery, is_named_instance, TypeOfAny, LiteralType,
ProperType, ParamSpecType, get_proper_type, TypeAliasType, is_union_with_any,
callable_with_ellipsis
callable_with_ellipsis,
TUPLE_LIKE_INSTANCE_NAMES,
)
from mypy.maptype import map_instance_to_supertype
import mypy.subtypes
Expand Down Expand Up @@ -501,11 +502,8 @@ def visit_instance(self, template: Instance) -> List[Constraint]:
return res
if isinstance(actual, AnyType):
return self.infer_against_any(template.args, actual)
if (isinstance(actual, TupleType) and
(is_named_instance(template, 'typing.Iterable') or
is_named_instance(template, 'typing.Container') or
is_named_instance(template, 'typing.Sequence') or
is_named_instance(template, 'typing.Reversible'))
if (isinstance(actual, TupleType)
and is_named_instance(template, TUPLE_LIKE_INSTANCE_NAMES)
and self.direction == SUPERTYPE_OF):
for item in actual.items:
cb = infer_constraints(template.args[0], item, SUPERTYPE_OF)
Expand Down
25 changes: 13 additions & 12 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
TypeTranslator, TypeOfAny, TypeType, NoneType, PlaceholderType, TPDICT_NAMES, ProperType,
get_proper_type, get_proper_types, TypeAliasType, TypeVarLikeType,
PROTOCOL_NAMES, TYPE_ALIAS_NAMES, FINAL_TYPE_NAMES, FINAL_DECORATOR_NAMES,
is_named_instance,
)
from mypy.typeops import function_type, get_type_vars
from mypy.type_visitor import TypeQuery
Expand Down Expand Up @@ -1038,8 +1039,7 @@ def visit_decorator(self, dec: Decorator) -> None:
removed.append(i)
dec.func.is_abstract = True
self.check_decorated_function_is_method('abstractmethod', dec)
elif (refers_to_fullname(d, 'asyncio.coroutines.coroutine') or
refers_to_fullname(d, 'types.coroutine')):
elif refers_to_fullname(d, ('asyncio.coroutines.coroutine', 'types.coroutine')):
removed.append(i)
dec.func.is_awaitable_coroutine = True
elif refers_to_fullname(d, 'builtins.staticmethod'):
Expand All @@ -1052,9 +1052,10 @@ def visit_decorator(self, dec: Decorator) -> None:
dec.func.is_class = True
dec.var.is_classmethod = True
self.check_decorated_function_is_method('classmethod', dec)
elif (refers_to_fullname(d, 'builtins.property') or
refers_to_fullname(d, 'abc.abstractproperty') or
refers_to_fullname(d, 'functools.cached_property')):
elif refers_to_fullname(d, (
'builtins.property',
'abc.abstractproperty',
'functools.cached_property')):
removed.append(i)
dec.func.is_property = True
dec.var.is_property = True
Expand All @@ -1068,8 +1069,7 @@ def visit_decorator(self, dec: Decorator) -> None:
elif refers_to_fullname(d, 'typing.no_type_check'):
dec.var.type = AnyType(TypeOfAny.special_form)
no_type_check = True
elif (refers_to_fullname(d, 'typing.final') or
refers_to_fullname(d, 'typing_extensions.final')):
elif refers_to_fullname(d, FINAL_DECORATOR_NAMES):
if self.is_class_scope():
assert self.type is not None, "No type set at class scope"
if self.type.is_protocol:
Expand Down Expand Up @@ -5315,16 +5315,17 @@ def replace_implicit_first_type(sig: FunctionLike, new: Type) -> FunctionLike:
assert False


def refers_to_fullname(node: Expression, fullname: str) -> bool:
def refers_to_fullname(node: Expression, fullnames: Union[str, Tuple[str, ...]]) -> bool:
"""Is node a name or member expression with the given full name?"""
if not isinstance(fullnames, tuple):
fullnames = (fullnames,)

if not isinstance(node, RefExpr):
return False
if node.fullname == fullname:
if node.fullname in fullnames:
return True
if isinstance(node.node, TypeAlias):
target = get_proper_type(node.node.target)
if isinstance(target, Instance) and target.type.fullname == fullname:
return True
return is_named_instance(node.node.target, fullnames)
return False


Expand Down
15 changes: 4 additions & 11 deletions mypy/subtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
Type, AnyType, UnboundType, TypeVisitor, FormalArgument, NoneType,
Instance, TypeVarType, CallableType, TupleType, TypedDictType, UnionType, Overloaded,
ErasedType, PartialType, DeletedType, UninhabitedType, TypeType, is_named_instance,
FunctionLike, TypeOfAny, LiteralType, get_proper_type, TypeAliasType, ParamSpecType
FunctionLike, TypeOfAny, LiteralType, get_proper_type, TypeAliasType, ParamSpecType,
TUPLE_LIKE_INSTANCE_NAMES,
)
import mypy.applytype
import mypy.constraints
Expand Down Expand Up @@ -362,11 +363,7 @@ def visit_tuple_type(self, left: TupleType) -> bool:
if isinstance(right, Instance):
if is_named_instance(right, 'typing.Sized'):
return True
elif (is_named_instance(right, 'builtins.tuple') or
is_named_instance(right, 'typing.Iterable') or
is_named_instance(right, 'typing.Container') or
is_named_instance(right, 'typing.Sequence') or
is_named_instance(right, 'typing.Reversible')):
elif is_named_instance(right, TUPLE_LIKE_INSTANCE_NAMES):
if right.args:
iter_type = right.args[0]
else:
Expand Down Expand Up @@ -1377,11 +1374,7 @@ def visit_callable_type(self, left: CallableType) -> bool:
def visit_tuple_type(self, left: TupleType) -> bool:
right = self.right
if isinstance(right, Instance):
if (is_named_instance(right, 'builtins.tuple') or
is_named_instance(right, 'typing.Iterable') or
is_named_instance(right, 'typing.Container') or
is_named_instance(right, 'typing.Sequence') or
is_named_instance(right, 'typing.Reversible')):
if is_named_instance(right, TUPLE_LIKE_INSTANCE_NAMES):
if not right.args:
return False
iter_type = get_proper_type(right.args[0])
Expand Down
16 changes: 14 additions & 2 deletions mypy/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,15 @@
'typing_extensions.Annotated',
)

# We use this constant in various places when checking `tuple` subtyping:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not related to your diff, but I wonder why Sized and Collection aren't in here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to open a new issue? 🤔

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes probably. I guess what this affects is whether a heterogeneous tuple type matches Sized or Collection?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done #11961

TUPLE_LIKE_INSTANCE_NAMES: Final = (
'builtins.tuple',
'typing.Iterable',
'typing.Container',
'typing.Sequence',
'typing.Reversible',
)

# A placeholder used for Bogus[...] parameters
_dummy: Final[Any] = object()

Expand Down Expand Up @@ -2482,9 +2491,12 @@ def strip_type(typ: Type) -> ProperType:
return typ


def is_named_instance(t: Type, fullname: str) -> bool:
def is_named_instance(t: Type, fullnames: Union[str, Tuple[str, ...]]) -> bool:
if not isinstance(fullnames, tuple):
fullnames = (fullnames,)

t = get_proper_type(t)
return isinstance(t, Instance) and t.type.fullname == fullname
return isinstance(t, Instance) and t.type.fullname in fullnames


TP = TypeVar('TP', bound=Type)
Expand Down