-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[red-knot] Rewrite
Type::try_iterate()
to improve type inference an…
…d diagnostic messages (#16321)
- Loading branch information
1 parent
1be0dc6
commit 5c007db
Showing
25 changed files
with
2,099 additions
and
154 deletions.
There are no files selected for viewing
476 changes: 470 additions & 6 deletions
476
crates/red_knot_python_semantic/resources/mdtest/loops/for.md
Large diffs are not rendered by default.
Oops, something went wrong.
52 changes: 52 additions & 0 deletions
52
...on_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Bad_`__getitem__`_method.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
--- | ||
source: crates/red_knot_test/src/lib.rs | ||
expression: snapshot | ||
--- | ||
--- | ||
mdtest name: for.md - For loops - Bad `__getitem__` method | ||
mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md | ||
--- | ||
|
||
# Python source files | ||
|
||
## mdtest_snippet.py | ||
|
||
``` | ||
1 | from typing_extensions import reveal_type | ||
2 | | ||
3 | class Iterable: | ||
4 | # invalid because it will implicitly be passed an `int` | ||
5 | # by the interpreter | ||
6 | def __getitem__(self, key: str) -> int: | ||
7 | return 42 | ||
8 | | ||
9 | # error: [not-iterable] | ||
10 | for x in Iterable(): | ||
11 | reveal_type(x) # revealed: int | ||
``` | ||
|
||
# Diagnostics | ||
|
||
``` | ||
error: lint:not-iterable | ||
--> /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 | ||
| | ||
``` | ||
|
||
``` | ||
info: revealed-type | ||
--> /src/mdtest_snippet.py:11:5 | ||
| | ||
9 | # error: [not-iterable] | ||
10 | for x in Iterable(): | ||
11 | reveal_type(x) # revealed: int | ||
| -------------- info: Revealed type is `int` | ||
| | ||
``` |
32 changes: 32 additions & 0 deletions
32
...not_python_semantic/resources/mdtest/snapshots/for.md_-_For_loops_-_Invalid_iterable.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
--- | ||
source: crates/red_knot_test/src/lib.rs | ||
expression: snapshot | ||
--- | ||
--- | ||
mdtest name: for.md - For loops - Invalid iterable | ||
mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md | ||
--- | ||
|
||
# Python source files | ||
|
||
## mdtest_snippet.py | ||
|
||
``` | ||
1 | nonsense = 123 | ||
2 | for x in nonsense: # error: [not-iterable] | ||
3 | pass | ||
``` | ||
|
||
# Diagnostics | ||
|
||
``` | ||
error: lint:not-iterable | ||
--> /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 | ||
| | ||
``` |
37 changes: 37 additions & 0 deletions
37
...esources/mdtest/snapshots/for.md_-_For_loops_-_New_over_old_style_iteration_protocol.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
--- | ||
source: crates/red_knot_test/src/lib.rs | ||
expression: snapshot | ||
--- | ||
--- | ||
mdtest name: for.md - For loops - New over old style iteration protocol | ||
mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md | ||
--- | ||
|
||
# Python source files | ||
|
||
## mdtest_snippet.py | ||
|
||
``` | ||
1 | class NotIterable: | ||
2 | def __getitem__(self, key: int) -> int: | ||
3 | return 42 | ||
4 | __iter__: None = None | ||
5 | | ||
6 | for x in NotIterable(): # error: [not-iterable] | ||
7 | pass | ||
``` | ||
|
||
# Diagnostics | ||
|
||
``` | ||
error: lint:not-iterable | ||
--> /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 | ||
| | ||
``` |
49 changes: 49 additions & 0 deletions
49
...napshots/for.md_-_For_loops_-_No_`__iter__`_method_and_`__getitem__`_is_not_callable.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
--- | ||
source: crates/red_knot_test/src/lib.rs | ||
expression: snapshot | ||
--- | ||
--- | ||
mdtest name: for.md - For loops - No `__iter__` method and `__getitem__` is not callable | ||
mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md | ||
--- | ||
|
||
# Python source files | ||
|
||
## mdtest_snippet.py | ||
|
||
``` | ||
1 | from typing_extensions import reveal_type | ||
2 | | ||
3 | class Bad: | ||
4 | __getitem__: None = None | ||
5 | | ||
6 | # error: [not-iterable] | ||
7 | for x in Bad(): | ||
8 | reveal_type(x) # revealed: Unknown | ||
``` | ||
|
||
# Diagnostics | ||
|
||
``` | ||
error: lint:not-iterable | ||
--> /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 | ||
| | ||
``` | ||
|
||
``` | ||
info: revealed-type | ||
--> /src/mdtest_snippet.py:8:5 | ||
| | ||
6 | # error: [not-iterable] | ||
7 | for x in Bad(): | ||
8 | reveal_type(x) # revealed: Unknown | ||
| -------------- info: Revealed type is `Unknown` | ||
| | ||
``` |
98 changes: 98 additions & 0 deletions
98
...ces/mdtest/snapshots/for.md_-_For_loops_-_Possibly-not-callable_`__getitem__`_method.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
--- | ||
source: crates/red_knot_test/src/lib.rs | ||
expression: snapshot | ||
--- | ||
--- | ||
mdtest name: for.md - For loops - Possibly-not-callable `__getitem__` method | ||
mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md | ||
--- | ||
|
||
# Python source files | ||
|
||
## mdtest_snippet.py | ||
|
||
``` | ||
1 | from typing_extensions import reveal_type | ||
2 | | ||
3 | def _(flag: bool): | ||
4 | class CustomCallable: | ||
5 | if flag: | ||
6 | def __call__(self, *args, **kwargs) -> int: | ||
7 | return 42 | ||
8 | else: | ||
9 | __call__: None = None | ||
10 | | ||
11 | class Iterable1: | ||
12 | __getitem__: CustomCallable = CustomCallable() | ||
13 | | ||
14 | class Iterable2: | ||
15 | if flag: | ||
16 | def __getitem__(self, key: int) -> int: | ||
17 | return 42 | ||
18 | else: | ||
19 | __getitem__: None = None | ||
20 | | ||
21 | # error: [not-iterable] | ||
22 | for x in Iterable1(): | ||
23 | # TODO... `int` might be ideal here? | ||
24 | reveal_type(x) # revealed: int | Unknown | ||
25 | | ||
26 | # error: [not-iterable] | ||
27 | for y in Iterable2(): | ||
28 | # TODO... `int` might be ideal here? | ||
29 | reveal_type(y) # revealed: int | Unknown | ||
``` | ||
|
||
# Diagnostics | ||
|
||
``` | ||
error: lint:not-iterable | ||
--> /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 | ||
| | ||
``` | ||
|
||
``` | ||
info: revealed-type | ||
--> /src/mdtest_snippet.py:24:9 | ||
| | ||
22 | for x in Iterable1(): | ||
23 | # TODO... `int` might be ideal here? | ||
24 | reveal_type(x) # revealed: int | Unknown | ||
| -------------- info: Revealed type is `int | Unknown` | ||
25 | | ||
26 | # error: [not-iterable] | ||
| | ||
``` | ||
|
||
``` | ||
error: lint:not-iterable | ||
--> /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 `Literal[__getitem__] | None`) may not be callable | ||
28 | # TODO... `int` might be ideal here? | ||
29 | reveal_type(y) # revealed: int | Unknown | ||
| | ||
``` | ||
|
||
``` | ||
info: revealed-type | ||
--> /src/mdtest_snippet.py:29:9 | ||
| | ||
27 | for y in Iterable2(): | ||
28 | # TODO... `int` might be ideal here? | ||
29 | reveal_type(y) # revealed: int | Unknown | ||
| -------------- info: Revealed type is `int | Unknown` | ||
| | ||
``` |
94 changes: 94 additions & 0 deletions
94
...sources/mdtest/snapshots/for.md_-_For_loops_-_Possibly_invalid_`__getitem__`_methods.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
--- | ||
source: crates/red_knot_test/src/lib.rs | ||
expression: snapshot | ||
--- | ||
--- | ||
mdtest name: for.md - For loops - Possibly invalid `__getitem__` methods | ||
mdtest path: crates/red_knot_python_semantic/resources/mdtest/loops/for.md | ||
--- | ||
|
||
# Python source files | ||
|
||
## mdtest_snippet.py | ||
|
||
``` | ||
1 | from typing_extensions import reveal_type | ||
2 | | ||
3 | def _(flag: bool): | ||
4 | class Iterable1: | ||
5 | if flag: | ||
6 | def __getitem__(self, item: int) -> str: | ||
7 | return "foo" | ||
8 | else: | ||
9 | __getitem__: None = None | ||
10 | | ||
11 | class Iterable2: | ||
12 | if flag: | ||
13 | def __getitem__(self, item: int) -> str: | ||
14 | return "foo" | ||
15 | else: | ||
16 | def __getitem__(self, item: str) -> int: | ||
17 | return "foo" | ||
18 | | ||
19 | # error: [not-iterable] | ||
20 | for x in Iterable1(): | ||
21 | # TODO: `str` might be better | ||
22 | reveal_type(x) # revealed: str | Unknown | ||
23 | | ||
24 | # error: [not-iterable] | ||
25 | for y in Iterable2(): | ||
26 | reveal_type(y) # revealed: str | int | ||
``` | ||
|
||
# Diagnostics | ||
|
||
``` | ||
error: lint:not-iterable | ||
--> /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 `Literal[__getitem__] | None`) may not be callable | ||
21 | # TODO: `str` might be better | ||
22 | reveal_type(x) # revealed: str | Unknown | ||
| | ||
``` | ||
|
||
``` | ||
info: revealed-type | ||
--> /src/mdtest_snippet.py:22:9 | ||
| | ||
20 | for x in Iterable1(): | ||
21 | # TODO: `str` might be better | ||
22 | reveal_type(x) # revealed: str | Unknown | ||
| -------------- info: Revealed type is `str | Unknown` | ||
23 | | ||
24 | # error: [not-iterable] | ||
| | ||
``` | ||
|
||
``` | ||
error: lint:not-iterable | ||
--> /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 `Literal[__getitem__, __getitem__]`) 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 | ||
| | ||
``` | ||
|
||
``` | ||
info: revealed-type | ||
--> /src/mdtest_snippet.py:26:9 | ||
| | ||
24 | # error: [not-iterable] | ||
25 | for y in Iterable2(): | ||
26 | reveal_type(y) # revealed: str | int | ||
| -------------- info: Revealed type is `str | int` | ||
| | ||
``` |
Oops, something went wrong.