Skip to content

Commit b889571

Browse files
authored
[ty] Use infer_type_expression for parsing parameter annotations and return-type annotations (#24353)
## Summary Currently we call `infer_annotation_expression` on return annotations and parameter annotations, and then after that we do some ad-hoc checks to make sure that the `TypeAndQualifiers` returned doesn't actually have any qualifiers in it. A simpler way of checking that an annotation expression doesn't contain type qualifiers is by simply calling `infer_type_expression` rather than `infer_annotation_expression`, since type qualifiers are always banned in type expressions -- they're only valid in annotation expressions. A naive way of doing this would regress our error messages -- rather than saying "Type qualifiers are not valid in parameter annotations", we would end up with the vaguer and more jargon-y "Type qualifiers are not valid in type expressions" error message. That's easily fixed, however, by plumbing some more context through our existing `InferenceFlags` bitflag. Doing this allows us to improve many of our existing error messages as well. ## Test Plan mdtests updated
1 parent 3286a62 commit b889571

34 files changed

Lines changed: 492 additions & 383 deletions

crates/ty/docs/rules.md

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ty_python_semantic/resources/mdtest/annotations/callable.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ def _(c: Callable[42, str]):
5252
Or, when one of the parameter type is invalid in the list:
5353

5454
```py
55-
# error: [invalid-type-form] "Int literals are not allowed in this context in a type expression"
56-
# error: [invalid-type-form] "Boolean literals are not allowed in this context in a type expression"
55+
# error: [invalid-type-form] "Int literals are not allowed in this context in a parameter annotation"
56+
# error: [invalid-type-form] "Boolean literals are not allowed in this context in a parameter annotation"
5757
def _(c: Callable[[int, 42, str, False], None]):
5858
# revealed: (int, Unknown, str, Unknown, /) -> None
5959
reveal_type(c)
@@ -69,7 +69,7 @@ def _(c: Callable[[...], int]):
6969
```
7070

7171
```py
72-
# error: [invalid-type-form] "`...` is not allowed in this context in a type expression"
72+
# error: [invalid-type-form] "`...` is not allowed in this context in a parameter annotation"
7373
def _(c: Callable[[int, ...], int]):
7474
reveal_type(c) # revealed: (int, Unknown, /) -> int
7575
```
@@ -114,7 +114,7 @@ from typing import Callable
114114
# fmt: off
115115

116116
def _(c: Callable[
117-
# error: [invalid-type-form] "Int literals are not allowed in this context in a type expression"
117+
# error: [invalid-type-form] "Int literals are not allowed in this context in a parameter annotation"
118118
{1, 2}, 2 # error: [invalid-type-form] "The first argument to `Callable` must be either a list of types, ParamSpec, Concatenate, or `...`"
119119
]
120120
):
@@ -143,7 +143,7 @@ from typing import Callable
143143

144144
def _(c: Callable[
145145
int, # error: [invalid-type-form] "The first argument to `Callable` must be either a list of types, ParamSpec, Concatenate, or `...`"
146-
[str] # error: [invalid-type-form] "List literals are not allowed in this context in a type expression"
146+
[str] # error: [invalid-type-form] "List literals are not allowed in this context in a parameter annotation"
147147
]
148148
):
149149
reveal_type(c) # revealed: (...) -> Unknown
@@ -158,7 +158,7 @@ from typing import Callable
158158

159159
def _(c: Callable[
160160
int, # error: [invalid-type-form] "The first argument to `Callable` must be either a list of types, ParamSpec, Concatenate, or `...`"
161-
(str, ) # error: [invalid-type-form] "Tuple literals are not allowed in this context in a type expression"
161+
(str, ) # error: [invalid-type-form] "Tuple literals are not allowed in this context in a parameter annotation"
162162
]
163163
):
164164
reveal_type(c) # revealed: (...) -> Unknown
@@ -169,7 +169,7 @@ def _(c: Callable[
169169
```py
170170
from typing import Callable
171171

172-
# error: [invalid-type-form] "List literals are not allowed in this context in a type expression"
172+
# error: [invalid-type-form] "List literals are not allowed in this context in a parameter annotation"
173173
def _(c: Callable[[int], [str]]):
174174
reveal_type(c) # revealed: (int, /) -> Unknown
175175
```
@@ -184,8 +184,8 @@ from typing import Callable
184184

185185
def _(c: Callable[ # error: [invalid-type-form] "Special form `typing.Callable` expected exactly two arguments (parameter types and return type)"
186186
[int],
187-
[str], # error: [invalid-type-form] "List literals are not allowed in this context in a type expression"
188-
[bytes] # error: [invalid-type-form] "List literals are not allowed in this context in a type expression"
187+
[str], # error: [invalid-type-form] "List literals are not allowed in this context in a parameter annotation"
188+
[bytes] # error: [invalid-type-form] "List literals are not allowed in this context in a parameter annotation"
189189
]
190190
):
191191
reveal_type(c) # revealed: (...) -> Unknown

crates/ty_python_semantic/resources/mdtest/annotations/generic_alias.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ reveal_type(Strings) # revealed: GenericAlias
2828
However, using such a `GenericAlias` instance in a type expression is currently not supported:
2929

3030
```py
31-
# error: [invalid-type-form] "Variable of type `GenericAlias` is not allowed in a type expression"
31+
# error: [invalid-type-form] "Variable of type `GenericAlias` is not allowed in a parameter annotation"
3232
def _(strings: Strings) -> None:
3333
reveal_type(strings) # revealed: Unknown
3434
```

crates/ty_python_semantic/resources/mdtest/annotations/invalid.md

Lines changed: 49 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def _(
2525
):
2626
def foo(): ...
2727
def invalid(
28-
a_: a, # error: [invalid-type-form] "Variable of type `type[int]` is not allowed in a type expression"
28+
a_: a, # error: [invalid-type-form] "Variable of type `type[int]` is not allowed in a parameter annotation"
2929
b_: b, # error: [invalid-type-form]
3030
c_: c, # error: [invalid-type-form]
3131
d_: d, # error: [invalid-type-form]
@@ -35,8 +35,8 @@ def _(
3535
h_: h, # error: [invalid-type-form]
3636
i_: typing, # error: [invalid-type-form]
3737
j_: foo, # error: [invalid-type-form]
38-
k_: i, # error: [invalid-type-form] "Variable of type `int` is not allowed in a type expression"
39-
l_: j, # error: [invalid-type-form] "Variable of type `A` is not allowed in a type expression"
38+
k_: i, # error: [invalid-type-form] "Variable of type `int` is not allowed in a parameter annotation"
39+
l_: j, # error: [invalid-type-form] "Variable of type `A` is not allowed in a parameter annotation"
4040
):
4141
reveal_type(a_) # revealed: Unknown
4242
reveal_type(b_) # revealed: Unknown
@@ -80,37 +80,37 @@ def bar() -> None:
8080

8181
def outer_sync(): # `yield` from is only valid syntax inside a synchronous function
8282
def _(
83-
a: (yield from [1]), # error: [invalid-type-form] "`yield from` expressions are not allowed in type expressions"
83+
a: (yield from [1]), # error: [invalid-type-form] "`yield from` expressions are not allowed in parameter annotations"
8484
): ...
8585

8686
async def baz(): ...
8787
async def outer_async(): # avoid unrelated syntax errors on `yield` and `await`
8888
def _(
89-
a: 1, # error: [invalid-type-form] "Int literals are not allowed in this context in a type expression"
90-
b: 2.3, # error: [invalid-type-form] "Float literals are not allowed in type expressions"
91-
c: 4j, # error: [invalid-type-form] "Complex literals are not allowed in type expressions"
92-
d: True, # error: [invalid-type-form] "Boolean literals are not allowed in this context in a type expression"
89+
a: 1, # error: [invalid-type-form] "Int literals are not allowed in this context in a parameter annotation"
90+
b: 2.3, # error: [invalid-type-form] "Float literals are not allowed in parameter annotations"
91+
c: 4j, # error: [invalid-type-form] "Complex literals are not allowed in parameter annotations"
92+
d: True, # error: [invalid-type-form] "Boolean literals are not allowed in this context in a parameter annotation"
9393
# error: [unsupported-operator]
94-
# error: [invalid-type-form] "Bytes literals are not allowed in this context in a type expression"
94+
# error: [invalid-type-form] "Bytes literals are not allowed in this context in a parameter annotation"
9595
e: int | b"foo",
96-
f: 1 and 2, # error: [invalid-type-form] "Boolean operations are not allowed in type expressions"
97-
g: 1 or 2, # error: [invalid-type-form] "Boolean operations are not allowed in type expressions"
98-
h: (foo := 1), # error: [invalid-type-form] "Named expressions are not allowed in type expressions"
99-
i: not 1, # error: [invalid-type-form] "Unary operations are not allowed in type expressions"
100-
j: lambda: 1, # error: [invalid-type-form] "`lambda` expressions are not allowed in type expressions"
101-
k: 1 if True else 2, # error: [invalid-type-form] "`if` expressions are not allowed in type expressions"
102-
l: await baz(), # error: [invalid-type-form] "`await` expressions are not allowed in type expressions"
103-
m: (yield 1), # error: [invalid-type-form] "`yield` expressions are not allowed in type expressions"
104-
n: 1 < 2, # error: [invalid-type-form] "Comparison expressions are not allowed in type expressions"
105-
o: bar(), # error: [invalid-type-form] "Function calls are not allowed in type expressions"
96+
f: 1 and 2, # error: [invalid-type-form] "Boolean operations are not allowed in parameter annotations"
97+
g: 1 or 2, # error: [invalid-type-form] "Boolean operations are not allowed in parameter annotations"
98+
h: (foo := 1), # error: [invalid-type-form] "Named expressions are not allowed in parameter annotations"
99+
i: not 1, # error: [invalid-type-form] "Unary operations are not allowed in parameter annotations"
100+
j: lambda: 1, # error: [invalid-type-form] "`lambda` expressions are not allowed in parameter annotations"
101+
k: 1 if True else 2, # error: [invalid-type-form] "`if` expressions are not allowed in parameter annotations"
102+
l: await baz(), # error: [invalid-type-form] "`await` expressions are not allowed in parameter annotations"
103+
m: (yield 1), # error: [invalid-type-form] "`yield` expressions are not allowed in parameter annotations"
104+
n: 1 < 2, # error: [invalid-type-form] "Comparison expressions are not allowed in parameter annotations"
105+
o: bar(), # error: [invalid-type-form] "Function calls are not allowed in parameter annotations"
106106
# error: [unsupported-operator]
107-
# error: [invalid-type-form] "F-strings are not allowed in type expressions"
107+
# error: [invalid-type-form] "F-strings are not allowed in parameter annotations"
108108
p: int | f"foo",
109-
# error: [invalid-type-form] "Only simple names and dotted names can be subscripted in type expressions"
109+
# error: [invalid-type-form] "Only simple names and dotted names can be subscripted in parameter annotations"
110110
q: [1, 2, 3][1:2],
111-
# error: [invalid-type-form] "Only simple names and dotted names can be subscripted in type expressions"
111+
# error: [invalid-type-form] "Only simple names and dotted names can be subscripted in parameter annotations"
112112
r: list[T][int],
113-
# error: [invalid-type-form] "Only simple names and dotted names can be subscripted in type expressions"
113+
# error: [invalid-type-form] "Only simple names and dotted names can be subscripted in parameter annotations"
114114
s: list[list[T][int]],
115115
):
116116
reveal_type(a) # revealed: Unknown
@@ -270,25 +270,25 @@ def bar() -> None:
270270
async def baz(): ...
271271
async def outer_async(): # avoid unrelated syntax errors on `yield` and `await`
272272
def _(
273-
a: "1", # error: [invalid-type-form] "Int literals are not allowed in this context in a type expression"
274-
b: "2.3", # error: [invalid-type-form] "Float literals are not allowed in type expressions"
275-
c: "4j", # error: [invalid-type-form] "Complex literals are not allowed in type expressions"
276-
d: "True", # error: [invalid-type-form] "Boolean literals are not allowed in this context in a type expression"
277-
e: "1 and 2", # error: [invalid-type-form] "Boolean operations are not allowed in type expressions"
278-
f: "1 or 2", # error: [invalid-type-form] "Boolean operations are not allowed in type expressions"
279-
g: "(foo := 1)", # error: [invalid-type-form] "Named expressions are not allowed in type expressions"
280-
h: "not 1", # error: [invalid-type-form] "Unary operations are not allowed in type expressions"
281-
i: "lambda: 1", # error: [invalid-type-form] "`lambda` expressions are not allowed in type expressions"
282-
j: "1 if True else 2", # error: [invalid-type-form] "`if` expressions are not allowed in type expressions"
283-
k: "await baz()", # error: [invalid-type-form] "`await` expressions are not allowed in type expressions"
284-
l: "(yield 1)", # error: [invalid-type-form] "`yield` expressions are not allowed in type expressions"
285-
m: "1 < 2", # error: [invalid-type-form] "Comparison expressions are not allowed in type expressions"
286-
n: "bar()", # error: [invalid-type-form] "Function calls are not allowed in type expressions"
287-
# error: [invalid-type-form] "Only simple names and dotted names can be subscripted in type expressions"
273+
a: "1", # error: [invalid-type-form] "Int literals are not allowed in this context in a parameter annotation"
274+
b: "2.3", # error: [invalid-type-form] "Float literals are not allowed in parameter annotations"
275+
c: "4j", # error: [invalid-type-form] "Complex literals are not allowed in parameter annotations"
276+
d: "True", # error: [invalid-type-form] "Boolean literals are not allowed in this context in a parameter annotation"
277+
e: "1 and 2", # error: [invalid-type-form] "Boolean operations are not allowed in parameter annotations"
278+
f: "1 or 2", # error: [invalid-type-form] "Boolean operations are not allowed in parameter annotations"
279+
g: "(foo := 1)", # error: [invalid-type-form] "Named expressions are not allowed in parameter annotations"
280+
h: "not 1", # error: [invalid-type-form] "Unary operations are not allowed in parameter annotations"
281+
i: "lambda: 1", # error: [invalid-type-form] "`lambda` expressions are not allowed in parameter annotations"
282+
j: "1 if True else 2", # error: [invalid-type-form] "`if` expressions are not allowed in parameter annotations"
283+
k: "await baz()", # error: [invalid-type-form] "`await` expressions are not allowed in parameter annotations"
284+
l: "(yield 1)", # error: [invalid-type-form] "`yield` expressions are not allowed in parameter annotations"
285+
m: "1 < 2", # error: [invalid-type-form] "Comparison expressions are not allowed in parameter annotations"
286+
n: "bar()", # error: [invalid-type-form] "Function calls are not allowed in parameter annotations"
287+
# error: [invalid-type-form] "Only simple names and dotted names can be subscripted in parameter annotations"
288288
o: "[1, 2, 3][1:2]",
289-
# error: [invalid-type-form] "Only simple names, dotted names and subscripts can be used in type expressions"
289+
# error: [invalid-type-form] "Only simple names, dotted names and subscripts can be used in parameter annotations"
290290
p: list[int].append,
291-
# error: [invalid-type-form] "Only simple names, dotted names and subscripts can be used in type expressions"
291+
# error: [invalid-type-form] "Only simple names, dotted names and subscripts can be used in parameter annotations"
292292
q: list[list[int].append],
293293
):
294294
reveal_type(a) # revealed: Unknown
@@ -319,17 +319,17 @@ python-version = "3.12"
319319

320320
```py
321321
def _(
322-
a: {1: 2}, # error: [invalid-type-form] "Dict literals are not allowed in type expressions"
323-
b: {1, 2}, # error: [invalid-type-form] "Set literals are not allowed in type expressions"
324-
c: {k: v for k, v in [(1, 2)]}, # error: [invalid-type-form] "Dict comprehensions are not allowed in type expressions"
325-
d: [k for k in [1, 2]], # error: [invalid-type-form] "List comprehensions are not allowed in type expressions"
326-
e: {k for k in [1, 2]}, # error: [invalid-type-form] "Set comprehensions are not allowed in type expressions"
327-
f: (k for k in [1, 2]), # error: [invalid-type-form] "Generator expressions are not allowed in type expressions"
328-
# error: [invalid-type-form] "List literals are not allowed in this context in a type expression"
322+
a: {1: 2}, # error: [invalid-type-form] "Dict literals are not allowed in parameter annotations"
323+
b: {1, 2}, # error: [invalid-type-form] "Set literals are not allowed in parameter annotations"
324+
c: {k: v for k, v in [(1, 2)]}, # error: [invalid-type-form] "Dict comprehensions are not allowed in parameter annotations"
325+
d: [k for k in [1, 2]], # error: [invalid-type-form] "List comprehensions are not allowed in parameter annotations"
326+
e: {k for k in [1, 2]}, # error: [invalid-type-form] "Set comprehensions are not allowed in parameter annotations"
327+
f: (k for k in [1, 2]), # error: [invalid-type-form] "Generator expressions are not allowed in parameter annotations"
328+
# error: [invalid-type-form] "List literals are not allowed in this context in a parameter annotation"
329329
g: [int, str],
330-
# error: [invalid-type-form] "Tuple literals are not allowed in this context in a type expression: Did you mean `tuple[int, str]`?"
330+
# error: [invalid-type-form] "Tuple literals are not allowed in this context in a parameter annotation: Did you mean `tuple[int, str]`?"
331331
h: (int, str),
332-
i: (), # error: [invalid-type-form] "Tuple literals are not allowed in this context in a type expression: Did you mean `tuple[()]`?"
332+
i: (), # error: [invalid-type-form] "Tuple literals are not allowed in this context in a parameter annotation: Did you mean `tuple[()]`?"
333333
):
334334
reveal_type(a) # revealed: Unknown
335335
reveal_type(b) # revealed: Unknown

crates/ty_python_semantic/resources/mdtest/annotations/literal.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ from other import Literal
329329
#
330330
# ?
331331
#
332-
# error: [invalid-type-form] "Invalid subscript of object of type `_SpecialForm` in type expression"
332+
# error: [invalid-type-form] "Invalid subscript of object of type `_SpecialForm` in a type expression"
333333
a1: Literal[26]
334334

335335
def f():

0 commit comments

Comments
 (0)