diff --git a/crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.md b/crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.md new file mode 100644 index 0000000000..303f72f29c --- /dev/null +++ b/crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.md @@ -0,0 +1,121 @@ +# Calling a union of function types + + + +```toml +[environment] +python-version = "3.12" +``` + +## A smaller scale example + +```py +def f1() -> int: + return 0 + +def f2(name: str) -> int: + return 0 + +def _(flag: bool): + if flag: + f = f1 + else: + f = f2 + # error: [too-many-positional-arguments] + x = f(3) +``` + +## Multiple variants but only one is invalid + +This test in particular demonstrates some of the smarts of this diagnostic. Namely, since only one +variant is invalid, additional context specific to that variant is added to the diagnostic output. +(If more than one variant is invalid, then this additional context is elided to avoid overwhelming +the end user.) + +```py +def f1(a: int) -> int: + return 0 + +def f2(name: str) -> int: + return 0 + +def _(flag: bool): + if flag: + f = f1 + else: + f = f2 + # error: [invalid-argument-type] + x = f(3) +``` + +## Try to cover all possible reasons + +These tests is likely to become stale over time, but this was added when the union-specific +diagnostic was initially created. In each test, we try to cover as much as we can. This is mostly +just ensuring that we get test coverage for each of the possible diagnostic messages. + +### Cover non-keyword related reasons + +```py +from inspect import getattr_static + +def f1() -> int: + return 0 + +def f2(name: str) -> int: + return 0 + +def f3(a: int, b: int) -> int: + return 0 + +def f4[T: str](x: T) -> int: + return 0 + +class OverloadExample: + def f(self, x: str) -> int: + return 0 + +f5 = getattr_static(OverloadExample, "f").__get__ + +def _(n: int): + class PossiblyNotCallable: + if n == 0: + def __call__(self) -> int: + return 0 + + if n == 0: + f = f1 + elif n == 1: + f = f2 + elif n == 2: + f = f3 + elif n == 3: + f = f4 + elif n == 4: + f = 5 + elif n == 5: + f = f5 + else: + f = PossiblyNotCallable() + # error: [too-many-positional-arguments] + x = f(3) +``` + +### Cover keyword argument related reasons + +```py +def any(*args, **kwargs) -> int: + return 0 + +def f1(name: str) -> int: + return 0 + +def _(n: int): + if n == 0: + f = f1 + else: + f = any + # error: [parameter-already-assigned] + # error: [unknown-argument] + y = f("foo", name="bar", unknown="quux") +``` 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 new file mode 100644 index 0000000000..77cd2624e5 --- /dev/null +++ b/crates/ty_python_semantic/resources/mdtest/snapshots/union_call.md_-_Calling_a_union_of_function_types_-_A_smaller_scale_example.snap @@ -0,0 +1,43 @@ +--- +source: crates/ty_test/src/lib.rs +expression: snapshot +--- +--- +mdtest name: union_call.md - Calling a union of function types - A smaller scale example +mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.md +--- + +# Python source files + +## mdtest_snippet.py + +``` + 1 | def f1() -> int: + 2 | return 0 + 3 | + 4 | def f2(name: str) -> int: + 5 | return 0 + 6 | + 7 | def _(flag: bool): + 8 | if flag: + 9 | f = f1 +10 | else: +11 | f = f2 +12 | # error: [too-many-positional-arguments] +13 | 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 + | +11 | f = f2 +12 | # error: [too-many-positional-arguments] +13 | 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_-_Multiple_variants_but_only_one_is_invalid.snap b/crates/ty_python_semantic/resources/mdtest/snapshots/union_call.md_-_Calling_a_union_of_function_types_-_Multiple_variants_but_only_one_is_invalid.snap new file mode 100644 index 0000000000..3d27c3172a --- /dev/null +++ b/crates/ty_python_semantic/resources/mdtest/snapshots/union_call.md_-_Calling_a_union_of_function_types_-_Multiple_variants_but_only_one_is_invalid.snap @@ -0,0 +1,52 @@ +--- +source: crates/ty_test/src/lib.rs +expression: snapshot +--- +--- +mdtest name: union_call.md - Calling a union of function types - Multiple variants but only one is invalid +mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.md +--- + +# Python source files + +## mdtest_snippet.py + +``` + 1 | def f1(a: int) -> int: + 2 | return 0 + 3 | + 4 | def f2(name: str) -> int: + 5 | return 0 + 6 | + 7 | def _(flag: bool): + 8 | if flag: + 9 | f = f1 +10 | else: +11 | f = f2 +12 | # error: [invalid-argument-type] +13 | x = f(3) +``` + +# Diagnostics + +``` +error: lint:invalid-argument-type: Argument to this function is incorrect + --> src/mdtest_snippet.py:13:11 + | +11 | f = f2 +12 | # error: [invalid-argument-type] +13 | 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 + +``` 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_keyword_argument_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_keyword_argument_related_reasons.snap new file mode 100644 index 0000000000..9e2b422427 --- /dev/null +++ b/crates/ty_python_semantic/resources/mdtest/snapshots/union_call.md_-_Calling_a_union_of_function_types_-_Try_to_cover_all_possible_reasons_-_Cover_keyword_argument_related_reasons.snap @@ -0,0 +1,57 @@ +--- +source: crates/ty_test/src/lib.rs +expression: snapshot +--- +--- +mdtest name: union_call.md - Calling a union of function types - Try to cover all possible reasons - Cover keyword argument related reasons +mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.md +--- + +# Python source files + +## mdtest_snippet.py + +``` + 1 | def any(*args, **kwargs) -> int: + 2 | return 0 + 3 | + 4 | def f1(name: str) -> int: + 5 | return 0 + 6 | + 7 | def _(n: int): + 8 | if n == 0: + 9 | f = f1 +10 | else: +11 | f = any +12 | # error: [parameter-already-assigned] +13 | # error: [unknown-argument] +14 | y = f("foo", name="bar", unknown="quux") +``` + +# Diagnostics + +``` +error: lint:parameter-already-assigned: Multiple values provided for parameter `name` of function `f1` + --> src/mdtest_snippet.py:14:18 + | +12 | # error: [parameter-already-assigned] +13 | # error: [unknown-argument] +14 | y = f("foo", name="bar", unknown="quux") + | ^^^^^^^^^^ + | +info: `lint:parameter-already-assigned` is enabled by default + +``` + +``` +error: lint:unknown-argument: Argument `unknown` does not match any known parameter of function `f1` + --> src/mdtest_snippet.py:14:30 + | +12 | # error: [parameter-already-assigned] +13 | # error: [unknown-argument] +14 | y = f("foo", name="bar", unknown="quux") + | ^^^^^^^^^^^^^^ + | +info: `lint:unknown-argument` 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 new file mode 100644 index 0000000000..93a36fd841 --- /dev/null +++ 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 @@ -0,0 +1,72 @@ +--- +source: crates/ty_test/src/lib.rs +expression: snapshot +--- +--- +mdtest name: union_call.md - Calling a union of function types - Try to cover all possible reasons - Cover non-keyword related reasons +mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.md +--- + +# Python source files + +## mdtest_snippet.py + +``` + 1 | from inspect import getattr_static + 2 | + 3 | def f1() -> int: + 4 | return 0 + 5 | + 6 | def f2(name: str) -> int: + 7 | return 0 + 8 | + 9 | def f3(a: int, b: int) -> int: +10 | return 0 +11 | +12 | def f4[T: str](x: T) -> int: +13 | return 0 +14 | +15 | class OverloadExample: +16 | def f(self, x: str) -> int: +17 | return 0 +18 | +19 | f5 = getattr_static(OverloadExample, "f").__get__ +20 | +21 | def _(n: int): +22 | class PossiblyNotCallable: +23 | if n == 0: +24 | def __call__(self) -> int: +25 | return 0 +26 | +27 | if n == 0: +28 | f = f1 +29 | elif n == 1: +30 | f = f2 +31 | elif n == 2: +32 | f = f3 +33 | elif n == 3: +34 | f = f4 +35 | elif n == 4: +36 | f = 5 +37 | elif n == 5: +38 | f = f5 +39 | else: +40 | f = PossiblyNotCallable() +41 | # error: [too-many-positional-arguments] +42 | 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 + | +40 | f = PossiblyNotCallable() +41 | # error: [too-many-positional-arguments] +42 | x = f(3) + | ^ + | +info: `lint:too-many-positional-arguments` is enabled by default + +```