Skip to content

Commit 47f39ed

Browse files
authored
[red-knot] Meta data for Type::Todo (#14500)
## Summary Adds meta information to `Type::Todo`, allowing developers to easily trace back the origin of a particular `@Todo` type they encounter. Instead of `Type::Todo`, we now write either `type_todo!()` which creates a `@Todo[path/to/source.rs:123]` type with file and line information, or using `type_todo!("PEP 604 unions not supported")`, which creates a variant with a custom message. `Type::Todo` now contains a `TodoType` field. In release mode, this is just a zero-sized struct, in order not to create any overhead. In debug mode, this is an `enum` that contains the meta information. `Type` implements `Copy`, which means that `TodoType` also needs to be copyable. This limits the design space. We could intern `TodoType`, but I discarded this option, as it would require us to have access to the salsa DB everywhere we want to use `Type::Todo`. And it would have made the macro invocations less ergonomic (requiring us to pass `db`). So for now, the meta information is simply a `&'static str` / `u32` for the file/line variant, or a `&'static str` for the custom message. Anything involving a chain/backtrace of several `@Todo`s or similar is therefore currently not implemented. Also because we currently don't see any direct use cases for this, and because all of this will eventually go away. Note that the size of `Type` increases from 16 to 24 bytes, but only in debug mode. ## Test Plan - Observed the changes in Markdown tests. - Added custom messages for all `Type::Todo`s that were revealed in the tests - Ran red knot in release and debug mode on the following Python file: ```py def f(x: int) -> int: reveal_type(x) ``` Prints `@Todo` in release mode and `@Todo(function parameter type)` in debug mode.
1 parent aecdb8c commit 47f39ed

File tree

24 files changed

+280
-153
lines changed

24 files changed

+280
-153
lines changed

crates/red_knot_python_semantic/resources/mdtest/annotations/starred.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ Ts = TypeVarTuple("Ts")
99

1010
def append_int(*args: *Ts) -> tuple[*Ts, int]:
1111
# TODO: should show some representation of the variadic generic type
12-
reveal_type(args) # revealed: @Todo
12+
reveal_type(args) # revealed: @Todo(function parameter type)
1313

1414
return (*args, 1)
1515

1616
# TODO should be tuple[Literal[True], Literal["a"], int]
17-
reveal_type(append_int(True, "a")) # revealed: @Todo
17+
reveal_type(append_int(True, "a")) # revealed: @Todo(full tuple[...] support)
1818
```

crates/red_knot_python_semantic/resources/mdtest/assignment/annotations.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,12 @@ reveal_type(c) # revealed: tuple[str, int]
5151
reveal_type(d) # revealed: tuple[tuple[str, str], tuple[int, int]]
5252

5353
# TODO: homogenous tuples, PEP-646 tuples
54-
reveal_type(e) # revealed: @Todo
55-
reveal_type(f) # revealed: @Todo
56-
reveal_type(g) # revealed: @Todo
54+
reveal_type(e) # revealed: @Todo(full tuple[...] support)
55+
reveal_type(f) # revealed: @Todo(full tuple[...] support)
56+
reveal_type(g) # revealed: @Todo(full tuple[...] support)
5757

5858
# TODO: support more kinds of type expressions in annotations
59-
reveal_type(h) # revealed: @Todo
59+
reveal_type(h) # revealed: @Todo(full tuple[...] support)
6060

6161
reveal_type(i) # revealed: tuple[str | int, str | int]
6262
reveal_type(j) # revealed: tuple[str | int]

crates/red_knot_python_semantic/resources/mdtest/binary/instances.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -317,15 +317,15 @@ reveal_type(1 + A()) # revealed: int
317317
reveal_type(A() + "foo") # revealed: A
318318
# TODO should be `A` since `str.__add__` doesn't support `A` instances
319319
# TODO overloads
320-
reveal_type("foo" + A()) # revealed: @Todo
320+
reveal_type("foo" + A()) # revealed: @Todo(return type)
321321

322322
reveal_type(A() + b"foo") # revealed: A
323323
# TODO should be `A` since `bytes.__add__` doesn't support `A` instances
324324
reveal_type(b"foo" + A()) # revealed: bytes
325325

326326
reveal_type(A() + ()) # revealed: A
327327
# TODO this should be `A`, since `tuple.__add__` doesn't support `A` instances
328-
reveal_type(() + A()) # revealed: @Todo
328+
reveal_type(() + A()) # revealed: @Todo(return type)
329329

330330
literal_string_instance = "foo" * 1_000_000_000
331331
# the test is not testing what it's meant to be testing if this isn't a `LiteralString`:
@@ -334,7 +334,7 @@ reveal_type(literal_string_instance) # revealed: LiteralString
334334
reveal_type(A() + literal_string_instance) # revealed: A
335335
# TODO should be `A` since `str.__add__` doesn't support `A` instances
336336
# TODO overloads
337-
reveal_type(literal_string_instance + A()) # revealed: @Todo
337+
reveal_type(literal_string_instance + A()) # revealed: @Todo(return type)
338338
```
339339

340340
## Operations involving instances of classes inheriting from `Any`

crates/red_knot_python_semantic/resources/mdtest/call/function.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ async def get_int_async() -> int:
1616
return 42
1717

1818
# TODO: we don't yet support `types.CoroutineType`, should be generic `Coroutine[Any, Any, int]`
19-
reveal_type(get_int_async()) # revealed: @Todo
19+
reveal_type(get_int_async()) # revealed: @Todo(generic types.CoroutineType)
2020
```
2121

2222
## Generic
@@ -44,7 +44,7 @@ def bar() -> str:
4444
return "bar"
4545

4646
# TODO: should reveal `int`, as the decorator replaces `bar` with `foo`
47-
reveal_type(bar()) # revealed: @Todo
47+
reveal_type(bar()) # revealed: @Todo(return type)
4848
```
4949

5050
## Invalid callable

crates/red_knot_python_semantic/resources/mdtest/exception/basic.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,11 @@ def foo(
5050
help()
5151
except x as e:
5252
# TODO: should be `AttributeError`
53-
reveal_type(e) # revealed: @Todo
53+
reveal_type(e) # revealed: @Todo(exception type)
5454
except y as f:
5555
# TODO: should be `OSError | RuntimeError`
56-
reveal_type(f) # revealed: @Todo
56+
reveal_type(f) # revealed: @Todo(exception type)
5757
except z as g:
5858
# TODO: should be `BaseException`
59-
reveal_type(g) # revealed: @Todo
59+
reveal_type(g) # revealed: @Todo(exception type)
6060
```

crates/red_knot_python_semantic/resources/mdtest/generics.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ box: MyBox[int] = MyBox(5)
1818
wrong_innards: MyBox[int] = MyBox("five")
1919

2020
# TODO reveal int
21-
reveal_type(box.data) # revealed: @Todo
21+
reveal_type(box.data) # revealed: @Todo(instance attributes)
2222

2323
reveal_type(MyBox.box_model_number) # revealed: Literal[695]
2424
```
@@ -39,7 +39,7 @@ class MySecureBox[T](MyBox[T]): ...
3939
secure_box: MySecureBox[int] = MySecureBox(5)
4040
reveal_type(secure_box) # revealed: MySecureBox
4141
# TODO reveal int
42-
reveal_type(secure_box.data) # revealed: @Todo
42+
reveal_type(secure_box.data) # revealed: @Todo(instance attributes)
4343
```
4444

4545
## Cyclical class definition

crates/red_knot_python_semantic/resources/mdtest/literal/literal.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ from other import Literal
7878
a1: Literal[26]
7979

8080
def f():
81-
reveal_type(a1) # revealed: @Todo
81+
reveal_type(a1) # revealed: @Todo(generics)
8282
```
8383

8484
## Detecting typing_extensions.Literal

crates/red_knot_python_semantic/resources/mdtest/loops/async_for.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ async def foo():
1818
pass
1919

2020
# TODO: should reveal `Unknown` because `__aiter__` is not defined
21-
# revealed: @Todo
21+
# revealed: @Todo(async iterables/iterators)
2222
# error: [possibly-unresolved-reference]
2323
reveal_type(x)
2424
```
@@ -40,6 +40,6 @@ async def foo():
4040
pass
4141

4242
# error: [possibly-unresolved-reference]
43-
# revealed: @Todo
43+
# revealed: @Todo(async iterables/iterators)
4444
reveal_type(x)
4545
```

crates/red_knot_python_semantic/resources/mdtest/metaclass.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ def f(*args, **kwargs) -> int: ...
171171
class A(metaclass=f): ...
172172

173173
# TODO should be `type[int]`
174-
reveal_type(A.__class__) # revealed: @Todo
174+
reveal_type(A.__class__) # revealed: @Todo(metaclass not a class)
175175
```
176176

177177
## Cyclic

crates/red_knot_python_semantic/resources/mdtest/scopes/moduletype_attrs.md

+4-5
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ reveal_type(__doc__) # revealed: str | None
1717
# (needs support for `*` imports)
1818
reveal_type(__spec__) # revealed: Unknown | None
1919

20-
# TODO: generics
21-
reveal_type(__path__) # revealed: @Todo
20+
reveal_type(__path__) # revealed: @Todo(generics)
2221

2322
class X:
2423
reveal_type(__name__) # revealed: str
@@ -64,7 +63,7 @@ reveal_type(typing.__class__) # revealed: Literal[type]
6463

6564
# TODO: needs support for attribute access on instances, properties and generics;
6665
# should be `dict[str, Any]`
67-
reveal_type(typing.__dict__) # revealed: @Todo
66+
reveal_type(typing.__dict__) # revealed: @Todo(instance attributes)
6867
```
6968

7069
Typeshed includes a fake `__getattr__` method in the stub for `types.ModuleType` to help out with
@@ -96,8 +95,8 @@ from foo import __dict__ as foo_dict
9695

9796
# TODO: needs support for attribute access on instances, properties, and generics;
9897
# should be `dict[str, Any]` for both of these:
99-
reveal_type(foo.__dict__) # revealed: @Todo
100-
reveal_type(foo_dict) # revealed: @Todo
98+
reveal_type(foo.__dict__) # revealed: @Todo(instance attributes)
99+
reveal_type(foo_dict) # revealed: @Todo(instance attributes)
101100
```
102101

103102
## Conditionally global or `ModuleType` attribute

crates/red_knot_python_semantic/resources/mdtest/subscript/bytes.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def int_instance() -> int:
2727

2828
a = b"abcde"[int_instance()]
2929
# TODO: Support overloads... Should be `bytes`
30-
reveal_type(a) # revealed: @Todo
30+
reveal_type(a) # revealed: @Todo(return type)
3131
```
3232

3333
## Slices
@@ -47,11 +47,11 @@ def int_instance() -> int: ...
4747

4848
byte_slice1 = b[int_instance() : int_instance()]
4949
# TODO: Support overloads... Should be `bytes`
50-
reveal_type(byte_slice1) # revealed: @Todo
50+
reveal_type(byte_slice1) # revealed: @Todo(return type)
5151

5252
def bytes_instance() -> bytes: ...
5353

5454
byte_slice2 = bytes_instance()[0:5]
5555
# TODO: Support overloads... Should be `bytes`
56-
reveal_type(byte_slice2) # revealed: @Todo
56+
reveal_type(byte_slice2) # revealed: @Todo(return type)
5757
```

crates/red_knot_python_semantic/resources/mdtest/subscript/lists.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ x = [1, 2, 3]
1212
reveal_type(x) # revealed: list
1313

1414
# TODO reveal int
15-
reveal_type(x[0]) # revealed: @Todo
15+
reveal_type(x[0]) # revealed: @Todo(return type)
1616

1717
# TODO reveal list
18-
reveal_type(x[0:1]) # revealed: @Todo
18+
reveal_type(x[0:1]) # revealed: @Todo(return type)
1919

2020
# TODO error
21-
reveal_type(x["a"]) # revealed: @Todo
21+
reveal_type(x["a"]) # revealed: @Todo(return type)
2222
```
2323

2424
## Assignments within list assignment

crates/red_knot_python_semantic/resources/mdtest/subscript/string.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def int_instance() -> int: ...
2323

2424
a = "abcde"[int_instance()]
2525
# TODO: Support overloads... Should be `str`
26-
reveal_type(a) # revealed: @Todo
26+
reveal_type(a) # revealed: @Todo(return type)
2727
```
2828

2929
## Slices
@@ -78,13 +78,13 @@ def int_instance() -> int: ...
7878

7979
substring1 = s[int_instance() : int_instance()]
8080
# TODO: Support overloads... Should be `LiteralString`
81-
reveal_type(substring1) # revealed: @Todo
81+
reveal_type(substring1) # revealed: @Todo(return type)
8282

8383
def str_instance() -> str: ...
8484

8585
substring2 = str_instance()[0:5]
8686
# TODO: Support overloads... Should be `str`
87-
reveal_type(substring2) # revealed: @Todo
87+
reveal_type(substring2) # revealed: @Todo(return type)
8888
```
8989

9090
## Unsupported slice types

crates/red_knot_python_semantic/resources/mdtest/subscript/tuple.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,5 @@ def int_instance() -> int: ...
7171

7272
tuple_slice = t[int_instance() : int_instance()]
7373
# TODO: Support overloads... Should be `tuple[Literal[1, 'a', b"b"] | None, ...]`
74-
reveal_type(tuple_slice) # revealed: @Todo
74+
reveal_type(tuple_slice) # revealed: @Todo(return type)
7575
```

crates/red_knot_python_semantic/resources/mdtest/sys_version_info.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,9 @@ properties on instance types:
112112
```py path=b.py
113113
import sys
114114

115-
reveal_type(sys.version_info.micro) # revealed: @Todo
116-
reveal_type(sys.version_info.releaselevel) # revealed: @Todo
117-
reveal_type(sys.version_info.serial) # revealed: @Todo
115+
reveal_type(sys.version_info.micro) # revealed: @Todo(instance attributes)
116+
reveal_type(sys.version_info.releaselevel) # revealed: @Todo(instance attributes)
117+
reveal_type(sys.version_info.serial) # revealed: @Todo(instance attributes)
118118
```
119119

120120
## Accessing fields by index/slice

crates/red_knot_python_semantic/resources/mdtest/unpacking.md

+11-11
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ reveal_type(b) # revealed: Literal[2]
8484
[a, *b, c, d] = (1, 2)
8585
reveal_type(a) # revealed: Literal[1]
8686
# TODO: Should be list[Any] once support for assigning to starred expression is added
87-
reveal_type(b) # revealed: @Todo
87+
reveal_type(b) # revealed: @Todo(starred unpacking)
8888
reveal_type(c) # revealed: Literal[2]
8989
reveal_type(d) # revealed: Unknown
9090
```
@@ -95,7 +95,7 @@ reveal_type(d) # revealed: Unknown
9595
[a, *b, c] = (1, 2)
9696
reveal_type(a) # revealed: Literal[1]
9797
# TODO: Should be list[Any] once support for assigning to starred expression is added
98-
reveal_type(b) # revealed: @Todo
98+
reveal_type(b) # revealed: @Todo(starred unpacking)
9999
reveal_type(c) # revealed: Literal[2]
100100
```
101101

@@ -105,7 +105,7 @@ reveal_type(c) # revealed: Literal[2]
105105
[a, *b, c] = (1, 2, 3)
106106
reveal_type(a) # revealed: Literal[1]
107107
# TODO: Should be list[int] once support for assigning to starred expression is added
108-
reveal_type(b) # revealed: @Todo
108+
reveal_type(b) # revealed: @Todo(starred unpacking)
109109
reveal_type(c) # revealed: Literal[3]
110110
```
111111

@@ -115,7 +115,7 @@ reveal_type(c) # revealed: Literal[3]
115115
[a, *b, c, d] = (1, 2, 3, 4, 5, 6)
116116
reveal_type(a) # revealed: Literal[1]
117117
# TODO: Should be list[int] once support for assigning to starred expression is added
118-
reveal_type(b) # revealed: @Todo
118+
reveal_type(b) # revealed: @Todo(starred unpacking)
119119
reveal_type(c) # revealed: Literal[5]
120120
reveal_type(d) # revealed: Literal[6]
121121
```
@@ -127,7 +127,7 @@ reveal_type(d) # revealed: Literal[6]
127127
reveal_type(a) # revealed: Literal[1]
128128
reveal_type(b) # revealed: Literal[2]
129129
# TODO: Should be list[int] once support for assigning to starred expression is added
130-
reveal_type(c) # revealed: @Todo
130+
reveal_type(c) # revealed: @Todo(starred unpacking)
131131
```
132132

133133
### Starred expression (6)
@@ -138,7 +138,7 @@ reveal_type(c) # revealed: @Todo
138138
reveal_type(a) # revealed: Literal[1]
139139
reveal_type(b) # revealed: Unknown
140140
reveal_type(c) # revealed: Unknown
141-
reveal_type(d) # revealed: @Todo
141+
reveal_type(d) # revealed: @Todo(starred unpacking)
142142
reveal_type(e) # revealed: Unknown
143143
reveal_type(f) # revealed: Unknown
144144
```
@@ -222,7 +222,7 @@ reveal_type(b) # revealed: LiteralString
222222
(a, *b, c, d) = "ab"
223223
reveal_type(a) # revealed: LiteralString
224224
# TODO: Should be list[LiteralString] once support for assigning to starred expression is added
225-
reveal_type(b) # revealed: @Todo
225+
reveal_type(b) # revealed: @Todo(starred unpacking)
226226
reveal_type(c) # revealed: LiteralString
227227
reveal_type(d) # revealed: Unknown
228228
```
@@ -233,7 +233,7 @@ reveal_type(d) # revealed: Unknown
233233
(a, *b, c) = "ab"
234234
reveal_type(a) # revealed: LiteralString
235235
# TODO: Should be list[Any] once support for assigning to starred expression is added
236-
reveal_type(b) # revealed: @Todo
236+
reveal_type(b) # revealed: @Todo(starred unpacking)
237237
reveal_type(c) # revealed: LiteralString
238238
```
239239

@@ -243,7 +243,7 @@ reveal_type(c) # revealed: LiteralString
243243
(a, *b, c) = "abc"
244244
reveal_type(a) # revealed: LiteralString
245245
# TODO: Should be list[LiteralString] once support for assigning to starred expression is added
246-
reveal_type(b) # revealed: @Todo
246+
reveal_type(b) # revealed: @Todo(starred unpacking)
247247
reveal_type(c) # revealed: LiteralString
248248
```
249249

@@ -253,7 +253,7 @@ reveal_type(c) # revealed: LiteralString
253253
(a, *b, c, d) = "abcdef"
254254
reveal_type(a) # revealed: LiteralString
255255
# TODO: Should be list[LiteralString] once support for assigning to starred expression is added
256-
reveal_type(b) # revealed: @Todo
256+
reveal_type(b) # revealed: @Todo(starred unpacking)
257257
reveal_type(c) # revealed: LiteralString
258258
reveal_type(d) # revealed: LiteralString
259259
```
@@ -265,5 +265,5 @@ reveal_type(d) # revealed: LiteralString
265265
reveal_type(a) # revealed: LiteralString
266266
reveal_type(b) # revealed: LiteralString
267267
# TODO: Should be list[int] once support for assigning to starred expression is added
268-
reveal_type(c) # revealed: @Todo
268+
reveal_type(c) # revealed: @Todo(starred unpacking)
269269
```

crates/red_knot_python_semantic/resources/mdtest/with/async.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@ class Manager:
1717

1818
async def test():
1919
async with Manager() as f:
20-
reveal_type(f) # revealed: @Todo
20+
reveal_type(f) # revealed: @Todo(async with statement)
2121
```

0 commit comments

Comments
 (0)