Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c95ecc1

Browse files
authored
Only return a declared type from __new__ if it is a subtype of the class (#7656)
Fixes #7597.
1 parent 6f8480c commit c95ecc1

File tree

2 files changed

+23
-4
lines changed

2 files changed

+23
-4
lines changed

mypy/typeops.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,20 @@ def class_callable(init_type: CallableType, info: TypeInfo, type_type: Instance,
7777
variables.extend(info.defn.type_vars)
7878
variables.extend(init_type.variables)
7979

80+
from mypy.subtypes import is_subtype
81+
8082
init_ret_type = get_proper_type(init_type.ret_type)
81-
if is_new and isinstance(init_ret_type, (Instance, TupleType)):
82-
ret_type = init_type.ret_type # type: Type
83+
default_ret_type = fill_typevars(info)
84+
if (
85+
is_new
86+
and isinstance(init_ret_type, (Instance, TupleType))
87+
# Only use the return type from __new__ if it is actually returning
88+
# a subtype of what we would return otherwise.
89+
and is_subtype(init_ret_type, default_ret_type, ignore_type_params=True)
90+
):
91+
ret_type = init_ret_type # type: Type
8392
else:
84-
ret_type = fill_typevars(info)
93+
ret_type = default_ret_type
8594

8695
callable_type = init_type.copy_modified(
8796
ret_type=ret_type, fallback=type_type, name=None, variables=variables,

test-data/unit/check-classes.test

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6031,7 +6031,7 @@ class A:
60316031
def __new__(cls) -> int: # E: Incompatible return type for "__new__" (returns "int", but must return a subtype of "A")
60326032
pass
60336033

6034-
reveal_type(A()) # N: Revealed type is 'builtins.int'
6034+
reveal_type(A()) # N: Revealed type is '__main__.A'
60356035

60366036
[case testNewReturnType4]
60376037
from typing import TypeVar, Type
@@ -6099,6 +6099,16 @@ class X:
60996099
def __new__(cls, x: TX) -> TX: # E: "__new__" must return a class instance (got "TX")
61006100
pass
61016101

6102+
[case testNewReturnType9]
6103+
class A:
6104+
def __new__(cls) -> A:
6105+
pass
6106+
6107+
class B(A):
6108+
pass
6109+
6110+
reveal_type(B()) # N: Revealed type is '__main__.B'
6111+
61026112
[case testGenericOverride]
61036113
from typing import Generic, TypeVar, Any
61046114

0 commit comments

Comments
 (0)