diff --git a/crates/ty_python_semantic/resources/mdtest/call/constructor.md b/crates/ty_python_semantic/resources/mdtest/call/constructor.md index 5d2c93b6e6..365da90b5e 100644 --- a/crates/ty_python_semantic/resources/mdtest/call/constructor.md +++ b/crates/ty_python_semantic/resources/mdtest/call/constructor.md @@ -100,8 +100,10 @@ def _(flag: bool) -> None: reveal_type(Foo(1)) # revealed: Foo # error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["1"]`" + # error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["1"]`" reveal_type(Foo("1")) # revealed: Foo # error: [missing-argument] "No argument provided for required parameter `x` of function `__new__`" + # error: [missing-argument] "No argument provided for required parameter `x` of function `__new__`" reveal_type(Foo()) # revealed: Foo # error: [too-many-positional-arguments] "Too many positional arguments to function `__new__`: expected 1, got 2" reveal_type(Foo(1, 2)) # revealed: Foo @@ -231,8 +233,10 @@ def _(flag: bool) -> None: reveal_type(Foo(1)) # revealed: Foo # error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["1"]`" + # error: [invalid-argument-type] "Argument to this function is incorrect: Expected `int`, found `Literal["1"]`" reveal_type(Foo("1")) # revealed: Foo # error: [missing-argument] "No argument provided for required parameter `x` of bound method `__init__`" + # error: [missing-argument] "No argument provided for required parameter `x` of bound method `__init__`" reveal_type(Foo()) # revealed: Foo # error: [too-many-positional-arguments] "Too many positional arguments to bound method `__init__`: expected 1, got 2" reveal_type(Foo(1, 2)) # revealed: Foo diff --git a/crates/ty_python_semantic/resources/mdtest/call/union.md b/crates/ty_python_semantic/resources/mdtest/call/union.md index 0b773fbb70..3f891eaed1 100644 --- a/crates/ty_python_semantic/resources/mdtest/call/union.md +++ b/crates/ty_python_semantic/resources/mdtest/call/union.md @@ -56,8 +56,8 @@ def _(flag: bool, flag2: bool): else: def f() -> int: return 1 - # TODO we should mention all non-callable elements of the union # error: [call-non-callable] "Object of type `Literal[1]` is not callable" + # error: [call-non-callable] "Object of type `Literal["foo"]` is not callable" # revealed: Unknown | int reveal_type(f()) ``` @@ -125,8 +125,8 @@ def _(flag: bool): else: f = f2 - # TODO: we should show all errors from the union, not arbitrarily pick one union element # error: [too-many-positional-arguments] "Too many positional arguments to function `f1`: expected 0, got 1" + # error: [too-many-positional-arguments] "Too many positional arguments to function `f2`: expected 0, got 1" x = f(3) reveal_type(x) # revealed: Unknown ``` @@ -143,8 +143,8 @@ def _(flag: bool): else: f = C() - # TODO: we should either show all union errors here, or prioritize the not-callable error # error: [too-many-positional-arguments] "Too many positional arguments to function `f1`: expected 0, got 1" + # error: [call-non-callable] "Object of type `C` is not callable" x = f(3) reveal_type(x) # revealed: Unknown ``` diff --git a/crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.md b/crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.md index 303f72f29c..f8dd3b3690 100644 --- a/crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.md +++ b/crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.md @@ -22,6 +22,7 @@ def _(flag: bool): else: f = f2 # error: [too-many-positional-arguments] + # error: [invalid-argument-type] x = f(3) ``` @@ -98,6 +99,12 @@ def _(n: int): else: f = PossiblyNotCallable() # error: [too-many-positional-arguments] + # error: [invalid-argument-type] "Argument to this function is incorrect: Expected `str`, found `Literal[3]`" + # error: [missing-argument] + # error: [invalid-argument-type] "Argument to this function is incorrect: Argument type `Literal[3]` does not satisfy upper bound of type variable `T`" + # error: [call-non-callable] "Object of type `Literal[5]` is not callable" + # error: [no-matching-overload] + # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)" x = f(3) ``` diff --git a/crates/ty_python_semantic/resources/mdtest/snapshots/union_call.md_-_Calling_a_union_of_function_types_-_A_smaller_scale_example.snap b/crates/ty_python_semantic/resources/mdtest/snapshots/union_call.md_-_Calling_a_union_of_function_types_-_A_smaller_scale_example.snap index 77cd2624e5..092bd1a77b 100644 --- a/crates/ty_python_semantic/resources/mdtest/snapshots/union_call.md_-_Calling_a_union_of_function_types_-_A_smaller_scale_example.snap +++ b/crates/ty_python_semantic/resources/mdtest/snapshots/union_call.md_-_Calling_a_union_of_function_types_-_A_smaller_scale_example.snap @@ -24,18 +24,41 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.m 10 | else: 11 | f = f2 12 | # error: [too-many-positional-arguments] -13 | x = f(3) +13 | # error: [invalid-argument-type] +14 | x = f(3) ``` # Diagnostics ``` -error: lint:too-many-positional-arguments: Too many positional arguments to function `f1`: expected 0, got 1 - --> src/mdtest_snippet.py:13:11 +error: lint:invalid-argument-type: Argument to this function is incorrect + --> src/mdtest_snippet.py:14:11 | -11 | f = f2 12 | # error: [too-many-positional-arguments] -13 | x = f(3) +13 | # error: [invalid-argument-type] +14 | x = f(3) + | ^ Expected `str`, found `Literal[3]` + | +info: Function defined here + --> src/mdtest_snippet.py:4:5 + | +2 | return 0 +3 | +4 | def f2(name: str) -> int: + | ^^ --------- Parameter declared here +5 | return 0 + | +info: `lint:invalid-argument-type` is enabled by default + +``` + +``` +error: lint:too-many-positional-arguments: Too many positional arguments to function `f1`: expected 0, got 1 + --> src/mdtest_snippet.py:14:11 + | +12 | # error: [too-many-positional-arguments] +13 | # error: [invalid-argument-type] +14 | x = f(3) | ^ | info: `lint:too-many-positional-arguments` is enabled by default diff --git a/crates/ty_python_semantic/resources/mdtest/snapshots/union_call.md_-_Calling_a_union_of_function_types_-_Try_to_cover_all_possible_reasons_-_Cover_non-keyword_related_reasons.snap b/crates/ty_python_semantic/resources/mdtest/snapshots/union_call.md_-_Calling_a_union_of_function_types_-_Try_to_cover_all_possible_reasons_-_Cover_non-keyword_related_reasons.snap index 93a36fd841..e66a8226f7 100644 --- a/crates/ty_python_semantic/resources/mdtest/snapshots/union_call.md_-_Calling_a_union_of_function_types_-_Try_to_cover_all_possible_reasons_-_Cover_non-keyword_related_reasons.snap +++ b/crates/ty_python_semantic/resources/mdtest/snapshots/union_call.md_-_Calling_a_union_of_function_types_-_Try_to_cover_all_possible_reasons_-_Cover_non-keyword_related_reasons.snap @@ -53,18 +53,120 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.m 39 | else: 40 | f = PossiblyNotCallable() 41 | # error: [too-many-positional-arguments] -42 | x = f(3) +42 | # error: [invalid-argument-type] "Argument to this function is incorrect: Expected `str`, found `Literal[3]`" +43 | # error: [missing-argument] +44 | # error: [invalid-argument-type] "Argument to this function is incorrect: Argument type `Literal[3]` does not satisfy upper bound of type variable `T`" +45 | # error: [call-non-callable] "Object of type `Literal[5]` is not callable" +46 | # error: [no-matching-overload] +47 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)" +48 | x = f(3) ``` # Diagnostics ``` -error: lint:too-many-positional-arguments: Too many positional arguments to function `f1`: expected 0, got 1 - --> src/mdtest_snippet.py:42:11 +error: lint:call-non-callable: Object of type `Literal[5]` is not callable + --> src/mdtest_snippet.py:48:9 | -40 | f = PossiblyNotCallable() -41 | # error: [too-many-positional-arguments] -42 | x = f(3) +46 | # error: [no-matching-overload] +47 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)" +48 | x = f(3) + | ^^^^ + | +info: `lint:call-non-callable` is enabled by default + +``` + +``` +error: lint:call-non-callable: Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method) + --> src/mdtest_snippet.py:48:9 + | +46 | # error: [no-matching-overload] +47 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)" +48 | x = f(3) + | ^^^^ + | +info: `lint:call-non-callable` is enabled by default + +``` + +``` +error: lint:missing-argument: No argument provided for required parameter `b` of function `f3` + --> src/mdtest_snippet.py:48:9 + | +46 | # error: [no-matching-overload] +47 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)" +48 | x = f(3) + | ^^^^ + | +info: `lint:missing-argument` is enabled by default + +``` + +``` +error: lint:no-matching-overload: No overload of method wrapper `__get__` of function `f` matches arguments + --> src/mdtest_snippet.py:48:9 + | +46 | # error: [no-matching-overload] +47 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)" +48 | x = f(3) + | ^^^^ + | +info: `lint:no-matching-overload` is enabled by default + +``` + +``` +error: lint:invalid-argument-type: Argument to this function is incorrect + --> src/mdtest_snippet.py:48:11 + | +46 | # error: [no-matching-overload] +47 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)" +48 | x = f(3) + | ^ Expected `str`, found `Literal[3]` + | +info: Function defined here + --> src/mdtest_snippet.py:6:5 + | +4 | return 0 +5 | +6 | def f2(name: str) -> int: + | ^^ --------- Parameter declared here +7 | return 0 + | +info: `lint:invalid-argument-type` is enabled by default + +``` + +``` +error: lint:invalid-argument-type: Argument to this function is incorrect + --> src/mdtest_snippet.py:48:11 + | +46 | # error: [no-matching-overload] +47 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)" +48 | x = f(3) + | ^ Argument type `Literal[3]` does not satisfy upper bound of type variable `T` + | +info: Type variable defined here + --> src/mdtest_snippet.py:12:8 + | +10 | return 0 +11 | +12 | def f4[T: str](x: T) -> int: + | ^^^^^^ +13 | return 0 + | +info: `lint:invalid-argument-type` is enabled by default + +``` + +``` +error: lint:too-many-positional-arguments: Too many positional arguments to function `f1`: expected 0, got 1 + --> src/mdtest_snippet.py:48:11 + | +46 | # error: [no-matching-overload] +47 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)" +48 | x = f(3) | ^ | info: `lint:too-many-positional-arguments` is enabled by default diff --git a/crates/ty_python_semantic/src/types/call/bind.rs b/crates/ty_python_semantic/src/types/call/bind.rs index 3e509e2333..28803bd902 100644 --- a/crates/ty_python_semantic/src/types/call/bind.rs +++ b/crates/ty_python_semantic/src/types/call/bind.rs @@ -199,11 +199,8 @@ impl<'db> Bindings<'db> { } } - // TODO: We currently only report errors for the first union element. Ideally, we'd report - // an error saying that the union type can't be called, followed by subdiagnostics - // explaining why. - if let Some(first) = self.into_iter().find(|b| b.as_result().is_err()) { - first.report_diagnostics(context, node); + for binding in self { + binding.report_diagnostics(context, node); } }