From 17f799424af74b9ec37834641bf8dda93ef34376 Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Tue, 22 Apr 2025 10:50:00 -0400 Subject: [PATCH] red_knot_python_semantic: migrate `types` to new diagnostics --- ..._For_loops_-_Bad_`__getitem__`_method.snap | 4 +- ...for.md_-_For_loops_-_Invalid_iterable.snap | 4 +- ...New_over_old_style_iteration_protocol.snap | 4 +- ...hod_and_`__getitem__`_is_not_callable.snap | 4 +- ...bly-not-callable_`__getitem__`_method.snap | 8 +- ...ossibly_invalid_`__getitem__`_methods.snap | 8 +- ...-_Possibly_invalid_`__iter__`_methods.snap | 8 +- ..._-_Possibly_invalid_`__next__`_method.snap | 8 +- ..._iter__`_and_bad_`__getitem__`_method.snap | 4 +- ..._`_and_possibly_invalid_`__getitem__`.snap | 8 +- ..._`_and_possibly_unbound_`__getitem__`.snap | 4 +- ...element_has_invalid_`__iter__`_method.snap | 4 +- ...nion_element_has_no_`__iter__`_method.snap | 4 +- ...or_loops_-_With_non-callable_iterator.snap | 4 +- ...__iter__`_does_not_return_an_iterator.snap | 4 +- ...__iter__`_method_with_a_bad_signature.snap | 4 +- ...tor_with_an_invalid_`__next__`_method.snap | 8 +- ...types_with_invalid_`__bool__`_methods.snap | 4 +- ...oesn't_implement_`__bool__`_correctly.snap | 8 +- ...hat_implements_`__bool__`_incorrectly.snap | 4 +- ..._don't_implement_`__bool__`_correctly.snap | 8 +- ...that_incorrectly_implement_`__bool__`.snap | 4 +- ...that_incorrectly_implement_`__bool__`.snap | 4 +- ...acking_-_Right_hand_side_not_iterable.snap | 4 +- crates/red_knot_python_semantic/src/types.rs | 167 +++++++++--------- 25 files changed, 144 insertions(+), 151 deletions(-) diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Bad_`__getitem__`_method.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Bad_`__getitem__`_method.snap index b80fd4586d..7c5331746e 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Bad_`__getitem__`_method.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Bad_`__getitem__`_method.snap @@ -28,12 +28,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md # Diagnostics ``` -error: lint:not-iterable +error: lint:not-iterable: Object of type `Iterable` is not iterable because it has no `__iter__` method and its `__getitem__` method has an incorrect signature for the old-style iteration protocol (expected a signature at least as permissive as `def __getitem__(self, key: int): ...`) --> /src/mdtest_snippet.py:10:10 | 9 | # error: [not-iterable] 10 | for x in Iterable(): - | ^^^^^^^^^^ Object of type `Iterable` is not iterable because it has no `__iter__` method and its `__getitem__` method has an incorrect signature for the old-style iteration protocol (expected a signature at least as permissive as `def __getitem__(self, key: int): ...`) + | ^^^^^^^^^^ 11 | reveal_type(x) # revealed: int | diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Invalid_iterable.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Invalid_iterable.snap index a8600a1547..29541bbdb2 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Invalid_iterable.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Invalid_iterable.snap @@ -20,12 +20,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md # Diagnostics ``` -error: lint:not-iterable +error: lint:not-iterable: Object of type `Literal[123]` is not iterable because it doesn't have an `__iter__` method or a `__getitem__` method --> /src/mdtest_snippet.py:2:10 | 1 | nonsense = 123 2 | for x in nonsense: # error: [not-iterable] - | ^^^^^^^^ Object of type `Literal[123]` is not iterable because it doesn't have an `__iter__` method or a `__getitem__` method + | ^^^^^^^^ 3 | pass | diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_New_over_old_style_iteration_protocol.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_New_over_old_style_iteration_protocol.snap index 59cf2147b8..9a6a707530 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_New_over_old_style_iteration_protocol.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_New_over_old_style_iteration_protocol.snap @@ -24,13 +24,13 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md # Diagnostics ``` -error: lint:not-iterable +error: lint:not-iterable: Object of type `NotIterable` is not iterable because its `__iter__` attribute has type `None`, which is not callable --> /src/mdtest_snippet.py:6:10 | 4 | __iter__: None = None 5 | 6 | for x in NotIterable(): # error: [not-iterable] - | ^^^^^^^^^^^^^ Object of type `NotIterable` is not iterable because its `__iter__` attribute has type `None`, which is not callable + | ^^^^^^^^^^^^^ 7 | pass | diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_No_`__iter__`_method_and_`__getitem__`_is_not_callable.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_No_`__iter__`_method_and_`__getitem__`_is_not_callable.snap index a9d5964a6b..69aad44e93 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_No_`__iter__`_method_and_`__getitem__`_is_not_callable.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_No_`__iter__`_method_and_`__getitem__`_is_not_callable.snap @@ -25,12 +25,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md # Diagnostics ``` -error: lint:not-iterable +error: lint:not-iterable: Object of type `Bad` is not iterable because it has no `__iter__` method and its `__getitem__` attribute has type `None`, which is not callable --> /src/mdtest_snippet.py:7:10 | 6 | # error: [not-iterable] 7 | for x in Bad(): - | ^^^^^ Object of type `Bad` is not iterable because it has no `__iter__` method and its `__getitem__` attribute has type `None`, which is not callable + | ^^^^^ 8 | reveal_type(x) # revealed: Unknown | diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly-not-callable_`__getitem__`_method.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly-not-callable_`__getitem__`_method.snap index 62695a6d1c..aef7309c4d 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly-not-callable_`__getitem__`_method.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly-not-callable_`__getitem__`_method.snap @@ -46,12 +46,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md # Diagnostics ``` -error: lint:not-iterable +error: lint:not-iterable: Object of type `Iterable1` may not be iterable because it has no `__iter__` method and its `__getitem__` attribute (with type `CustomCallable`) may not be callable --> /src/mdtest_snippet.py:22:14 | 21 | # error: [not-iterable] 22 | for x in Iterable1(): - | ^^^^^^^^^^^ Object of type `Iterable1` may not be iterable because it has no `__iter__` method and its `__getitem__` attribute (with type `CustomCallable`) may not be callable + | ^^^^^^^^^^^ 23 | # TODO... `int` might be ideal here? 24 | reveal_type(x) # revealed: int | Unknown | @@ -73,12 +73,12 @@ info: revealed-type: Revealed type ``` ``` -error: lint:not-iterable +error: lint:not-iterable: Object of type `Iterable2` may not be iterable because it has no `__iter__` method and its `__getitem__` attribute (with type `(bound method Iterable2.__getitem__(key: int) -> int) | None`) may not be callable --> /src/mdtest_snippet.py:27:14 | 26 | # error: [not-iterable] 27 | for y in Iterable2(): - | ^^^^^^^^^^^ Object of type `Iterable2` may not be iterable because it has no `__iter__` method and its `__getitem__` attribute (with type `(bound method Iterable2.__getitem__(key: int) -> int) | None`) may not be callable + | ^^^^^^^^^^^ 28 | # TODO... `int` might be ideal here? 29 | reveal_type(y) # revealed: int | Unknown | diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_invalid_`__getitem__`_methods.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_invalid_`__getitem__`_methods.snap index 1a0330059d..173adfdc41 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_invalid_`__getitem__`_methods.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_invalid_`__getitem__`_methods.snap @@ -43,12 +43,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md # Diagnostics ``` -error: lint:not-iterable +error: lint:not-iterable: Object of type `Iterable1` may not be iterable because it has no `__iter__` method and its `__getitem__` attribute (with type `(bound method Iterable1.__getitem__(item: int) -> str) | None`) may not be callable --> /src/mdtest_snippet.py:20:14 | 19 | # error: [not-iterable] 20 | for x in Iterable1(): - | ^^^^^^^^^^^ Object of type `Iterable1` may not be iterable because it has no `__iter__` method and its `__getitem__` attribute (with type `(bound method Iterable1.__getitem__(item: int) -> str) | None`) may not be callable + | ^^^^^^^^^^^ 21 | # TODO: `str` might be better 22 | reveal_type(x) # revealed: str | Unknown | @@ -70,12 +70,12 @@ info: revealed-type: Revealed type ``` ``` -error: lint:not-iterable +error: lint:not-iterable: Object of type `Iterable2` may not be iterable because it has no `__iter__` method and its `__getitem__` method (with type `(bound method Iterable2.__getitem__(item: int) -> str) | (bound method Iterable2.__getitem__(item: str) -> int)`) may have an incorrect signature for the old-style iteration protocol (expected a signature at least as permissive as `def __getitem__(self, key: int): ...`) --> /src/mdtest_snippet.py:25:14 | 24 | # error: [not-iterable] 25 | for y in Iterable2(): - | ^^^^^^^^^^^ Object of type `Iterable2` may not be iterable because it has no `__iter__` method and its `__getitem__` method (with type `(bound method Iterable2.__getitem__(item: int) -> str) | (bound method Iterable2.__getitem__(item: str) -> int)`) may have an incorrect signature for the old-style iteration protocol (expected a signature at least as permissive as `def __getitem__(self, key: int): ...`) + | ^^^^^^^^^^^ 26 | reveal_type(y) # revealed: str | int | diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_invalid_`__iter__`_methods.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_invalid_`__iter__`_methods.snap index d59db051e7..67b34560f8 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_invalid_`__iter__`_methods.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_invalid_`__iter__`_methods.snap @@ -47,12 +47,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md # Diagnostics ``` -error: lint:not-iterable +error: lint:not-iterable: Object of type `Iterable1` may not be iterable because its `__iter__` method (with type `(bound method Iterable1.__iter__() -> Iterator) | (bound method Iterable1.__iter__(invalid_extra_arg) -> Iterator)`) may have an invalid signature (expected `def __iter__(self): ...`) --> /src/mdtest_snippet.py:17:14 | 16 | # error: [not-iterable] 17 | for x in Iterable1(): - | ^^^^^^^^^^^ Object of type `Iterable1` may not be iterable because its `__iter__` method (with type `(bound method Iterable1.__iter__() -> Iterator) | (bound method Iterable1.__iter__(invalid_extra_arg) -> Iterator)`) may have an invalid signature (expected `def __iter__(self): ...`) + | ^^^^^^^^^^^ 18 | reveal_type(x) # revealed: int | @@ -73,12 +73,12 @@ info: revealed-type: Revealed type ``` ``` -error: lint:not-iterable +error: lint:not-iterable: Object of type `Iterable2` may not be iterable because its `__iter__` attribute (with type `(bound method Iterable2.__iter__() -> Iterator) | None`) may not be callable --> /src/mdtest_snippet.py:28:14 | 27 | # error: [not-iterable] 28 | for x in Iterable2(): - | ^^^^^^^^^^^ Object of type `Iterable2` may not be iterable because its `__iter__` attribute (with type `(bound method Iterable2.__iter__() -> Iterator) | None`) may not be callable + | ^^^^^^^^^^^ 29 | # TODO: `int` would probably be better here: 30 | reveal_type(x) # revealed: int | Unknown | diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_invalid_`__next__`_method.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_invalid_`__next__`_method.snap index e4957e08fd..7e56bce301 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_invalid_`__next__`_method.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_invalid_`__next__`_method.snap @@ -51,12 +51,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md # Diagnostics ``` -error: lint:not-iterable +error: lint:not-iterable: Object of type `Iterable1` may not be iterable because its `__iter__` method returns an object of type `Iterator1`, which may have an invalid `__next__` method (expected `def __next__(self): ...`) --> /src/mdtest_snippet.py:28:14 | 27 | # error: [not-iterable] 28 | for x in Iterable1(): - | ^^^^^^^^^^^ Object of type `Iterable1` may not be iterable because its `__iter__` method returns an object of type `Iterator1`, which may have an invalid `__next__` method (expected `def __next__(self): ...`) + | ^^^^^^^^^^^ 29 | reveal_type(x) # revealed: int | str | @@ -77,12 +77,12 @@ info: revealed-type: Revealed type ``` ``` -error: lint:not-iterable +error: lint:not-iterable: Object of type `Iterable2` may not be iterable because its `__iter__` method returns an object of type `Iterator2`, which has a `__next__` attribute that may not be callable --> /src/mdtest_snippet.py:32:14 | 31 | # error: [not-iterable] 32 | for y in Iterable2(): - | ^^^^^^^^^^^ Object of type `Iterable2` may not be iterable because its `__iter__` method returns an object of type `Iterator2`, which has a `__next__` attribute that may not be callable + | ^^^^^^^^^^^ 33 | # TODO: `int` would probably be better here: 34 | reveal_type(y) # revealed: int | Unknown | diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_unbound_`__iter__`_and_bad_`__getitem__`_method.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_unbound_`__iter__`_and_bad_`__getitem__`_method.snap index dfcb11a238..4aa08e1173 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_unbound_`__iter__`_and_bad_`__getitem__`_method.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_unbound_`__iter__`_and_bad_`__getitem__`_method.snap @@ -36,12 +36,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md # Diagnostics ``` -error: lint:not-iterable +error: lint:not-iterable: Object of type `Iterable` may not be iterable because it may not have an `__iter__` method and its `__getitem__` method has an incorrect signature for the old-style iteration protocol (expected a signature at least as permissive as `def __getitem__(self, key: int): ...`) --> /src/mdtest_snippet.py:18:14 | 17 | # error: [not-iterable] 18 | for x in Iterable(): - | ^^^^^^^^^^ Object of type `Iterable` may not be iterable because it may not have an `__iter__` method and its `__getitem__` method has an incorrect signature for the old-style iteration protocol (expected a signature at least as permissive as `def __getitem__(self, key: int): ...`) + | ^^^^^^^^^^ 19 | reveal_type(x) # revealed: int | bytes | diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_unbound_`__iter__`_and_possibly_invalid_`__getitem__`.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_unbound_`__iter__`_and_possibly_invalid_`__getitem__`.snap index 90a743e300..0bb17a5837 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_unbound_`__iter__`_and_possibly_invalid_`__getitem__`.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_unbound_`__iter__`_and_possibly_invalid_`__getitem__`.snap @@ -54,12 +54,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md # Diagnostics ``` -error: lint:not-iterable +error: lint:not-iterable: Object of type `Iterable1` may not be iterable because it may not have an `__iter__` method and its `__getitem__` attribute (with type `(bound method Iterable1.__getitem__(item: int) -> str) | None`) may not be callable --> /src/mdtest_snippet.py:31:14 | 30 | # error: [not-iterable] 31 | for x in Iterable1(): - | ^^^^^^^^^^^ Object of type `Iterable1` may not be iterable because it may not have an `__iter__` method and its `__getitem__` attribute (with type `(bound method Iterable1.__getitem__(item: int) -> str) | None`) may not be callable + | ^^^^^^^^^^^ 32 | # TODO: `bytes | str` might be better 33 | reveal_type(x) # revealed: bytes | str | Unknown | @@ -81,12 +81,12 @@ info: revealed-type: Revealed type ``` ``` -error: lint:not-iterable +error: lint:not-iterable: Object of type `Iterable2` may not be iterable because it may not have an `__iter__` method and its `__getitem__` method (with type `(bound method Iterable2.__getitem__(item: int) -> str) | (bound method Iterable2.__getitem__(item: str) -> int)`) may have an incorrect signature for the old-style iteration protocol (expected a signature at least as permissive as `def __getitem__(self, key: int): ...`) --> /src/mdtest_snippet.py:36:14 | 35 | # error: [not-iterable] 36 | for y in Iterable2(): - | ^^^^^^^^^^^ Object of type `Iterable2` may not be iterable because it may not have an `__iter__` method and its `__getitem__` method (with type `(bound method Iterable2.__getitem__(item: int) -> str) | (bound method Iterable2.__getitem__(item: str) -> int)`) may have an incorrect signature for the old-style iteration protocol (expected a signature at least as permissive as `def __getitem__(self, key: int): ...`) + | ^^^^^^^^^^^ 37 | reveal_type(y) # revealed: bytes | str | int | diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_unbound_`__iter__`_and_possibly_unbound_`__getitem__`.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_unbound_`__iter__`_and_possibly_unbound_`__getitem__`.snap index dacd22e758..d55e7203a2 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_unbound_`__iter__`_and_possibly_unbound_`__getitem__`.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_unbound_`__iter__`_and_possibly_unbound_`__getitem__`.snap @@ -35,12 +35,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md # Diagnostics ``` -error: lint:not-iterable +error: lint:not-iterable: Object of type `Iterable` may not be iterable because it may not have an `__iter__` method or a `__getitem__` method --> /src/mdtest_snippet.py:17:14 | 16 | # error: [not-iterable] 17 | for x in Iterable(): - | ^^^^^^^^^^ Object of type `Iterable` may not be iterable because it may not have an `__iter__` method or a `__getitem__` method + | ^^^^^^^^^^ 18 | reveal_type(x) # revealed: int | bytes | diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Union_type_as_iterable_where_one_union_element_has_invalid_`__iter__`_method.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Union_type_as_iterable_where_one_union_element_has_invalid_`__iter__`_method.snap index f5f70d0c13..1e708f0e98 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Union_type_as_iterable_where_one_union_element_has_invalid_`__iter__`_method.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Union_type_as_iterable_where_one_union_element_has_invalid_`__iter__`_method.snap @@ -36,13 +36,13 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md # Diagnostics ``` -error: lint:not-iterable +error: lint:not-iterable: Object of type `Test | Test2` may not be iterable because its `__iter__` method returns an object of type `TestIter | int`, which may not have a `__next__` method --> /src/mdtest_snippet.py:18:14 | 16 | # TODO: Improve error message to state which union variant isn't iterable (https://github.com/astral-sh/ruff/issues/13989) 17 | # error: [not-iterable] 18 | for x in Test() if flag else Test2(): - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Object of type `Test | Test2` may not be iterable because its `__iter__` method returns an object of type `TestIter | int`, which may not have a `__next__` method + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 19 | reveal_type(x) # revealed: int | diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Union_type_as_iterable_where_one_union_element_has_no_`__iter__`_method.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Union_type_as_iterable_where_one_union_element_has_no_`__iter__`_method.snap index c474ec522c..62fb5bc8e8 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Union_type_as_iterable_where_one_union_element_has_no_`__iter__`_method.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Union_type_as_iterable_where_one_union_element_has_no_`__iter__`_method.snap @@ -31,13 +31,13 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md # Diagnostics ``` -error: lint:not-iterable +error: lint:not-iterable: Object of type `Test | Literal[42]` may not be iterable because it may not have an `__iter__` method and it doesn't have a `__getitem__` method --> /src/mdtest_snippet.py:13:14 | 11 | def _(flag: bool): 12 | # error: [not-iterable] 13 | for x in Test() if flag else 42: - | ^^^^^^^^^^^^^^^^^^^^^^ Object of type `Test | Literal[42]` may not be iterable because it may not have an `__iter__` method and it doesn't have a `__getitem__` method + | ^^^^^^^^^^^^^^^^^^^^^^ 14 | reveal_type(x) # revealed: int | diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_With_non-callable_iterator.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_With_non-callable_iterator.snap index f85c26b823..bd2bfcd156 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_With_non-callable_iterator.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_With_non-callable_iterator.snap @@ -33,12 +33,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md # Diagnostics ``` -error: lint:not-iterable +error: lint:not-iterable: Object of type `NotIterable` is not iterable because its `__iter__` attribute has type `int | None`, which is not callable --> /src/mdtest_snippet.py:11:14 | 10 | # error: [not-iterable] 11 | for x in NotIterable(): - | ^^^^^^^^^^^^^ Object of type `NotIterable` is not iterable because its `__iter__` attribute has type `int | None`, which is not callable + | ^^^^^^^^^^^^^ 12 | pass | diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_`__iter__`_does_not_return_an_iterator.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_`__iter__`_does_not_return_an_iterator.snap index cf9109de80..5f66eb75e7 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_`__iter__`_does_not_return_an_iterator.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_`__iter__`_does_not_return_an_iterator.snap @@ -26,12 +26,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md # Diagnostics ``` -error: lint:not-iterable +error: lint:not-iterable: Object of type `Bad` is not iterable because its `__iter__` method returns an object of type `int`, which has no `__next__` method --> /src/mdtest_snippet.py:8:10 | 7 | # error: [not-iterable] 8 | for x in Bad(): - | ^^^^^ Object of type `Bad` is not iterable because its `__iter__` method returns an object of type `int`, which has no `__next__` method + | ^^^^^ 9 | reveal_type(x) # revealed: Unknown | diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_`__iter__`_method_with_a_bad_signature.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_`__iter__`_method_with_a_bad_signature.snap index 65331fe197..62bcf1e730 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_`__iter__`_method_with_a_bad_signature.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_`__iter__`_method_with_a_bad_signature.snap @@ -30,12 +30,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md # Diagnostics ``` -error: lint:not-iterable +error: lint:not-iterable: Object of type `Iterable` is not iterable because its `__iter__` method has an invalid signature (expected `def __iter__(self): ...`) --> /src/mdtest_snippet.py:12:10 | 11 | # error: [not-iterable] 12 | for x in Iterable(): - | ^^^^^^^^^^ Object of type `Iterable` is not iterable because its `__iter__` method has an invalid signature (expected `def __iter__(self): ...`) + | ^^^^^^^^^^ 13 | reveal_type(x) # revealed: int | diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_`__iter__`_returns_an_iterator_with_an_invalid_`__next__`_method.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_`__iter__`_returns_an_iterator_with_an_invalid_`__next__`_method.snap index 5807ade696..1d4e8e2eed 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_`__iter__`_returns_an_iterator_with_an_invalid_`__next__`_method.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_`__iter__`_returns_an_iterator_with_an_invalid_`__next__`_method.snap @@ -41,12 +41,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md # Diagnostics ``` -error: lint:not-iterable +error: lint:not-iterable: Object of type `Iterable1` is not iterable because its `__iter__` method returns an object of type `Iterator1`, which has an invalid `__next__` method (expected `def __next__(self): ...`) --> /src/mdtest_snippet.py:19:10 | 18 | # error: [not-iterable] 19 | for x in Iterable1(): - | ^^^^^^^^^^^ Object of type `Iterable1` is not iterable because its `__iter__` method returns an object of type `Iterator1`, which has an invalid `__next__` method (expected `def __next__(self): ...`) + | ^^^^^^^^^^^ 20 | reveal_type(x) # revealed: int | @@ -67,12 +67,12 @@ info: revealed-type: Revealed type ``` ``` -error: lint:not-iterable +error: lint:not-iterable: Object of type `Iterable2` is not iterable because its `__iter__` method returns an object of type `Iterator2`, which has a `__next__` attribute that is not callable --> /src/mdtest_snippet.py:23:10 | 22 | # error: [not-iterable] 23 | for y in Iterable2(): - | ^^^^^^^^^^^ Object of type `Iterable2` is not iterable because its `__iter__` method returns an object of type `Iterator2`, which has a `__next__` attribute that is not callable + | ^^^^^^^^^^^ 24 | reveal_type(y) # revealed: Unknown | diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/instances.md_-_Binary_operations_on_instances_-_Operations_involving_types_with_invalid_`__bool__`_methods.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/instances.md_-_Binary_operations_on_instances_-_Operations_involving_types_with_invalid_`__bool__`_methods.snap index cebcc87655..df0e16c766 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/instances.md_-_Binary_operations_on_instances_-_Operations_involving_types_with_invalid_`__bool__`_methods.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/instances.md_-_Binary_operations_on_instances_-_Operations_involving_types_with_invalid_`__bool__`_methods.snap @@ -24,12 +24,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/binary/instances.m # Diagnostics ``` -error: lint:unsupported-bool-conversion +error: lint:unsupported-bool-conversion: Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable --> /src/mdtest_snippet.py:7:8 | 6 | # error: [unsupported-bool-conversion] 7 | 10 and a and True - | ^ Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable + | ^ | ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/membership_test.md_-_Comparison___Membership_Test_-_Return_type_that_doesn't_implement_`__bool__`_correctly.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/membership_test.md_-_Comparison___Membership_Test_-_Return_type_that_doesn't_implement_`__bool__`_correctly.snap index c811afea2f..4412f143f7 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/membership_test.md_-_Comparison___Membership_Test_-_Return_type_that_doesn't_implement_`__bool__`_correctly.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/membership_test.md_-_Comparison___Membership_Test_-_Return_type_that_doesn't_implement_`__bool__`_correctly.snap @@ -28,12 +28,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/comparison/instanc # Diagnostics ``` -error: lint:unsupported-bool-conversion +error: lint:unsupported-bool-conversion: Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable --> /src/mdtest_snippet.py:9:1 | 8 | # error: [unsupported-bool-conversion] 9 | 10 in WithContains() - | ^^^^^^^^^^^^^^^^^^^^ Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable + | ^^^^^^^^^^^^^^^^^^^^ 10 | # error: [unsupported-bool-conversion] 11 | 10 not in WithContains() | @@ -41,13 +41,13 @@ error: lint:unsupported-bool-conversion ``` ``` -error: lint:unsupported-bool-conversion +error: lint:unsupported-bool-conversion: Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable --> /src/mdtest_snippet.py:11:1 | 9 | 10 in WithContains() 10 | # error: [unsupported-bool-conversion] 11 | 10 not in WithContains() - | ^^^^^^^^^^^^^^^^^^^^^^^^ Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable + | ^^^^^^^^^^^^^^^^^^^^^^^^ | ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/not.md_-_Unary_not_-_Object_that_implements_`__bool__`_incorrectly.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/not.md_-_Unary_not_-_Object_that_implements_`__bool__`_incorrectly.snap index 3482463acd..b02543d3a5 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/not.md_-_Unary_not_-_Object_that_implements_`__bool__`_incorrectly.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/not.md_-_Unary_not_-_Object_that_implements_`__bool__`_incorrectly.snap @@ -22,12 +22,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/unary/not.md # Diagnostics ``` -error: lint:unsupported-bool-conversion +error: lint:unsupported-bool-conversion: Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable --> /src/mdtest_snippet.py:5:1 | 4 | # error: [unsupported-bool-conversion] 5 | not NotBoolable() - | ^^^^^^^^^^^^^^^^^ Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable + | ^^^^^^^^^^^^^^^^^ | ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/rich_comparison.md_-_Comparison___Rich_Comparison_-_Chained_comparisons_with_objects_that_don't_implement_`__bool__`_correctly.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/rich_comparison.md_-_Comparison___Rich_Comparison_-_Chained_comparisons_with_objects_that_don't_implement_`__bool__`_correctly.snap index c0004ad58d..ff2b61237c 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/rich_comparison.md_-_Comparison___Rich_Comparison_-_Chained_comparisons_with_objects_that_don't_implement_`__bool__`_correctly.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/rich_comparison.md_-_Comparison___Rich_Comparison_-_Chained_comparisons_with_objects_that_don't_implement_`__bool__`_correctly.snap @@ -33,12 +33,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/comparison/instanc # Diagnostics ``` -error: lint:unsupported-bool-conversion +error: lint:unsupported-bool-conversion: Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable --> /src/mdtest_snippet.py:12:1 | 11 | # error: [unsupported-bool-conversion] 12 | 10 < Comparable() < 20 - | ^^^^^^^^^^^^^^^^^ Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable + | ^^^^^^^^^^^^^^^^^ 13 | # error: [unsupported-bool-conversion] 14 | 10 < Comparable() < Comparable() | @@ -46,13 +46,13 @@ error: lint:unsupported-bool-conversion ``` ``` -error: lint:unsupported-bool-conversion +error: lint:unsupported-bool-conversion: Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable --> /src/mdtest_snippet.py:14:1 | 12 | 10 < Comparable() < 20 13 | # error: [unsupported-bool-conversion] 14 | 10 < Comparable() < Comparable() - | ^^^^^^^^^^^^^^^^^ Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable + | ^^^^^^^^^^^^^^^^^ 15 | 16 | Comparable() < Comparable() # fine | diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/tuples.md_-_Comparison___Tuples_-_Chained_comparisons_with_elements_that_incorrectly_implement_`__bool__`.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/tuples.md_-_Comparison___Tuples_-_Chained_comparisons_with_elements_that_incorrectly_implement_`__bool__`.snap index b741702c18..f7ad96efef 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/tuples.md_-_Comparison___Tuples_-_Chained_comparisons_with_elements_that_incorrectly_implement_`__bool__`.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/tuples.md_-_Comparison___Tuples_-_Chained_comparisons_with_elements_that_incorrectly_implement_`__bool__`.snap @@ -34,12 +34,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/comparison/tuples. # Diagnostics ``` -error: lint:unsupported-bool-conversion +error: lint:unsupported-bool-conversion: Boolean conversion is unsupported for type `NotBoolable | Literal[False]`; its `__bool__` method isn't callable --> /src/mdtest_snippet.py:15:1 | 14 | # error: [unsupported-bool-conversion] 15 | a < b < b - | ^^^^^ Boolean conversion is unsupported for type `NotBoolable | Literal[False]`; its `__bool__` method isn't callable + | ^^^^^ 16 | 17 | a < b # fine | diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/tuples.md_-_Comparison___Tuples_-_Equality_with_elements_that_incorrectly_implement_`__bool__`.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/tuples.md_-_Comparison___Tuples_-_Equality_with_elements_that_incorrectly_implement_`__bool__`.snap index 1580c863e8..99de8491fc 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/tuples.md_-_Comparison___Tuples_-_Equality_with_elements_that_incorrectly_implement_`__bool__`.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/tuples.md_-_Comparison___Tuples_-_Equality_with_elements_that_incorrectly_implement_`__bool__`.snap @@ -26,12 +26,12 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/comparison/tuples. # Diagnostics ``` -error: lint:unsupported-bool-conversion +error: lint:unsupported-bool-conversion: Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable --> /src/mdtest_snippet.py:9:1 | 8 | # error: [unsupported-bool-conversion] 9 | (A(),) == (A(),) - | ^^^^^^^^^^^^^^^^ Boolean conversion is unsupported for type `NotBoolable`; its `__bool__` method isn't callable + | ^^^^^^^^^^^^^^^^ | ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/snapshots/unpacking.md_-_Unpacking_-_Right_hand_side_not_iterable.snap b/crates/red_knot_python_semantic/resources/mdtest/snapshots/unpacking.md_-_Unpacking_-_Right_hand_side_not_iterable.snap index 6f2eb7f739..026dd73c54 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/snapshots/unpacking.md_-_Unpacking_-_Right_hand_side_not_iterable.snap +++ b/crates/red_knot_python_semantic/resources/mdtest/snapshots/unpacking.md_-_Unpacking_-_Right_hand_side_not_iterable.snap @@ -18,11 +18,11 @@ mdtest path: crates/red_knot_python_semantic/resources/mdtest/diagnostics/unpack # Diagnostics ``` -error: lint:not-iterable +error: lint:not-iterable: Object of type `Literal[1]` is not iterable because it doesn't have an `__iter__` method or a `__getitem__` method --> /src/mdtest_snippet.py:1:8 | 1 | a, b = 1 # error: [not-iterable] - | ^ Object of type `Literal[1]` is not iterable because it doesn't have an `__iter__` method or a `__getitem__` method + | ^ | ``` diff --git a/crates/red_knot_python_semantic/src/types.rs b/crates/red_knot_python_semantic/src/types.rs index 06b189a2d4..87f4715269 100644 --- a/crates/red_knot_python_semantic/src/types.rs +++ b/crates/red_knot_python_semantic/src/types.rs @@ -5029,11 +5029,10 @@ impl<'db> InvalidTypeExpressionError<'db> { } = self; if is_reachable { for error in invalid_expressions { - context.report_lint_old( - &INVALID_TYPE_FORM, - node, - format_args!("{}", error.reason(context.db())), - ); + let Some(builder) = context.report_lint(&INVALID_TYPE_FORM, node) else { + continue; + }; + builder.into_diagnostic(error.reason(context.db())); } } fallback_type @@ -5218,6 +5217,11 @@ impl<'db> ContextManagerError<'db> { context_expression_type: Type<'db>, context_expression_node: ast::AnyNodeRef, ) { + let Some(builder) = context.report_lint(&INVALID_CONTEXT_MANAGER, context_expression_node) + else { + return; + }; + let format_call_dunder_error = |call_dunder_error: &CallDunderError<'db>, name: &str| { match call_dunder_error { CallDunderError::MethodNotAvailable => format!("it does not implement `{name}`"), @@ -5269,9 +5273,7 @@ impl<'db> ContextManagerError<'db> { } => format_call_dunder_errors(enter_error, "__enter__", exit_error, "__exit__"), }; - context.report_lint_old( - &INVALID_CONTEXT_MANAGER, - context_expression_node, + builder.into_diagnostic( format_args!( "Object of type `{context_expression}` cannot be used with `with` because {formatted_errors}", context_expression = context_expression_type.display(db) @@ -5369,10 +5371,13 @@ impl<'db> IterationError<'db> { iterable_type: Type<'db>, iterable_node: ast::AnyNodeRef, ) { + let Some(builder) = context.report_lint(&NOT_ITERABLE, iterable_node) else { + return; + }; let db = context.db(); let report_not_iterable = |arguments: std::fmt::Arguments| { - context.report_lint_old(&NOT_ITERABLE, iterable_node, arguments); + builder.into_diagnostic(arguments); }; // TODO: for all of these error variants, the "explanation" for the diagnostic @@ -5646,13 +5651,14 @@ impl<'db> BoolError<'db> { } fn report_diagnostic_impl(&self, context: &InferContext, condition: TextRange) { + let Some(builder) = context.report_lint(&UNSUPPORTED_BOOL_CONVERSION, condition) else { + return; + }; match self { Self::IncorrectArguments { not_boolable_type, .. } => { - context.report_lint_old( - &UNSUPPORTED_BOOL_CONVERSION, - condition, + builder.into_diagnostic( format_args!( "Boolean conversion is unsupported for type `{}`; it incorrectly implements `__bool__`", not_boolable_type.display(context.db()) @@ -5663,25 +5669,20 @@ impl<'db> BoolError<'db> { not_boolable_type, return_type, } => { - context.report_lint_old( - &UNSUPPORTED_BOOL_CONVERSION, - condition, - format_args!( - "Boolean conversion is unsupported for type `{not_boolable}`; the return type of its bool method (`{return_type}`) isn't assignable to `bool", - not_boolable = not_boolable_type.display(context.db()), - return_type = return_type.display(context.db()) - ), - ); + builder.into_diagnostic(format_args!( + "Boolean conversion is unsupported for type `{not_boolable}`; \ + the return type of its bool method (`{return_type}`) \ + isn't assignable to `bool", + not_boolable = not_boolable_type.display(context.db()), + return_type = return_type.display(context.db()) + )); } Self::NotCallable { not_boolable_type } => { - context.report_lint_old( - &UNSUPPORTED_BOOL_CONVERSION, - condition, - format_args!( - "Boolean conversion is unsupported for type `{}`; its `__bool__` method isn't callable", - not_boolable_type.display(context.db()) - ), - ); + builder.into_diagnostic(format_args!( + "Boolean conversion is unsupported for type `{}`; \ + its `__bool__` method isn't callable", + not_boolable_type.display(context.db()) + )); } Self::Union { union, .. } => { let first_error = union @@ -5690,26 +5691,20 @@ impl<'db> BoolError<'db> { .find_map(|element| element.try_bool(context.db()).err()) .unwrap(); - context.report_lint_old( - &UNSUPPORTED_BOOL_CONVERSION, - condition, - format_args!( - "Boolean conversion is unsupported for union `{}` because `{}` doesn't implement `__bool__` correctly", - Type::Union(*union).display(context.db()), - first_error.not_boolable_type().display(context.db()), - ), - ); + builder.into_diagnostic(format_args!( + "Boolean conversion is unsupported for union `{}` \ + because `{}` doesn't implement `__bool__` correctly", + Type::Union(*union).display(context.db()), + first_error.not_boolable_type().display(context.db()), + )); } Self::Other { not_boolable_type } => { - context.report_lint_old( - &UNSUPPORTED_BOOL_CONVERSION, - condition, - format_args!( - "Boolean conversion is unsupported for type `{}`; it incorrectly implements `__bool__`", - not_boolable_type.display(context.db()) - ), - ); + builder.into_diagnostic(format_args!( + "Boolean conversion is unsupported for type `{}`; \ + it incorrectly implements `__bool__`", + not_boolable_type.display(context.db()) + )); } } } @@ -5740,27 +5735,28 @@ impl<'db> ConstructorCallError<'db> { ) { let report_init_error = |call_dunder_error: &CallDunderError<'db>| match call_dunder_error { CallDunderError::MethodNotAvailable => { - // If we are using vendored typeshed, it should be impossible to have missing - // or unbound `__init__` method on a class, as all classes have `object` in MRO. - // Thus the following may only trigger if a custom typeshed is used. - context.report_lint_old( - &CALL_POSSIBLY_UNBOUND_METHOD, - context_expression_node, - format_args!( - "`__init__` method is missing on type `{}`. Make sure your `object` in typeshed has its definition.", + if let Some(builder) = + context.report_lint(&CALL_POSSIBLY_UNBOUND_METHOD, context_expression_node) + { + // If we are using vendored typeshed, it should be impossible to have missing + // or unbound `__init__` method on a class, as all classes have `object` in MRO. + // Thus the following may only trigger if a custom typeshed is used. + builder.into_diagnostic(format_args!( + "`__init__` method is missing on type `{}`. \ + Make sure your `object` in typeshed has its definition.", context_expression_type.display(context.db()), - ), - ); + )); + } } CallDunderError::PossiblyUnbound(bindings) => { - context.report_lint_old( - &CALL_POSSIBLY_UNBOUND_METHOD, - context_expression_node, - format_args!( + if let Some(builder) = + context.report_lint(&CALL_POSSIBLY_UNBOUND_METHOD, context_expression_node) + { + builder.into_diagnostic(format_args!( "Method `__init__` on type `{}` is possibly unbound.", context_expression_type.display(context.db()), - ), - ); + )); + } bindings.report_diagnostics(context, context_expression_node); } @@ -5776,14 +5772,14 @@ impl<'db> ConstructorCallError<'db> { unreachable!("`__new__` method may not be called if missing"); } CallDunderError::PossiblyUnbound(bindings) => { - context.report_lint_old( - &CALL_POSSIBLY_UNBOUND_METHOD, - context_expression_node, - format_args!( + if let Some(builder) = + context.report_lint(&CALL_POSSIBLY_UNBOUND_METHOD, context_expression_node) + { + builder.into_diagnostic(format_args!( "Method `__new__` on type `{}` is possibly unbound.", context_expression_type.display(context.db()), - ), - ); + )); + } bindings.report_diagnostics(context, context_expression_node); } @@ -7130,34 +7126,31 @@ impl BoundSuperError<'_> { pub(super) fn report_diagnostic(&self, context: &InferContext, node: AnyNodeRef) { match self { BoundSuperError::InvalidPivotClassType { pivot_class } => { - context.report_lint_old( - &INVALID_SUPER_ARGUMENT, - node, - format_args!( + if let Some(builder) = context.report_lint(&INVALID_SUPER_ARGUMENT, node) { + builder.into_diagnostic(format_args!( "`{pivot_class}` is not a valid class", pivot_class = pivot_class.display(context.db()), - ), - ); + )); + } } BoundSuperError::FailingConditionCheck { pivot_class, owner } => { - context.report_lint_old( - &INVALID_SUPER_ARGUMENT, - node, - format_args!( - "`{owner}` is not an instance or subclass of `{pivot_class}` in `super({pivot_class}, {owner})` call", + if let Some(builder) = context.report_lint(&INVALID_SUPER_ARGUMENT, node) { + builder.into_diagnostic(format_args!( + "`{owner}` is not an instance or subclass of \ + `{pivot_class}` in `super({pivot_class}, {owner})` call", pivot_class = pivot_class.display(context.db()), owner = owner.display(context.db()), - ), - ); + )); + } } BoundSuperError::UnavailableImplicitArguments => { - context.report_lint_old( - &UNAVAILABLE_IMPLICIT_SUPER_ARGUMENTS, - node, - format_args!( + if let Some(builder) = + context.report_lint(&UNAVAILABLE_IMPLICIT_SUPER_ARGUMENTS, node) + { + builder.into_diagnostic(format_args!( "Cannot determine implicit arguments for 'super()' in this context", - ), - ); + )); + } } } }