From c4dcdaabb6d693caf186b2d4ab579bd7fa9c67e5 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sat, 23 Sep 2023 14:16:05 -0700 Subject: [PATCH 1/2] Fix various type object handling 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`, or ones I thought were scary --- mypy/checker.py | 4 ++-- mypy/checkexpr.py | 8 ++++---- mypy/messages.py | 2 +- mypy/plugins/proper_plugin.py | 2 +- mypy/typeops.py | 2 +- test-data/unit/check-abstract.test | 11 ++++++++++- 6 files changed, 19 insertions(+), 10 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index 95a65b0a8cd1..053ddfeb574b 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -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 @@ -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)]) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 7b9b84938930..c4319a8708a3 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -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 @@ -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) @@ -4142,7 +4142,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 ): @@ -5721,7 +5721,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) diff --git a/mypy/messages.py b/mypy/messages.py index 8bc190b7d66d..5fc006de942b 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -411,7 +411,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) diff --git a/mypy/plugins/proper_plugin.py b/mypy/plugins/proper_plugin.py index ab93f0d126db..5409a1b9c362 100644 --- a/mypy/plugins/proper_plugin.py +++ b/mypy/plugins/proper_plugin.py @@ -131,7 +131,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 diff --git a/mypy/typeops.py b/mypy/typeops.py index 10efa32c4b91..37817933a397 100644 --- a/mypy/typeops.py +++ b/mypy/typeops.py @@ -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): diff --git a/test-data/unit/check-abstract.test b/test-data/unit/check-abstract.test index 299074050baa..7f91eb8e7145 100644 --- a/test-data/unit/check-abstract.test +++ b/test-data/unit/check-abstract.test @@ -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: @@ -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] From fb36d673490e6913043dddef59e6d160a13aee4b Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sat, 23 Sep 2023 14:51:22 -0700 Subject: [PATCH 2/2] error --- mypy/plugins/proper_plugin.py | 1 - test-data/unit/pythoneval.test | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/mypy/plugins/proper_plugin.py b/mypy/plugins/proper_plugin.py index 5409a1b9c362..a1fd05272b65 100644 --- a/mypy/plugins/proper_plugin.py +++ b/mypy/plugins/proper_plugin.py @@ -17,7 +17,6 @@ from mypy.subtypes import is_proper_subtype from mypy.types import ( AnyType, - CallableType, FunctionLike, Instance, NoneTyp, diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index c5be30eac1b7..3d8e8d09a5ad 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -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