Skip to content

Commit e2d3a5e

Browse files
committed
changes
1 parent 4616fa2 commit e2d3a5e

File tree

3 files changed

+38
-17
lines changed

3 files changed

+38
-17
lines changed

mypy/typeops.py

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -191,19 +191,27 @@ def class_callable(
191191
orig_self_type = get_proper_type(orig_self_type)
192192
default_ret_type = fill_typevars(info)
193193
explicit_type = init_ret_type if is_new else orig_self_type
194-
if (
195-
isinstance(explicit_type, (Instance, TupleType, UninhabitedType))
196-
# We have to skip protocols, because it can be a subtype of a return type
197-
# by accident. Like `Hashable` is a subtype of `object`. See #11799
198-
and isinstance(default_ret_type, Instance)
199-
and not default_ret_type.type.is_protocol
200-
# Only use the declared return type from declared self in __init__
201-
# if it is actually returning a subtype of what we would return otherwise.
202-
and (is_new or is_subtype(explicit_type, default_ret_type, ignore_type_params=True))
203-
):
204-
ret_type: Type = explicit_type
205-
else:
206-
ret_type = default_ret_type
194+
195+
ret_type: Type = default_ret_type
196+
if isinstance(explicit_type, (Instance, TupleType, UninhabitedType)):
197+
if is_new:
198+
# For a long time, mypy didn't truly believe annotations on __new__
199+
# This has led to some proliferation of code that depends on this, namely
200+
# annotations on __new__ that hardcode the class in the return type.
201+
# This can then cause problems for subclasses. Preserve the old behaviour in
202+
# this case (although we should probably change it at some point)
203+
if not is_subtype(default_ret_type, explicit_type, ignore_type_params=True):
204+
ret_type = explicit_type
205+
elif (
206+
# We have to skip protocols, because it can be a subtype of a return type
207+
# by accident. Like `Hashable` is a subtype of `object`. See #11799
208+
isinstance(default_ret_type, Instance)
209+
and not default_ret_type.type.is_protocol
210+
# Only use the declared return type from declared self in __init__
211+
# if it is actually returning a subtype of what we would return otherwise.
212+
and is_subtype(explicit_type, default_ret_type, ignore_type_params=True)
213+
):
214+
ret_type = explicit_type
207215

208216
callable_type = init_type.copy_modified(
209217
ret_type=ret_type,

test-data/unit/check-classes.test

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6913,8 +6913,8 @@ class O(Generic[T]):
69136913
def __new__(cls, x: int = 0) -> O[Any]:
69146914
pass
69156915

6916-
reveal_type(O()) # N: Revealed type is "__main__.O[builtins.int]"
6917-
reveal_type(O(10)) # N: Revealed type is "__main__.O[builtins.str]"
6916+
reveal_type(O()) # N: Revealed type is "__main__.O[Never]"
6917+
reveal_type(O(10)) # N: Revealed type is "__main__.O[Never]"
69186918

69196919
[case testNewReturnType6]
69206920
from typing import Tuple, Optional
@@ -6960,7 +6960,7 @@ class A:
69606960
class B(A):
69616961
pass
69626962

6963-
reveal_type(B()) # N: Revealed type is "__main__.A"
6963+
reveal_type(B()) # N: Revealed type is "__main__.B"
69646964

69656965
[case testNewReturnType10]
69666966
# https://github.com/python/mypy/issues/11398
@@ -6993,6 +6993,19 @@ class MyMetaClass(type):
69936993
class MyClass(metaclass=MyMetaClass):
69946994
pass
69956995

6996+
[case testNewReturnType13]
6997+
from typing import Protocol
6998+
6999+
class Foo(Protocol):
7000+
def foo(self) -> str: ...
7001+
7002+
class A:
7003+
def __new__(cls) -> Foo: ... # E: Incompatible return type for "__new__" (returns "Foo", but must return a subtype of "A")
7004+
7005+
reveal_type(A()) # E: Cannot instantiate protocol class "Foo" \
7006+
# N: Revealed type is "__main__.Foo"
7007+
reveal_type(A().foo()) # E: Cannot instantiate protocol class "Foo" \
7008+
# N: Revealed type is "builtins.str"
69967009

69977010
[case testMetaclassPlaceholderNode]
69987011
from sympy.assumptions import ManagedProperties

test-data/unit/check-enum.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1360,7 +1360,7 @@ class Bar(Foo):
13601360
A = 1
13611361
B = 2
13621362

1363-
a = Bar.A # E: "Type[Foo]" has no attribute "A"
1363+
a = Bar.A
13641364
reveal_type(a.value) # N: Revealed type is "Any"
13651365
reveal_type(a._value_) # N: Revealed type is "Any"
13661366
[builtins fixtures/primitives.pyi]

0 commit comments

Comments
 (0)