Skip to content

Commit

Permalink
Fix cases of type object handling for overloads (#16168)
Browse files Browse the repository at this point in the history
Fixes most of #12320. I didn't add tests for every code path because
it's niche. I also didn't fix everything, in particular the cases where
we proceed to use `ret_type`
  • Loading branch information
hauntsaninja authored Oct 1, 2023
1 parent 7a62481 commit 3d3e482
Show file tree
Hide file tree
Showing 7 changed files with 21 additions and 13 deletions.
4 changes: 2 additions & 2 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -2986,7 +2986,7 @@ def check_assignment(
p_rvalue_type = get_proper_type(rvalue_type)
p_lvalue_type = get_proper_type(lvalue_type)
if (
isinstance(p_rvalue_type, CallableType)
isinstance(p_rvalue_type, FunctionLike)
and p_rvalue_type.is_type_obj()
and (
p_rvalue_type.type_object().is_abstract
Expand Down Expand Up @@ -3771,7 +3771,7 @@ def split_around_star(

def type_is_iterable(self, type: Type) -> bool:
type = get_proper_type(type)
if isinstance(type, CallableType) and type.is_type_obj():
if isinstance(type, FunctionLike) and type.is_type_obj():
type = type.fallback
return is_subtype(
type, self.named_generic_type("typing.Iterable", [AnyType(TypeOfAny.special_form)])
Expand Down
8 changes: 4 additions & 4 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,7 @@ def check_runtime_protocol_test(self, e: CallExpr) -> None:
for expr in mypy.checker.flatten(e.args[1]):
tp = get_proper_type(self.chk.lookup_type(expr))
if (
isinstance(tp, CallableType)
isinstance(tp, FunctionLike)
and tp.is_type_obj()
and tp.type_object().is_protocol
and not tp.type_object().runtime_protocol
Expand All @@ -704,7 +704,7 @@ def check_runtime_protocol_test(self, e: CallExpr) -> None:
def check_protocol_issubclass(self, e: CallExpr) -> None:
for expr in mypy.checker.flatten(e.args[1]):
tp = get_proper_type(self.chk.lookup_type(expr))
if isinstance(tp, CallableType) and tp.is_type_obj() and tp.type_object().is_protocol:
if isinstance(tp, FunctionLike) and tp.is_type_obj() and tp.type_object().is_protocol:
attr_members = non_method_protocol_members(tp.type_object())
if attr_members:
self.chk.msg.report_non_method_protocol(tp.type_object(), attr_members, e)
Expand Down Expand Up @@ -4190,7 +4190,7 @@ def visit_index_with_type(
elif isinstance(left_type, TypedDictType):
return self.visit_typeddict_index_expr(left_type, e.index)
elif (
isinstance(left_type, CallableType)
isinstance(left_type, FunctionLike)
and left_type.is_type_obj()
and left_type.type_object().is_enum
):
Expand Down Expand Up @@ -5832,7 +5832,7 @@ def has_abstract_type_part(self, caller_type: ProperType, callee_type: ProperTyp

def has_abstract_type(self, caller_type: ProperType, callee_type: ProperType) -> bool:
return (
isinstance(caller_type, CallableType)
isinstance(caller_type, FunctionLike)
and isinstance(callee_type, TypeType)
and caller_type.is_type_obj()
and (caller_type.type_object().is_abstract or caller_type.type_object().is_protocol)
Expand Down
2 changes: 1 addition & 1 deletion mypy/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ def has_no_attr(
elif member == "__getitem__":
# Indexed get.
# TODO: Fix this consistently in format_type
if isinstance(original_type, CallableType) and original_type.is_type_obj():
if isinstance(original_type, FunctionLike) and original_type.is_type_obj():
self.fail(
"The type {} is not generic and not indexable".format(
format_type(original_type, self.options)
Expand Down
3 changes: 1 addition & 2 deletions mypy/plugins/proper_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from mypy.subtypes import is_proper_subtype
from mypy.types import (
AnyType,
CallableType,
FunctionLike,
Instance,
NoneTyp,
Expand Down Expand Up @@ -131,7 +130,7 @@ def is_dangerous_target(typ: ProperType) -> bool:
"""Is this a dangerous target (right argument) for an isinstance() check?"""
if isinstance(typ, TupleType):
return any(is_dangerous_target(get_proper_type(t)) for t in typ.items)
if isinstance(typ, CallableType) and typ.is_type_obj():
if isinstance(typ, FunctionLike) and typ.is_type_obj():
return typ.type_object().has_base("mypy.types.Type")
return False

Expand Down
2 changes: 1 addition & 1 deletion mypy/typeops.py
Original file line number Diff line number Diff line change
Expand Up @@ -989,7 +989,7 @@ def custom_special_method(typ: Type, name: str, check_all: bool = False) -> bool
return any(custom_special_method(t, name) for t in typ.items)
if isinstance(typ, TupleType):
return custom_special_method(tuple_fallback(typ), name, check_all)
if isinstance(typ, CallableType) and typ.is_type_obj():
if isinstance(typ, FunctionLike) and typ.is_type_obj():
# Look up __method__ on the metaclass for class objects.
return custom_special_method(typ.fallback, name, check_all)
if isinstance(typ, AnyType):
Expand Down
11 changes: 10 additions & 1 deletion test-data/unit/check-abstract.test
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ f(GoodAlias)

[case testInstantiationAbstractsInTypeForVariables]
# flags: --no-strict-optional
from typing import Type
from typing import Type, overload
from abc import abstractmethod

class A:
Expand Down Expand Up @@ -269,6 +269,15 @@ if int():
var_old = B # E: Can only assign concrete classes to a variable of type "Type[A]"
if int():
var_old = C # OK

class D(A):
@overload
def __new__(cls, a) -> "D": ...
@overload
def __new__(cls) -> "D": ...
def __new__(cls, a=None) -> "D": ...
if int():
var = D # E: Can only assign concrete classes to a variable of type "Type[A]"
[out]

[case testInstantiationAbstractsInTypeForClassMethods]
Expand Down
4 changes: 2 additions & 2 deletions test-data/unit/pythoneval.test
Original file line number Diff line number Diff line change
Expand Up @@ -1801,9 +1801,9 @@ C = str | int
D: TypeAlias = str | int
[out]
_testTypeAliasNotSupportedWithNewStyleUnion.py:3: error: Invalid type alias: expression is not a valid type
_testTypeAliasNotSupportedWithNewStyleUnion.py:3: error: Value of type "Type[type]" is not indexable
_testTypeAliasNotSupportedWithNewStyleUnion.py:3: error: The type "Type[type]" is not generic and not indexable
_testTypeAliasNotSupportedWithNewStyleUnion.py:4: error: Invalid type alias: expression is not a valid type
_testTypeAliasNotSupportedWithNewStyleUnion.py:4: error: Value of type "Type[type]" is not indexable
_testTypeAliasNotSupportedWithNewStyleUnion.py:4: error: The type "Type[type]" is not generic and not indexable
_testTypeAliasNotSupportedWithNewStyleUnion.py:5: error: Invalid type alias: expression is not a valid type
_testTypeAliasNotSupportedWithNewStyleUnion.py:5: error: Unsupported left operand type for | ("Type[str]")
_testTypeAliasNotSupportedWithNewStyleUnion.py:6: error: Invalid type alias: expression is not a valid type
Expand Down

0 comments on commit 3d3e482

Please sign in to comment.