Skip to content
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

Fix inference for overloaded __call__ with generic self #16053

Merged
merged 15 commits into from
Sep 19, 2023
Prev Previous commit
Next Next commit
comment
  • Loading branch information
hauntsaninja committed Sep 15, 2023
commit 44999065054885c58ed7dbf5cb3fd2483c4a8c4c
7 changes: 4 additions & 3 deletions mypy/subtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -466,10 +466,11 @@ def visit_instance(self, left: Instance) -> bool:
if all(isinstance(get_proper_type(a), AnyType) for a in mapped.args):
Copy link
Member

@ilevkivskyi ilevkivskyi Sep 15, 2023

Choose a reason for hiding this comment

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

I think this should actually be combined with the if just above. I just realised that the if I added is incomplete, in fact if all type argument are either Any or *tuple[Any, ...] we are still good. But currently we are only considering only plain *tuple[Any, ...] or e.g. Any, Any, Any, while missing Any, *tuple[Any, ...], Any, which should be equally fine (note you don't need to check number of unpacks, it is already validated during semantic analyzis).

Note this also equally applies to the equivalent special case for plain instances I added around line 538. You may fix that as well if you want while you are at it.

return not self.proper_subtype
if mapped.type.tuple_type:
Copy link
Member

Choose a reason for hiding this comment

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

This additional branch looks like a hack. We shouldn't need this. I think the real bug is that we are passing incomplete information when accessing __call__ on a tuple type. This diff I think is a (much) more cleaner fix:

--- a/mypy/checkexpr.py
+++ b/mypy/checkexpr.py
@@ -1476,6 +1476,7 @@ class ExpressionChecker(ExpressionVisitor[Type]):
         callable_node: Expression | None = None,
         callable_name: str | None = None,
         object_type: Type | None = None,
+        original_type: Type | None = None,
     ) -> tuple[Type, Type]:
         """Type check a call.
 
@@ -1538,7 +1539,7 @@ class ExpressionChecker(ExpressionVisitor[Type]):
                 is_super=False,
                 is_operator=True,
                 msg=self.msg,
-                original_type=callee,
+                original_type=original_type or callee,
                 chk=self.chk,
                 in_literal_context=self.is_literal_context(),
             )
@@ -1579,6 +1580,7 @@ class ExpressionChecker(ExpressionVisitor[Type]):
                 callable_node,
                 callable_name,
                 object_type,
+                original_type=callee,
             )
         else:
             return self.msg.not_callable(callee, context), AnyType(TypeOfAny.from_error)

expanded = expand_type_by_instance(mapped.type.tuple_type, mapped)
assert isinstance(expanded, TupleType)
# similar to logic inside map_instance_to_supertype
tuple_type = expand_type_by_instance(mapped.type.tuple_type, mapped)
assert isinstance(tuple_type, TupleType)
return self._is_subtype(
expanded, right.copy_modified(fallback=expanded.partial_fallback)
tuple_type, right.copy_modified(fallback=tuple_type.partial_fallback)
) and self._is_subtype(left, mypy.typeops.tuple_fallback(right))
return False
if isinstance(right, TypeVarTupleType):
Expand Down