Skip to content

Commit 4ac35ba

Browse files
authored
Make overloaded constructors consistent in error messages (#20483)
This allows to re-enable 7 tests that were skipped in parallel mode. Note that I changed my opinion on what the representation of overloaded constructors should actually be. Now I think that the representation that previously was only used in warm runs is better. Two reasons for this: * Having a non-`None` return type for `__init__` would be weird (and manually tweaking it would introduce some fragile special-casing) * I found a (very) old test case `testSerializeOverloaded__init__` from which it looks like using the class name is very much intentional. Also note that currently logic for determining function name, and for determining first argument (i.e. `self`/`cls`) are currently entangled. I refactor this to make these two pieces independent.
1 parent 2322834 commit 4ac35ba

11 files changed

+59
-52
lines changed

mypy/messages.py

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3017,30 +3017,37 @@ def [T <: int] f(self, x: int, y: T) -> None
30173017
s += ", /"
30183018
slash = True
30193019

3020-
# If we got a "special arg" (i.e: self, cls, etc...), prepend it to the arg list
30213020
definition = get_func_def(tp)
3021+
3022+
# Extract function name, prefer the "human-readable" name if available.
3023+
func_name = None
3024+
if tp.name:
3025+
func_name = tp.name.split()[0] # skip "of Class" part
3026+
elif isinstance(definition, FuncDef):
3027+
func_name = definition.name
3028+
3029+
# If we got a "special arg" (i.e: self, cls, etc...), prepend it to the arg list
3030+
first_arg = None
30223031
if (
30233032
isinstance(definition, FuncDef)
30243033
and hasattr(definition, "arguments")
30253034
and not tp.from_concatenate
30263035
):
30273036
definition_arg_names = [arg.variable.name for arg in definition.arguments]
3028-
if (
3029-
len(definition_arg_names) > len(tp.arg_names)
3030-
and definition_arg_names[0]
3031-
and not skip_self
3032-
):
3033-
if s:
3034-
s = ", " + s
3035-
s = definition_arg_names[0] + s
3036-
s = f"{definition.name}({s})"
3037-
elif tp.name:
3037+
if len(definition_arg_names) > len(tp.arg_names) and definition_arg_names[0]:
3038+
first_arg = definition_arg_names[0]
3039+
else:
3040+
# TODO: avoid different logic for incremental runs.
30383041
first_arg = get_first_arg(tp)
3039-
if first_arg:
3040-
if s:
3041-
s = ", " + s
3042-
s = first_arg + s
3043-
s = f"{tp.name.split()[0]}({s})" # skip "of Class" part
3042+
3043+
if tp.is_type_obj():
3044+
skip_self = True
3045+
if first_arg and not skip_self:
3046+
if s:
3047+
s = ", " + s
3048+
s = first_arg + s
3049+
if func_name:
3050+
s = f"{func_name}({s})"
30443051
else:
30453052
s = f"({s})"
30463053

test-data/unit/check-classes.test

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3492,8 +3492,8 @@ c.a # E: "C" has no attribute "a"
34923492
C('', '')
34933493
C('') # E: No overload variant of "C" matches argument type "str" \
34943494
# N: Possible overload variants: \
3495-
# N: def __new__(cls, foo: int) -> C \
3496-
# N: def __new__(cls, x: str, y: str) -> C
3495+
# N: def C(foo: int) -> C \
3496+
# N: def C(x: str, y: str) -> C
34973497
[builtins fixtures/__new__.pyi]
34983498

34993499

@@ -3922,8 +3922,8 @@ u = new(User)
39223922
[out]
39233923
tmp/foo.pyi:17: error: No overload variant of "User" matches argument type "str"
39243924
tmp/foo.pyi:17: note: Possible overload variants:
3925-
tmp/foo.pyi:17: note: def __init__(self) -> U
3926-
tmp/foo.pyi:17: note: def __init__(self, arg: int) -> U
3925+
tmp/foo.pyi:17: note: def User() -> U
3926+
tmp/foo.pyi:17: note: def User(arg: int) -> U
39273927
tmp/foo.pyi:18: error: Too many arguments for "foo" of "User"
39283928

39293929
[case testTypeUsingTypeCInUpperBound]
@@ -8529,7 +8529,7 @@ def identity_wrapper(func: FuncT) -> FuncT:
85298529
def foo(self: Any) -> str:
85308530
return ""
85318531

8532-
[case testParentClassWithTypeAliasAndSubclassWithMethod_no_parallel]
8532+
[case testParentClassWithTypeAliasAndSubclassWithMethod]
85338533
from typing import Any, Callable, TypeVar
85348534

85358535
class Parent:
@@ -8548,7 +8548,7 @@ class Child(Parent):
85488548
return val
85498549
def bar(self, val: str) -> str: # E: Signature of "bar" incompatible with supertype "Parent" \
85508550
# N: Superclass: \
8551-
# N: def __init__(self) -> bar \
8551+
# N: def bar() -> bar \
85528552
# N: Subclass: \
85538553
# N: def bar(self, val: str) -> str
85548554
return val

test-data/unit/check-flags.test

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2472,19 +2472,19 @@ cb(lambda x: a) # OK
24722472
fn = lambda x: a
24732473
cb(fn)
24742474

2475-
[case testShowErrorCodeLinks_no_parallel]
2475+
[case testShowErrorCodeLinks]
24762476
# flags: --show-error-codes --show-error-code-links
24772477

24782478
x: int = "" # E: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment]
24792479
list(1) # E: No overload variant of "list" matches argument type "int" [call-overload] \
24802480
# N: Possible overload variants: \
2481-
# N: def [T] __init__(self) -> list[T] \
2482-
# N: def [T] __init__(self, x: Iterable[T]) -> list[T] \
2481+
# N: def [T] list() -> list[T] \
2482+
# N: def [T] list(x: Iterable[T]) -> list[T] \
24832483
# N: See https://mypy.rtfd.io/en/stable/_refs.html#code-call-overload for more info
24842484
list(2) # E: No overload variant of "list" matches argument type "int" [call-overload] \
24852485
# N: Possible overload variants: \
2486-
# N: def [T] __init__(self) -> list[T] \
2487-
# N: def [T] __init__(self, x: Iterable[T]) -> list[T]
2486+
# N: def [T] list() -> list[T] \
2487+
# N: def [T] list(x: Iterable[T]) -> list[T]
24882488
[builtins fixtures/list.pyi]
24892489

24902490
[case testNestedGenericInAliasDisallow]

test-data/unit/check-inference.test

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1748,13 +1748,13 @@ def f(blocks: Any): # E: Name "Any" is not defined \
17481748
to_process = list(blocks)
17491749
[builtins fixtures/list.pyi]
17501750

1751-
[case testSpecialCaseEmptyListInitialization2_no_parallel]
1751+
[case testSpecialCaseEmptyListInitialization2]
17521752
def f(blocks: object):
17531753
to_process = []
17541754
to_process = list(blocks) # E: No overload variant of "list" matches argument type "object" \
17551755
# N: Possible overload variants: \
1756-
# N: def [T] __init__(self) -> list[T] \
1757-
# N: def [T] __init__(self, x: Iterable[T]) -> list[T]
1756+
# N: def [T] list() -> list[T] \
1757+
# N: def [T] list(x: Iterable[T]) -> list[T]
17581758
[builtins fixtures/list.pyi]
17591759

17601760
[case testInferListInitializedToEmptyAndAssigned]

test-data/unit/check-overloading.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -625,8 +625,8 @@ a = A(a)
625625
a = A(b)
626626
a = A(object()) # E: No overload variant of "A" matches argument type "object" \
627627
# N: Possible overload variants: \
628-
# N: def __init__(self, a: A) -> A \
629-
# N: def __init__(self, b: B) -> A
628+
# N: def A(a: A) -> A \
629+
# N: def A(b: B) -> A
630630

631631
class A:
632632
@overload

test-data/unit/check-protocols.test

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3609,7 +3609,7 @@ test(C) # E: Argument 1 to "test" has incompatible type "type[C]"; expected "P"
36093609
# N: Expected: \
36103610
# N: def __call__(x: int, y: int) -> Any \
36113611
# N: Got: \
3612-
# N: def __init__(x: int, y: str) -> C \
3612+
# N: def C(x: int, y: str) -> C \
36133613
# N: "P.__call__" has type "def __call__(self, x: int, y: int) -> Any"
36143614

36153615
[case testProtocolClassObjectPureCallback]
@@ -3631,7 +3631,7 @@ test(C) # E: Argument 1 to "test" has incompatible type "type[C]"; expected "P"
36313631
# N: Expected: \
36323632
# N: def __call__(x: int, y: int) -> Any \
36333633
# N: Got: \
3634-
# N: def __init__(x: int, y: str) -> C \
3634+
# N: def C(x: int, y: str) -> C \
36353635
# N: "P.__call__" has type "def __call__(self, x: int, y: int) -> Any"
36363636
[builtins fixtures/type.pyi]
36373637

@@ -3654,7 +3654,7 @@ p: P = C # E: Incompatible types in assignment (expression has type "type[C]",
36543654
# N: Expected: \
36553655
# N: def __call__(app: int) -> Callable[[str], None] \
36563656
# N: Got: \
3657-
# N: def __init__(app: str) -> C \
3657+
# N: def C(app: str) -> C \
36583658
# N: "P.__call__" has type "def __call__(self, app: int) -> Callable[[str], None]"
36593659

36603660
[builtins fixtures/type.pyi]
@@ -3890,7 +3890,7 @@ other_flag = False
38903890
def update() -> str: ...
38913891
[builtins fixtures/module.pyi]
38923892

3893-
[case testModuleAsProtocolImplementationClassObject_no_parallel]
3893+
[case testModuleAsProtocolImplementationClassObject]
38943894
import runner
38953895
import bad_runner
38963896
from typing import Callable, Protocol
@@ -3909,7 +3909,7 @@ run(bad_runner) # E: Argument 1 to "run" has incompatible type Module; expected
39093909
# N: Expected: \
39103910
# N: def (int, /) -> Result \
39113911
# N: Got: \
3912-
# N: def __init__(arg: str) -> Run
3912+
# N: def Run(arg: str) -> Run
39133913

39143914
[file runner.py]
39153915
class Run:
@@ -3922,7 +3922,7 @@ class Run:
39223922
def __init__(self, arg: str) -> None: ...
39233923
[builtins fixtures/module.pyi]
39243924

3925-
[case testModuleAsProtocolImplementationTypeAlias_no_parallel]
3925+
[case testModuleAsProtocolImplementationTypeAlias]
39263926
import runner
39273927
import bad_runner
39283928
from typing import Callable, Protocol
@@ -3941,7 +3941,7 @@ run(bad_runner) # E: Argument 1 to "run" has incompatible type Module; expected
39413941
# N: Expected: \
39423942
# N: def (int, /) -> Result \
39433943
# N: Got: \
3944-
# N: def __init__(arg: str) -> Run
3944+
# N: def Run(arg: str) -> Run
39453945

39463946
[file runner.py]
39473947
class Run:

test-data/unit/check-python311.test

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,9 @@ myclass2 = MyClass(float, float)
137137
reveal_type(myclass2) # N: Revealed type is "__main__.MyClass[builtins.float, builtins.float]"
138138
myclass3 = MyClass(float, float, float) # E: No overload variant of "MyClass" matches argument types "type[float]", "type[float]", "type[float]" \
139139
# N: Possible overload variants: \
140-
# N: def [T1, T2] __init__(self) -> MyClass[None, None] \
141-
# N: def [T1, T2] __init__(self, type[T1], /) -> MyClass[T1, None] \
142-
# N: def [T1, T2] __init__(type[T1], type[T2], /) -> MyClass[T1, T2]
140+
# N: def [T1, T2] MyClass() -> MyClass[None, None] \
141+
# N: def [T1, T2] MyClass(type[T1], /) -> MyClass[T1, None] \
142+
# N: def [T1, T2] MyClass(type[T1], type[T2], /) -> MyClass[T1, T2]
143143
reveal_type(myclass3) # N: Revealed type is "Any"
144144
[builtins fixtures/tuple.pyi]
145145

test-data/unit/check-selftype.test

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -749,7 +749,7 @@ def bad(x: str) -> str: ...
749749
reveal_type(ci.from_item(conv)) # N: Revealed type is "builtins.str"
750750
ci.from_item(bad) # E: Argument 1 to "from_item" of "C" has incompatible type "Callable[[str], str]"; expected "Callable[[int], str]"
751751

752-
[case testSelfTypeRestrictedMethodOverloadInit_no_parallel]
752+
[case testSelfTypeRestrictedMethodOverloadInit]
753753
from typing import TypeVar
754754
from lib import P, C
755755

@@ -767,8 +767,8 @@ class SubP(P[T]):
767767

768768
SubP('no') # E: No overload variant of "SubP" matches argument type "str" \
769769
# N: Possible overload variants: \
770-
# N: def [T] __init__(self, use_str: Literal[True]) -> SubP[T] \
771-
# N: def [T] __init__(self, use_str: Literal[False]) -> SubP[T]
770+
# N: def [T] SubP(use_str: Literal[True]) -> SubP[T] \
771+
# N: def [T] SubP(use_str: Literal[False]) -> SubP[T]
772772

773773
# This is a bit unfortunate: we don't have a way to map the overloaded __init__ to subtype.
774774
x = SubP(use_str=True) # E: Need type annotation for "x"

test-data/unit/check-serialize.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,8 @@ class A:
312312
[out2]
313313
tmp/a.py:2: error: No overload variant of "A" matches argument type "object"
314314
tmp/a.py:2: note: Possible overload variants:
315-
tmp/a.py:2: note: def A(self, x: int) -> A
316-
tmp/a.py:2: note: def A(self, x: str) -> A
315+
tmp/a.py:2: note: def A(x: int) -> A
316+
tmp/a.py:2: note: def A(x: str) -> A
317317
tmp/a.py:7: error: No overload variant of "__init__" of "A" matches argument type "object"
318318
tmp/a.py:7: note: Possible overload variants:
319319
tmp/a.py:7: note: def __init__(self, x: int) -> None

test-data/unit/check-type-aliases.test

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,16 +1339,16 @@ a: A
13391339
reveal_type(a) # N: Revealed type is "builtins.list[builtins.str]"
13401340
[builtins fixtures/tuple.pyi]
13411341

1342-
[case testTypeAliasDict_no_parallel]
1342+
[case testTypeAliasDict]
13431343
D = dict[str, int]
13441344
d = D()
13451345
reveal_type(d) # N: Revealed type is "builtins.dict[builtins.str, builtins.int]"
13461346
reveal_type(D()) # N: Revealed type is "builtins.dict[builtins.str, builtins.int]"
13471347
reveal_type(D(x=1)) # N: Revealed type is "builtins.dict[builtins.str, builtins.int]"
13481348
reveal_type(D(x="asdf")) # E: No overload variant of "dict" matches argument type "str" \
13491349
# N: Possible overload variants: \
1350-
# N: def __init__(self, **kwargs: int) -> dict[str, int] \
1351-
# N: def __init__(self, arg: Iterable[tuple[str, int]], **kwargs: int) -> dict[str, int] \
1350+
# N: def dict(**kwargs: int) -> dict[str, int] \
1351+
# N: def dict(arg: Iterable[tuple[str, int]], **kwargs: int) -> dict[str, int] \
13521352
# N: Revealed type is "Any"
13531353
[builtins fixtures/dict.pyi]
13541354

0 commit comments

Comments
 (0)