diff --git a/crates/ty/docs/rules.md b/crates/ty/docs/rules.md
index 1e62ff958d6b91..8d53b96ac0ebda 100644
--- a/crates/ty/docs/rules.md
+++ b/crates/ty/docs/rules.md
@@ -584,7 +584,7 @@ def bar() -> str:
Default level: error ·
Added in 0.0.1-alpha.1 ·
Related issues ·
-View source
+View source
@@ -705,7 +705,7 @@ a = 20 / 0 # ty: ignore[division-by-zero]
Default level: error ·
Added in 0.0.1-alpha.1 ·
Related issues ·
-View source
+View source
@@ -2138,7 +2138,7 @@ super(B, A) # error: `A` does not satisfy `issubclass(A, B)`
Default level: error ·
Added in 0.0.1-alpha.1 ·
Related issues ·
-View source
+View source
@@ -3160,7 +3160,7 @@ print(x) # NameError: name 'x' is not defined
Default level: error ·
Added in 0.0.1-alpha.1 ·
Related issues ·
-View source
+View source
diff --git a/crates/ty_python_semantic/resources/mdtest/annotations/callable.md b/crates/ty_python_semantic/resources/mdtest/annotations/callable.md
index 76d42b11c4b0b4..3fa30ed73afa4d 100644
--- a/crates/ty_python_semantic/resources/mdtest/annotations/callable.md
+++ b/crates/ty_python_semantic/resources/mdtest/annotations/callable.md
@@ -52,8 +52,8 @@ def _(c: Callable[42, str]):
Or, when one of the parameter type is invalid in the list:
```py
-# error: [invalid-type-form] "Int literals are not allowed in this context in a type expression"
-# error: [invalid-type-form] "Boolean literals are not allowed in this context in a type expression"
+# error: [invalid-type-form] "Int literals are not allowed in this context in a parameter annotation"
+# error: [invalid-type-form] "Boolean literals are not allowed in this context in a parameter annotation"
def _(c: Callable[[int, 42, str, False], None]):
# revealed: (int, Unknown, str, Unknown, /) -> None
reveal_type(c)
@@ -69,7 +69,7 @@ def _(c: Callable[[...], int]):
```
```py
-# error: [invalid-type-form] "`...` is not allowed in this context in a type expression"
+# error: [invalid-type-form] "`...` is not allowed in this context in a parameter annotation"
def _(c: Callable[[int, ...], int]):
reveal_type(c) # revealed: (int, Unknown, /) -> int
```
@@ -114,7 +114,7 @@ from typing import Callable
# fmt: off
def _(c: Callable[
- # error: [invalid-type-form] "Int literals are not allowed in this context in a type expression"
+ # error: [invalid-type-form] "Int literals are not allowed in this context in a parameter annotation"
{1, 2}, 2 # error: [invalid-type-form] "The first argument to `Callable` must be either a list of types, ParamSpec, Concatenate, or `...`"
]
):
@@ -143,7 +143,7 @@ from typing import Callable
def _(c: Callable[
int, # error: [invalid-type-form] "The first argument to `Callable` must be either a list of types, ParamSpec, Concatenate, or `...`"
- [str] # error: [invalid-type-form] "List literals are not allowed in this context in a type expression"
+ [str] # error: [invalid-type-form] "List literals are not allowed in this context in a parameter annotation"
]
):
reveal_type(c) # revealed: (...) -> Unknown
@@ -158,7 +158,7 @@ from typing import Callable
def _(c: Callable[
int, # error: [invalid-type-form] "The first argument to `Callable` must be either a list of types, ParamSpec, Concatenate, or `...`"
- (str, ) # error: [invalid-type-form] "Tuple literals are not allowed in this context in a type expression"
+ (str, ) # error: [invalid-type-form] "Tuple literals are not allowed in this context in a parameter annotation"
]
):
reveal_type(c) # revealed: (...) -> Unknown
@@ -169,7 +169,7 @@ def _(c: Callable[
```py
from typing import Callable
-# error: [invalid-type-form] "List literals are not allowed in this context in a type expression"
+# error: [invalid-type-form] "List literals are not allowed in this context in a parameter annotation"
def _(c: Callable[[int], [str]]):
reveal_type(c) # revealed: (int, /) -> Unknown
```
@@ -184,8 +184,8 @@ from typing import Callable
def _(c: Callable[ # error: [invalid-type-form] "Special form `typing.Callable` expected exactly two arguments (parameter types and return type)"
[int],
- [str], # error: [invalid-type-form] "List literals are not allowed in this context in a type expression"
- [bytes] # error: [invalid-type-form] "List literals are not allowed in this context in a type expression"
+ [str], # error: [invalid-type-form] "List literals are not allowed in this context in a parameter annotation"
+ [bytes] # error: [invalid-type-form] "List literals are not allowed in this context in a parameter annotation"
]
):
reveal_type(c) # revealed: (...) -> Unknown
diff --git a/crates/ty_python_semantic/resources/mdtest/annotations/generic_alias.md b/crates/ty_python_semantic/resources/mdtest/annotations/generic_alias.md
index 86a115d90e50be..4a9f1ac67b4787 100644
--- a/crates/ty_python_semantic/resources/mdtest/annotations/generic_alias.md
+++ b/crates/ty_python_semantic/resources/mdtest/annotations/generic_alias.md
@@ -28,7 +28,7 @@ reveal_type(Strings) # revealed: GenericAlias
However, using such a `GenericAlias` instance in a type expression is currently not supported:
```py
-# error: [invalid-type-form] "Variable of type `GenericAlias` is not allowed in a type expression"
+# error: [invalid-type-form] "Variable of type `GenericAlias` is not allowed in a parameter annotation"
def _(strings: Strings) -> None:
reveal_type(strings) # revealed: Unknown
```
diff --git a/crates/ty_python_semantic/resources/mdtest/annotations/invalid.md b/crates/ty_python_semantic/resources/mdtest/annotations/invalid.md
index 79df38114ebbbc..5fc9348736bd0a 100644
--- a/crates/ty_python_semantic/resources/mdtest/annotations/invalid.md
+++ b/crates/ty_python_semantic/resources/mdtest/annotations/invalid.md
@@ -25,7 +25,7 @@ def _(
):
def foo(): ...
def invalid(
- a_: a, # error: [invalid-type-form] "Variable of type `type[int]` is not allowed in a type expression"
+ a_: a, # error: [invalid-type-form] "Variable of type `type[int]` is not allowed in a parameter annotation"
b_: b, # error: [invalid-type-form]
c_: c, # error: [invalid-type-form]
d_: d, # error: [invalid-type-form]
@@ -35,8 +35,8 @@ def _(
h_: h, # error: [invalid-type-form]
i_: typing, # error: [invalid-type-form]
j_: foo, # error: [invalid-type-form]
- k_: i, # error: [invalid-type-form] "Variable of type `int` is not allowed in a type expression"
- l_: j, # error: [invalid-type-form] "Variable of type `A` is not allowed in a type expression"
+ k_: i, # error: [invalid-type-form] "Variable of type `int` is not allowed in a parameter annotation"
+ l_: j, # error: [invalid-type-form] "Variable of type `A` is not allowed in a parameter annotation"
):
reveal_type(a_) # revealed: Unknown
reveal_type(b_) # revealed: Unknown
@@ -80,37 +80,37 @@ def bar() -> None:
def outer_sync(): # `yield` from is only valid syntax inside a synchronous function
def _(
- a: (yield from [1]), # error: [invalid-type-form] "`yield from` expressions are not allowed in type expressions"
+ a: (yield from [1]), # error: [invalid-type-form] "`yield from` expressions are not allowed in parameter annotations"
): ...
async def baz(): ...
async def outer_async(): # avoid unrelated syntax errors on `yield` and `await`
def _(
- a: 1, # error: [invalid-type-form] "Int literals are not allowed in this context in a type expression"
- b: 2.3, # error: [invalid-type-form] "Float literals are not allowed in type expressions"
- c: 4j, # error: [invalid-type-form] "Complex literals are not allowed in type expressions"
- d: True, # error: [invalid-type-form] "Boolean literals are not allowed in this context in a type expression"
+ a: 1, # error: [invalid-type-form] "Int literals are not allowed in this context in a parameter annotation"
+ b: 2.3, # error: [invalid-type-form] "Float literals are not allowed in parameter annotations"
+ c: 4j, # error: [invalid-type-form] "Complex literals are not allowed in parameter annotations"
+ d: True, # error: [invalid-type-form] "Boolean literals are not allowed in this context in a parameter annotation"
# error: [unsupported-operator]
- # error: [invalid-type-form] "Bytes literals are not allowed in this context in a type expression"
+ # error: [invalid-type-form] "Bytes literals are not allowed in this context in a parameter annotation"
e: int | b"foo",
- f: 1 and 2, # error: [invalid-type-form] "Boolean operations are not allowed in type expressions"
- g: 1 or 2, # error: [invalid-type-form] "Boolean operations are not allowed in type expressions"
- h: (foo := 1), # error: [invalid-type-form] "Named expressions are not allowed in type expressions"
- i: not 1, # error: [invalid-type-form] "Unary operations are not allowed in type expressions"
- j: lambda: 1, # error: [invalid-type-form] "`lambda` expressions are not allowed in type expressions"
- k: 1 if True else 2, # error: [invalid-type-form] "`if` expressions are not allowed in type expressions"
- l: await baz(), # error: [invalid-type-form] "`await` expressions are not allowed in type expressions"
- m: (yield 1), # error: [invalid-type-form] "`yield` expressions are not allowed in type expressions"
- n: 1 < 2, # error: [invalid-type-form] "Comparison expressions are not allowed in type expressions"
- o: bar(), # error: [invalid-type-form] "Function calls are not allowed in type expressions"
+ f: 1 and 2, # error: [invalid-type-form] "Boolean operations are not allowed in parameter annotations"
+ g: 1 or 2, # error: [invalid-type-form] "Boolean operations are not allowed in parameter annotations"
+ h: (foo := 1), # error: [invalid-type-form] "Named expressions are not allowed in parameter annotations"
+ i: not 1, # error: [invalid-type-form] "Unary operations are not allowed in parameter annotations"
+ j: lambda: 1, # error: [invalid-type-form] "`lambda` expressions are not allowed in parameter annotations"
+ k: 1 if True else 2, # error: [invalid-type-form] "`if` expressions are not allowed in parameter annotations"
+ l: await baz(), # error: [invalid-type-form] "`await` expressions are not allowed in parameter annotations"
+ m: (yield 1), # error: [invalid-type-form] "`yield` expressions are not allowed in parameter annotations"
+ n: 1 < 2, # error: [invalid-type-form] "Comparison expressions are not allowed in parameter annotations"
+ o: bar(), # error: [invalid-type-form] "Function calls are not allowed in parameter annotations"
# error: [unsupported-operator]
- # error: [invalid-type-form] "F-strings are not allowed in type expressions"
+ # error: [invalid-type-form] "F-strings are not allowed in parameter annotations"
p: int | f"foo",
- # error: [invalid-type-form] "Only simple names and dotted names can be subscripted in type expressions"
+ # error: [invalid-type-form] "Only simple names and dotted names can be subscripted in parameter annotations"
q: [1, 2, 3][1:2],
- # error: [invalid-type-form] "Only simple names and dotted names can be subscripted in type expressions"
+ # error: [invalid-type-form] "Only simple names and dotted names can be subscripted in parameter annotations"
r: list[T][int],
- # error: [invalid-type-form] "Only simple names and dotted names can be subscripted in type expressions"
+ # error: [invalid-type-form] "Only simple names and dotted names can be subscripted in parameter annotations"
s: list[list[T][int]],
):
reveal_type(a) # revealed: Unknown
@@ -270,25 +270,25 @@ def bar() -> None:
async def baz(): ...
async def outer_async(): # avoid unrelated syntax errors on `yield` and `await`
def _(
- a: "1", # error: [invalid-type-form] "Int literals are not allowed in this context in a type expression"
- b: "2.3", # error: [invalid-type-form] "Float literals are not allowed in type expressions"
- c: "4j", # error: [invalid-type-form] "Complex literals are not allowed in type expressions"
- d: "True", # error: [invalid-type-form] "Boolean literals are not allowed in this context in a type expression"
- e: "1 and 2", # error: [invalid-type-form] "Boolean operations are not allowed in type expressions"
- f: "1 or 2", # error: [invalid-type-form] "Boolean operations are not allowed in type expressions"
- g: "(foo := 1)", # error: [invalid-type-form] "Named expressions are not allowed in type expressions"
- h: "not 1", # error: [invalid-type-form] "Unary operations are not allowed in type expressions"
- i: "lambda: 1", # error: [invalid-type-form] "`lambda` expressions are not allowed in type expressions"
- j: "1 if True else 2", # error: [invalid-type-form] "`if` expressions are not allowed in type expressions"
- k: "await baz()", # error: [invalid-type-form] "`await` expressions are not allowed in type expressions"
- l: "(yield 1)", # error: [invalid-type-form] "`yield` expressions are not allowed in type expressions"
- m: "1 < 2", # error: [invalid-type-form] "Comparison expressions are not allowed in type expressions"
- n: "bar()", # error: [invalid-type-form] "Function calls are not allowed in type expressions"
- # error: [invalid-type-form] "Only simple names and dotted names can be subscripted in type expressions"
+ a: "1", # error: [invalid-type-form] "Int literals are not allowed in this context in a parameter annotation"
+ b: "2.3", # error: [invalid-type-form] "Float literals are not allowed in parameter annotations"
+ c: "4j", # error: [invalid-type-form] "Complex literals are not allowed in parameter annotations"
+ d: "True", # error: [invalid-type-form] "Boolean literals are not allowed in this context in a parameter annotation"
+ e: "1 and 2", # error: [invalid-type-form] "Boolean operations are not allowed in parameter annotations"
+ f: "1 or 2", # error: [invalid-type-form] "Boolean operations are not allowed in parameter annotations"
+ g: "(foo := 1)", # error: [invalid-type-form] "Named expressions are not allowed in parameter annotations"
+ h: "not 1", # error: [invalid-type-form] "Unary operations are not allowed in parameter annotations"
+ i: "lambda: 1", # error: [invalid-type-form] "`lambda` expressions are not allowed in parameter annotations"
+ j: "1 if True else 2", # error: [invalid-type-form] "`if` expressions are not allowed in parameter annotations"
+ k: "await baz()", # error: [invalid-type-form] "`await` expressions are not allowed in parameter annotations"
+ l: "(yield 1)", # error: [invalid-type-form] "`yield` expressions are not allowed in parameter annotations"
+ m: "1 < 2", # error: [invalid-type-form] "Comparison expressions are not allowed in parameter annotations"
+ n: "bar()", # error: [invalid-type-form] "Function calls are not allowed in parameter annotations"
+ # error: [invalid-type-form] "Only simple names and dotted names can be subscripted in parameter annotations"
o: "[1, 2, 3][1:2]",
- # error: [invalid-type-form] "Only simple names, dotted names and subscripts can be used in type expressions"
+ # error: [invalid-type-form] "Only simple names, dotted names and subscripts can be used in parameter annotations"
p: list[int].append,
- # error: [invalid-type-form] "Only simple names, dotted names and subscripts can be used in type expressions"
+ # error: [invalid-type-form] "Only simple names, dotted names and subscripts can be used in parameter annotations"
q: list[list[int].append],
):
reveal_type(a) # revealed: Unknown
@@ -319,17 +319,17 @@ python-version = "3.12"
```py
def _(
- a: {1: 2}, # error: [invalid-type-form] "Dict literals are not allowed in type expressions"
- b: {1, 2}, # error: [invalid-type-form] "Set literals are not allowed in type expressions"
- c: {k: v for k, v in [(1, 2)]}, # error: [invalid-type-form] "Dict comprehensions are not allowed in type expressions"
- d: [k for k in [1, 2]], # error: [invalid-type-form] "List comprehensions are not allowed in type expressions"
- e: {k for k in [1, 2]}, # error: [invalid-type-form] "Set comprehensions are not allowed in type expressions"
- f: (k for k in [1, 2]), # error: [invalid-type-form] "Generator expressions are not allowed in type expressions"
- # error: [invalid-type-form] "List literals are not allowed in this context in a type expression"
+ a: {1: 2}, # error: [invalid-type-form] "Dict literals are not allowed in parameter annotations"
+ b: {1, 2}, # error: [invalid-type-form] "Set literals are not allowed in parameter annotations"
+ c: {k: v for k, v in [(1, 2)]}, # error: [invalid-type-form] "Dict comprehensions are not allowed in parameter annotations"
+ d: [k for k in [1, 2]], # error: [invalid-type-form] "List comprehensions are not allowed in parameter annotations"
+ e: {k for k in [1, 2]}, # error: [invalid-type-form] "Set comprehensions are not allowed in parameter annotations"
+ f: (k for k in [1, 2]), # error: [invalid-type-form] "Generator expressions are not allowed in parameter annotations"
+ # error: [invalid-type-form] "List literals are not allowed in this context in a parameter annotation"
g: [int, str],
- # error: [invalid-type-form] "Tuple literals are not allowed in this context in a type expression: Did you mean `tuple[int, str]`?"
+ # error: [invalid-type-form] "Tuple literals are not allowed in this context in a parameter annotation: Did you mean `tuple[int, str]`?"
h: (int, str),
- i: (), # error: [invalid-type-form] "Tuple literals are not allowed in this context in a type expression: Did you mean `tuple[()]`?"
+ i: (), # error: [invalid-type-form] "Tuple literals are not allowed in this context in a parameter annotation: Did you mean `tuple[()]`?"
):
reveal_type(a) # revealed: Unknown
reveal_type(b) # revealed: Unknown
diff --git a/crates/ty_python_semantic/resources/mdtest/annotations/literal.md b/crates/ty_python_semantic/resources/mdtest/annotations/literal.md
index 119d8404783ed8..1e36725340df01 100644
--- a/crates/ty_python_semantic/resources/mdtest/annotations/literal.md
+++ b/crates/ty_python_semantic/resources/mdtest/annotations/literal.md
@@ -329,7 +329,7 @@ from other import Literal
#
# ?
#
-# error: [invalid-type-form] "Invalid subscript of object of type `_SpecialForm` in type expression"
+# error: [invalid-type-form] "Invalid subscript of object of type `_SpecialForm` in a type expression"
a1: Literal[26]
def f():
diff --git a/crates/ty_python_semantic/resources/mdtest/annotations/string.md b/crates/ty_python_semantic/resources/mdtest/annotations/string.md
index 1dc6a8ce18c78d..5ad349fb4b20ab 100644
--- a/crates/ty_python_semantic/resources/mdtest/annotations/string.md
+++ b/crates/ty_python_semantic/resources/mdtest/annotations/string.md
@@ -217,29 +217,29 @@ class Foo: ...
```py
def f1(
- # error: [raw-string-type-annotation] "Raw string literals are not allowed in type expressions"
+ # error: [raw-string-type-annotation] "Raw string literals are not allowed in parameter annotations"
a: r"int",
- # error: [raw-string-type-annotation] "Raw string literals are not allowed in type expressions"
+ # error: [raw-string-type-annotation] "Raw string literals are not allowed in parameter annotations"
b: list[r"int"],
- # error: [invalid-type-form] "F-strings are not allowed in type expressions"
+ # error: [invalid-type-form] "F-strings are not allowed in parameter annotations"
c: f"int",
- # error: [invalid-type-form] "F-strings are not allowed in type expressions"
+ # error: [invalid-type-form] "F-strings are not allowed in parameter annotations"
d: list[f"int"],
- # error: [invalid-type-form] "Bytes literals are not allowed in this context in a type expression"
+ # error: [invalid-type-form] "Bytes literals are not allowed in this context in a parameter annotation"
e: b"int",
f: "int",
# error: [implicit-concatenated-string-type-annotation] "Type expressions cannot span multiple string literals"
g: "in" "t",
# error: [implicit-concatenated-string-type-annotation] "Type expressions cannot span multiple string literals"
h: list["in" "t"],
- # error: [escape-character-in-forward-annotation] "Escape characters are not allowed in type expressions"
+ # error: [escape-character-in-forward-annotation] "Escape characters are not allowed in parameter annotations"
i: "\N{LATIN SMALL LETTER I}nt",
- # error: [escape-character-in-forward-annotation] "Escape characters are not allowed in type expressions"
+ # error: [escape-character-in-forward-annotation] "Escape characters are not allowed in parameter annotations"
j: "\x69nt",
k: """int""",
- # error: [invalid-type-form] "Bytes literals are not allowed in this context in a type expression"
+ # error: [invalid-type-form] "Bytes literals are not allowed in this context in a parameter annotation"
l: "b'int'",
- # error: [invalid-type-form] "Bytes literals are not allowed in this context in a type expression"
+ # error: [invalid-type-form] "Bytes literals are not allowed in this context in a parameter annotation"
m: list[b"int"],
): # fmt:skip
reveal_type(a) # revealed: Unknown
diff --git a/crates/ty_python_semantic/resources/mdtest/annotations/unsupported_special_forms.md b/crates/ty_python_semantic/resources/mdtest/annotations/unsupported_special_forms.md
index 13baa1a01f446c..0b8e23102e6bc1 100644
--- a/crates/ty_python_semantic/resources/mdtest/annotations/unsupported_special_forms.md
+++ b/crates/ty_python_semantic/resources/mdtest/annotations/unsupported_special_forms.md
@@ -62,14 +62,14 @@ def _(
c: TypeIs, # error: [invalid-type-form] "`typing.TypeIs` requires exactly one argument when used in a type expression"
d: Concatenate, # error: [invalid-type-form] "`typing.Concatenate` is not allowed in this context in a type expression"
e: ParamSpec,
- f: Generic, # error: [invalid-type-form] "`typing.Generic` is not allowed in type expressions"
+ f: Generic, # error: [invalid-type-form] "`typing.Generic` is not allowed in parameter annotations"
) -> None:
reveal_type(a) # revealed: Unknown
reveal_type(b) # revealed: Unknown
reveal_type(c) # revealed: Unknown
reveal_type(d) # revealed: Unknown
- # error: [invalid-type-form] "Variable of type `ParamSpec` is not allowed in a type expression"
+ # error: [invalid-type-form] "Variable of type `ParamSpec` is not allowed in a parameter annotation"
def foo(a_: e) -> None:
reveal_type(a_) # revealed: Unknown
```
diff --git a/crates/ty_python_semantic/resources/mdtest/annotations/unsupported_type_qualifiers.md b/crates/ty_python_semantic/resources/mdtest/annotations/unsupported_type_qualifiers.md
index 1c02eac9f0bf9d..a110d48561f912 100644
--- a/crates/ty_python_semantic/resources/mdtest/annotations/unsupported_type_qualifiers.md
+++ b/crates/ty_python_semantic/resources/mdtest/annotations/unsupported_type_qualifiers.md
@@ -23,11 +23,11 @@ One thing that is supported is error messages for using type qualifiers in type
from typing_extensions import Final, ClassVar, Required, NotRequired, ReadOnly
def _(
- # error: [invalid-type-form] "Type qualifier `typing.Final` is not allowed in type expressions (only in annotation expressions)"
+ # error: [invalid-type-form] "Type qualifier `typing.Final` is not allowed in parameter annotations"
a: Final | int,
- # error: [invalid-type-form] "Type qualifier `typing.ClassVar` is not allowed in type expressions (only in annotation expressions)"
+ # error: [invalid-type-form] "Type qualifier `typing.ClassVar` is not allowed in parameter annotations"
b: ClassVar | int,
- # error: [invalid-type-form] "Type qualifier `typing.ReadOnly` is not allowed in type expressions (only in annotation expressions, and only with exactly one argument)"
+ # error: [invalid-type-form] "Type qualifier `typing.ReadOnly` is not allowed in parameter annotations"
c: ReadOnly | int,
) -> None:
reveal_type(a) # revealed: Unknown | int
diff --git a/crates/ty_python_semantic/resources/mdtest/diagnostics/semantic_syntax_errors.md b/crates/ty_python_semantic/resources/mdtest/diagnostics/semantic_syntax_errors.md
index 7212217e0ad86f..1941be3e9bf331 100644
--- a/crates/ty_python_semantic/resources/mdtest/diagnostics/semantic_syntax_errors.md
+++ b/crates/ty_python_semantic/resources/mdtest/diagnostics/semantic_syntax_errors.md
@@ -97,7 +97,7 @@ python-version = "3.12"
```py
from __future__ import annotations
-# error: [invalid-type-form] "Named expressions are not allowed in type expressions"
+# error: [invalid-type-form] "Named expressions are not allowed in return type annotations"
# error: [invalid-syntax] "named expression cannot be used within a type annotation"
def f() -> (y := 3): ...
```
@@ -326,11 +326,11 @@ def _():
type X[T: (yield 1)] = int
def _():
- # error: [invalid-type-form] "`yield` expressions are not allowed in type expressions"
+ # error: [invalid-type-form] "`yield` expressions are not allowed in type alias values"
# error: [invalid-syntax] "yield expression cannot be used within a type alias"
type Y = (yield 1)
-# error: [invalid-type-form] "Named expressions are not allowed in type expressions"
+# error: [invalid-type-form] "Named expressions are not allowed in return type annotations"
# error: [invalid-syntax] "named expression cannot be used within a generic definition"
def f[T](x: int) -> (y := 3):
return x
diff --git a/crates/ty_python_semantic/resources/mdtest/generics/pep695/aliases.md b/crates/ty_python_semantic/resources/mdtest/generics/pep695/aliases.md
index f9588545249d90..396181bfc4db5a 100644
--- a/crates/ty_python_semantic/resources/mdtest/generics/pep695/aliases.md
+++ b/crates/ty_python_semantic/resources/mdtest/generics/pep695/aliases.md
@@ -105,11 +105,11 @@ def _(l: ListOfInts[int]):
type List[T] = list[T]
-# error: [invalid-type-form] "Only simple names and dotted names can be subscripted in type expressions"
+# error: [invalid-type-form] "Only simple names and dotted names can be subscripted in parameter annotations"
def _(l: List[int][int]):
reveal_type(l) # revealed: Unknown
-# error: [invalid-type-form] "Only simple names and dotted names can be subscripted in type expressions"
+# error: [invalid-type-form] "Only simple names and dotted names can be subscripted in type alias values"
type DoubleSpecialization[T] = list[T][T]
def _(d: DoubleSpecialization[int]):
diff --git a/crates/ty_python_semantic/resources/mdtest/generics/pep695/concatenate.md b/crates/ty_python_semantic/resources/mdtest/generics/pep695/concatenate.md
index 6bacc0864e5115..24264f09d61102 100644
--- a/crates/ty_python_semantic/resources/mdtest/generics/pep695/concatenate.md
+++ b/crates/ty_python_semantic/resources/mdtest/generics/pep695/concatenate.md
@@ -219,13 +219,13 @@ from typing import Concatenate
# error: [invalid-type-form] "`typing.Concatenate` is not allowed in this context in a type expression"
def invalid0(x: Concatenate): ...
-# error: [invalid-type-form] "`typing.Concatenate` is not allowed in this context in a type expression"
+# error: [invalid-type-form] "`typing.Concatenate` is not allowed in this context in a parameter annotation"
def invalid1(x: Concatenate[int]): ...
-# error: [invalid-type-form] "`typing.Concatenate` is not allowed in this context in a type expression"
+# error: [invalid-type-form] "`typing.Concatenate` is not allowed in this context in a parameter annotation"
def invalid2(x: Concatenate[int, ...]) -> None: ...
-# error: [invalid-type-form] "`typing.Concatenate` is not allowed in this context in a type expression"
+# error: [invalid-type-form] "`typing.Concatenate` is not allowed in this context in a return type annotation"
def invalid3() -> Concatenate[int, ...]: ...
```
diff --git a/crates/ty_python_semantic/resources/mdtest/implicit_type_aliases.md b/crates/ty_python_semantic/resources/mdtest/implicit_type_aliases.md
index 625a63e913c582..47596e34d9f9d2 100644
--- a/crates/ty_python_semantic/resources/mdtest/implicit_type_aliases.md
+++ b/crates/ty_python_semantic/resources/mdtest/implicit_type_aliases.md
@@ -783,7 +783,7 @@ def this_does_not_work() -> TypeOf[IntOrStr]:
raise NotImplementedError()
def _(
- # error: [invalid-type-form] "Only simple names and dotted names can be subscripted in type expressions"
+ # error: [invalid-type-form] "Only simple names and dotted names can be subscripted in parameter annotations"
specialized: this_does_not_work()[int],
):
reveal_type(specialized) # revealed: Unknown
@@ -1582,7 +1582,7 @@ errors:
```py
AliasForStr = "str"
-# error: [invalid-type-form] "Variable of type `Literal["str"]` is not allowed in a type expression"
+# error: [invalid-type-form] "Variable of type `Literal["str"]` is not allowed in a parameter annotation"
def _(s: AliasForStr):
reveal_type(s) # revealed: Unknown
diff --git a/crates/ty_python_semantic/resources/mdtest/pep695_type_aliases.md b/crates/ty_python_semantic/resources/mdtest/pep695_type_aliases.md
index cdcdc7560a6a04..35967424387674 100644
--- a/crates/ty_python_semantic/resources/mdtest/pep695_type_aliases.md
+++ b/crates/ty_python_semantic/resources/mdtest/pep695_type_aliases.md
@@ -50,23 +50,23 @@ appear at the top level of a PEP 695 alias definition:
from typing_extensions import ClassVar, Final, Required, NotRequired, ReadOnly
from dataclasses import InitVar
-# error: [invalid-type-form] "Type qualifier `typing.ClassVar` is not allowed in type expressions (only in annotation expressions)"
+# error: [invalid-type-form] "Type qualifier `typing.ClassVar` is not allowed in type alias values"
type Bad1 = ClassVar[str]
-# error: [invalid-type-form] "Type qualifier `typing.ClassVar` is not allowed in type expressions (only in annotation expressions)"
+# error: [invalid-type-form] "Type qualifier `typing.ClassVar` is not allowed in type alias values"
type Bad2 = ClassVar
-# error: [invalid-type-form] "Type qualifier `typing.Final` is not allowed in type expressions (only in annotation expressions)"
+# error: [invalid-type-form] "Type qualifier `typing.Final` is not allowed in type alias values"
type Bad3 = Final[int]
-# error: [invalid-type-form] "Type qualifier `typing.Final` is not allowed in type expressions (only in annotation expressions)"
+# error: [invalid-type-form] "Type qualifier `typing.Final` is not allowed in type alias values"
type Bad4 = Final
-# error: [invalid-type-form] "Type qualifier `typing.Required` is not allowed in type expressions (only in annotation expressions)"
+# error: [invalid-type-form] "Type qualifier `typing.Required` is not allowed in type alias values"
type Bad5 = Required[int]
-# error: [invalid-type-form] "Type qualifier `typing.NotRequired` is not allowed in type expressions (only in annotation expressions)"
+# error: [invalid-type-form] "Type qualifier `typing.NotRequired` is not allowed in type alias values"
type Bad6 = NotRequired[int]
-# error: [invalid-type-form] "Type qualifier `typing.ReadOnly` is not allowed in type expressions (only in annotation expressions)"
+# error: [invalid-type-form] "Type qualifier `typing.ReadOnly` is not allowed in type alias values"
type Bad7 = ReadOnly[int]
-# error: [invalid-type-form] "Type qualifier `dataclasses.InitVar` is not allowed in type expressions (only in annotation expressions)"
+# error: [invalid-type-form] "Type qualifier `dataclasses.InitVar` is not allowed in type alias values"
type Bad8 = InitVar[int]
-# error: [invalid-type-form] "Type qualifier `dataclasses.InitVar` is not allowed in type expressions (only in annotation expressions, and only with exactly one argument)"
+# error: [invalid-type-form] "Type qualifier `dataclasses.InitVar` is not allowed in type alias values"
type Bad9 = InitVar
```
diff --git a/crates/ty_python_semantic/resources/mdtest/protocols.md b/crates/ty_python_semantic/resources/mdtest/protocols.md
index d71a7dd3df855f..8ff1d495803e7f 100644
--- a/crates/ty_python_semantic/resources/mdtest/protocols.md
+++ b/crates/ty_python_semantic/resources/mdtest/protocols.md
@@ -260,8 +260,8 @@ And it is also an error to use `Protocol` in type expressions:
# fmt: off
def f(
- x: Protocol, # error: [invalid-type-form] "`typing.Protocol` is not allowed in type expressions"
- y: type[Protocol], # error: [invalid-type-form] "`typing.Protocol` is not allowed in type expressions"
+ x: Protocol, # error: [invalid-type-form] "`typing.Protocol` is not allowed in parameter annotations"
+ y: type[Protocol], # error: [invalid-type-form] "`typing.Protocol` is not allowed in parameter annotations"
):
reveal_type(x) # revealed: Unknown
reveal_type(y) # revealed: type[Unknown]
diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/invalid.md_-_Tests_for_invalid_ty\342\200\246_-_Diagnostics_for_comm\342\200\246_-_AST_nodes_that_are_o\342\200\246_(58a3839a9bc7026d).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid.md_-_Tests_for_invalid_ty\342\200\246_-_Diagnostics_for_comm\342\200\246_-_AST_nodes_that_are_o\342\200\246_(58a3839a9bc7026d).snap"
index 29dacab84a8acd..4652200f5793f4 100644
--- "a/crates/ty_python_semantic/resources/mdtest/snapshots/invalid.md_-_Tests_for_invalid_ty\342\200\246_-_Diagnostics_for_comm\342\200\246_-_AST_nodes_that_are_o\342\200\246_(58a3839a9bc7026d).snap"
+++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid.md_-_Tests_for_invalid_ty\342\200\246_-_Diagnostics_for_comm\342\200\246_-_AST_nodes_that_are_o\342\200\246_(58a3839a9bc7026d).snap"
@@ -28,7 +28,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/annotations/invalid.md
# Diagnostics
```
-error[invalid-type-form]: Int literals are not allowed in this context in a type expression
+error[invalid-type-form]: Int literals are not allowed in this context in a parameter annotation
--> src/mdtest_snippet.py:3:8
|
1 | def bad(
@@ -45,7 +45,7 @@ info: rule `invalid-type-form` is enabled by default
```
```
-error[invalid-type-form]: Bytes literals are not allowed in this context in a type expression
+error[invalid-type-form]: Bytes literals are not allowed in this context in a parameter annotation
--> src/mdtest_snippet.py:5:8
|
3 | a: 42,
@@ -62,7 +62,7 @@ info: rule `invalid-type-form` is enabled by default
```
```
-error[invalid-type-form]: Boolean literals are not allowed in this context in a type expression
+error[invalid-type-form]: Boolean literals are not allowed in this context in a parameter annotation
--> src/mdtest_snippet.py:7:8
|
5 | b: b"42",
diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/invalid.md_-_Tests_for_invalid_ty\342\200\246_-_Diagnostics_for_comm\342\200\246_-_Dict-literal_or_set-\342\200\246_(15737b0beb194b0e).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid.md_-_Tests_for_invalid_ty\342\200\246_-_Diagnostics_for_comm\342\200\246_-_Dict-literal_or_set-\342\200\246_(15737b0beb194b0e).snap"
index 87da04f6651d43..273be276f8bb19 100644
--- "a/crates/ty_python_semantic/resources/mdtest/snapshots/invalid.md_-_Tests_for_invalid_ty\342\200\246_-_Diagnostics_for_comm\342\200\246_-_Dict-literal_or_set-\342\200\246_(15737b0beb194b0e).snap"
+++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid.md_-_Tests_for_invalid_ty\342\200\246_-_Diagnostics_for_comm\342\200\246_-_Dict-literal_or_set-\342\200\246_(15737b0beb194b0e).snap"
@@ -22,7 +22,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/annotations/invalid.md
# Diagnostics
```
-error[invalid-type-form]: Dict literals are not allowed in type expressions
+error[invalid-type-form]: Dict literals are not allowed in parameter annotations
--> src/mdtest_snippet.py:2:8
|
1 | def _(
@@ -38,7 +38,7 @@ info: rule `invalid-type-form` is enabled by default
```
```
-error[invalid-type-form]: Set literals are not allowed in type expressions
+error[invalid-type-form]: Set literals are not allowed in parameter annotations
--> src/mdtest_snippet.py:3:8
|
1 | def _(
diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/invalid.md_-_Tests_for_invalid_ty\342\200\246_-_Diagnostics_for_comm\342\200\246_-_List-literal_used_wh\342\200\246_(ba5cb09eaa3715d8).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid.md_-_Tests_for_invalid_ty\342\200\246_-_Diagnostics_for_comm\342\200\246_-_List-literal_used_wh\342\200\246_(ba5cb09eaa3715d8).snap"
index 6dc642c163795a..ab0e1caa4e5a22 100644
--- "a/crates/ty_python_semantic/resources/mdtest/snapshots/invalid.md_-_Tests_for_invalid_ty\342\200\246_-_Diagnostics_for_comm\342\200\246_-_List-literal_used_wh\342\200\246_(ba5cb09eaa3715d8).snap"
+++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid.md_-_Tests_for_invalid_ty\342\200\246_-_Diagnostics_for_comm\342\200\246_-_List-literal_used_wh\342\200\246_(ba5cb09eaa3715d8).snap"
@@ -28,7 +28,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/annotations/invalid.md
# Diagnostics
```
-error[invalid-type-form]: List literals are not allowed in this context in a type expression
+error[invalid-type-form]: List literals are not allowed in this context in a parameter annotation
--> src/mdtest_snippet.py:2:8
|
1 | def _(
@@ -44,7 +44,7 @@ info: rule `invalid-type-form` is enabled by default
```
```
-error[invalid-type-form]: List literals are not allowed in this context in a type expression
+error[invalid-type-form]: List literals are not allowed in this context in a return type annotation
--> src/mdtest_snippet.py:3:6
|
1 | def _(
@@ -60,7 +60,7 @@ info: rule `invalid-type-form` is enabled by default
```
```
-error[invalid-type-form]: List literals are not allowed in this context in a type expression
+error[invalid-type-form]: List literals are not allowed in this context in a parameter annotation
--> src/mdtest_snippet.py:8:8
|
6 | # No special hints for these: it's unclear what the user meant:
@@ -77,7 +77,7 @@ info: rule `invalid-type-form` is enabled by default
```
```
-error[invalid-type-form]: List literals are not allowed in this context in a type expression
+error[invalid-type-form]: List literals are not allowed in this context in a return type annotation
--> src/mdtest_snippet.py:9:6
|
7 | def _(
diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/invalid.md_-_Tests_for_invalid_ty\342\200\246_-_Diagnostics_for_comm\342\200\246_-_Module-literal_used_\342\200\246_(652fec4fd4a6c63a).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid.md_-_Tests_for_invalid_ty\342\200\246_-_Diagnostics_for_comm\342\200\246_-_Module-literal_used_\342\200\246_(652fec4fd4a6c63a).snap"
index b28e8e246a8bf4..8a11768ba08471 100644
--- "a/crates/ty_python_semantic/resources/mdtest/snapshots/invalid.md_-_Tests_for_invalid_ty\342\200\246_-_Diagnostics_for_comm\342\200\246_-_Module-literal_used_\342\200\246_(652fec4fd4a6c63a).snap"
+++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid.md_-_Tests_for_invalid_ty\342\200\246_-_Diagnostics_for_comm\342\200\246_-_Module-literal_used_\342\200\246_(652fec4fd4a6c63a).snap"
@@ -35,7 +35,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/annotations/invalid.md
# Diagnostics
```
-error[invalid-type-form]: Module `datetime` is not valid in a type expression
+error[invalid-type-form]: Module `datetime` is not valid in a parameter annotation
--> src/foo.py:3:10
|
1 | import datetime
@@ -53,7 +53,7 @@ note: This is an unsafe fix and may change runtime behavior
```
```
-error[invalid-type-form]: Module `PIL.Image` is not valid in a type expression
+error[invalid-type-form]: Module `PIL.Image` is not valid in a parameter annotation
--> src/bar.py:3:10
|
1 | from PIL import Image
diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/invalid.md_-_Tests_for_invalid_ty\342\200\246_-_Diagnostics_for_comm\342\200\246_-_Special-cased_diagno\342\200\246_(a4b698196d337a3f).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid.md_-_Tests_for_invalid_ty\342\200\246_-_Diagnostics_for_comm\342\200\246_-_Special-cased_diagno\342\200\246_(a4b698196d337a3f).snap"
index 1c56915789959a..50b1305e9be4ff 100644
--- "a/crates/ty_python_semantic/resources/mdtest/snapshots/invalid.md_-_Tests_for_invalid_ty\342\200\246_-_Diagnostics_for_comm\342\200\246_-_Special-cased_diagno\342\200\246_(a4b698196d337a3f).snap"
+++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid.md_-_Tests_for_invalid_ty\342\200\246_-_Diagnostics_for_comm\342\200\246_-_Special-cased_diagno\342\200\246_(a4b698196d337a3f).snap"
@@ -22,7 +22,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/annotations/invalid.md
# Diagnostics
```
-error[invalid-type-form]: Function `callable` is not valid in a type expression
+error[invalid-type-form]: Function `callable` is not valid in a parameter annotation
--> src/mdtest_snippet.py:3:19
|
1 | # error: [invalid-type-form]
@@ -36,7 +36,7 @@ info: rule `invalid-type-form` is enabled by default
```
```
-error[invalid-type-form]: Function `callable` is not valid in a type expression
+error[invalid-type-form]: Function `callable` is not valid in a return type annotation
--> src/mdtest_snippet.py:3:32
|
1 | # error: [invalid-type-form]
diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/invalid.md_-_Tests_for_invalid_ty\342\200\246_-_Diagnostics_for_comm\342\200\246_-_Tuple-literal_used_w\342\200\246_(f61204fc81905069).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid.md_-_Tests_for_invalid_ty\342\200\246_-_Diagnostics_for_comm\342\200\246_-_Tuple-literal_used_w\342\200\246_(f61204fc81905069).snap"
index 9da08843aeb5f6..df4d0cf9ad8d81 100644
--- "a/crates/ty_python_semantic/resources/mdtest/snapshots/invalid.md_-_Tests_for_invalid_ty\342\200\246_-_Diagnostics_for_comm\342\200\246_-_Tuple-literal_used_w\342\200\246_(f61204fc81905069).snap"
+++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/invalid.md_-_Tests_for_invalid_ty\342\200\246_-_Diagnostics_for_comm\342\200\246_-_Tuple-literal_used_w\342\200\246_(f61204fc81905069).snap"
@@ -30,7 +30,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/annotations/invalid.md
# Diagnostics
```
-error[invalid-type-form]: Tuple literals are not allowed in this context in a type expression
+error[invalid-type-form]: Tuple literals are not allowed in this context in a parameter annotation
--> src/mdtest_snippet.py:2:8
|
1 | def _(
@@ -46,7 +46,7 @@ info: rule `invalid-type-form` is enabled by default
```
```
-error[invalid-type-form]: Tuple literals are not allowed in this context in a type expression
+error[invalid-type-form]: Tuple literals are not allowed in this context in a return type annotation
--> src/mdtest_snippet.py:3:6
|
1 | def _(
@@ -63,7 +63,7 @@ info: rule `invalid-type-form` is enabled by default
```
```
-error[invalid-type-form]: Tuple literals are not allowed in this context in a type expression
+error[invalid-type-form]: Tuple literals are not allowed in this context in a parameter annotation
--> src/mdtest_snippet.py:6:8
|
4 | return x
@@ -80,7 +80,7 @@ info: rule `invalid-type-form` is enabled by default
```
```
-error[invalid-type-form]: Tuple literals are not allowed in this context in a type expression
+error[invalid-type-form]: Tuple literals are not allowed in this context in a return type annotation
--> src/mdtest_snippet.py:7:6
|
5 | def _(
@@ -97,7 +97,7 @@ info: rule `invalid-type-form` is enabled by default
```
```
-error[invalid-type-form]: Tuple literals are not allowed in this context in a type expression
+error[invalid-type-form]: Tuple literals are not allowed in this context in a parameter annotation
--> src/mdtest_snippet.py:10:8
|
8 | return x
@@ -114,7 +114,7 @@ info: rule `invalid-type-form` is enabled by default
```
```
-error[invalid-type-form]: Tuple literals are not allowed in this context in a type expression
+error[invalid-type-form]: Tuple literals are not allowed in this context in a return type annotation
--> src/mdtest_snippet.py:11:6
|
9 | def _(
diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/string.md_-_String_annotations_-_Partially_deferred_a\342\200\246_-_Python_less_than_3.1\342\200\246_(5e6477d05ddea33f).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/string.md_-_String_annotations_-_Partially_deferred_a\342\200\246_-_Python_less_than_3.1\342\200\246_(5e6477d05ddea33f).snap"
index ca2eb92bea212e..25131842ce2160 100644
--- "a/crates/ty_python_semantic/resources/mdtest/snapshots/string.md_-_String_annotations_-_Partially_deferred_a\342\200\246_-_Python_less_than_3.1\342\200\246_(5e6477d05ddea33f).snap"
+++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/string.md_-_String_annotations_-_Partially_deferred_a\342\200\246_-_Python_less_than_3.1\342\200\246_(5e6477d05ddea33f).snap"
@@ -102,7 +102,7 @@ error[unsupported-operator]: Unsupported `|` operation
20 | # error: [unsupported-operator]
21 | b: int | "memoryview" | bytes,
|
-info: All type expressions are evaluated at runtime by default on Python <3.14
+info: All parameter annotations are evaluated at runtime by default on Python <3.14
info: Python 3.13 was assumed when inferring types because it was specified on the command line
help: Put quotes around the whole union rather than just certain elements
info: rule `unsupported-operator` is enabled by default
@@ -123,7 +123,7 @@ error[unsupported-operator]: Unsupported `|` operation
22 | # error: [unsupported-operator]
23 | c: "TD" | None,
|
-info: All type expressions are evaluated at runtime by default on Python <3.14
+info: All parameter annotations are evaluated at runtime by default on Python <3.14
info: Python 3.13 was assumed when inferring types because it was specified on the command line
help: Put quotes around the whole union rather than just certain elements
info: rule `unsupported-operator` is enabled by default
@@ -144,7 +144,7 @@ error[unsupported-operator]: Unsupported `|` operation
24 | # error: [unsupported-operator]
25 | d: "P" | None,
|
-info: All type expressions are evaluated at runtime by default on Python <3.14
+info: All parameter annotations are evaluated at runtime by default on Python <3.14
info: Python 3.13 was assumed when inferring types because it was specified on the command line
help: Put quotes around the whole union rather than just certain elements
info: rule `unsupported-operator` is enabled by default
@@ -165,7 +165,7 @@ error[unsupported-operator]: Unsupported `|` operation
26 | # fine: `TypeVar.__or__` accepts strings at runtime
27 | e: T | "Foo",
|
-info: All type expressions are evaluated at runtime by default on Python <3.14
+info: All parameter annotations are evaluated at runtime by default on Python <3.14
info: Python 3.13 was assumed when inferring types because it was specified on the command line
help: Put quotes around the whole union rather than just certain elements
info: rule `unsupported-operator` is enabled by default
@@ -183,7 +183,7 @@ error[unsupported-operator]: Unsupported `|` operation
34 | # error: [unresolved-reference] "SomethingUndefined"
35 | # error: [unresolved-reference] "SomethingAlsoUndefined"
|
-info: All type expressions are evaluated at runtime by default on Python <3.14
+info: All parameter annotations are evaluated at runtime by default on Python <3.14
info: Python 3.13 was assumed when inferring types because it was specified on the command line
info: rule `unsupported-operator` is enabled by default
@@ -233,7 +233,7 @@ error[unsupported-operator]: Unsupported `|` operation
40 | ):
41 | reveal_type(a) # revealed: int | Foo
|
-info: All type expressions are evaluated at runtime by default on Python <3.14
+info: All parameter annotations are evaluated at runtime by default on Python <3.14
info: Python 3.13 was assumed when inferring types because it was specified on the command line
help: Put quotes around the whole union rather than just certain elements
info: rule `unsupported-operator` is enabled by default
@@ -254,7 +254,7 @@ error[unsupported-operator]: Unsupported `|` operation
40 | ):
41 | reveal_type(a) # revealed: int | Foo
|
-info: All type expressions are evaluated at runtime by default on Python <3.14
+info: All parameter annotations are evaluated at runtime by default on Python <3.14
info: Python 3.13 was assumed when inferring types because it was specified on the command line
help: Put quotes around the whole union rather than just certain elements
info: rule `unsupported-operator` is enabled by default
@@ -316,7 +316,7 @@ error[unsupported-operator]: Unsupported `|` operation
67 |
68 | class Bar:
|
-info: All type expressions are evaluated at runtime by default on Python <3.14
+info: All parameter annotations are evaluated at runtime by default on Python <3.14
info: Python 3.13 was assumed when inferring types because it was specified on the command line
help: Put quotes around the whole union rather than just certain elements
info: rule `unsupported-operator` is enabled by default
diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/unreachable.md_-_Unreachable_code_-_`Never`-inferred_var\342\200\246_(6ce5aa6d2a0ce029).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/unreachable.md_-_Unreachable_code_-_`Never`-inferred_var\342\200\246_(6ce5aa6d2a0ce029).snap"
index 4963a7411e561f..e6085925a0b57c 100644
--- "a/crates/ty_python_semantic/resources/mdtest/snapshots/unreachable.md_-_Unreachable_code_-_`Never`-inferred_var\342\200\246_(6ce5aa6d2a0ce029).snap"
+++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/unreachable.md_-_Unreachable_code_-_`Never`-inferred_var\342\200\246_(6ce5aa6d2a0ce029).snap"
@@ -32,7 +32,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/unreachable.md
# Diagnostics
```
-error[invalid-type-form]: Variable of type `Never` is not allowed in a type expression
+error[invalid-type-form]: Variable of type `Never` is not allowed in a parameter annotation
--> src/main.py:3:10
|
1 | import module
diff --git a/crates/ty_python_semantic/resources/mdtest/type_qualifiers/classvar.md b/crates/ty_python_semantic/resources/mdtest/type_qualifiers/classvar.md
index 01138809deb436..9decd09b446a78 100644
--- a/crates/ty_python_semantic/resources/mdtest/type_qualifiers/classvar.md
+++ b/crates/ty_python_semantic/resources/mdtest/type_qualifiers/classvar.md
@@ -347,21 +347,19 @@ class C:
# error: [invalid-type-form] "`ClassVar` annotations are only allowed in class-body scopes"
y: ClassVar[int] = 1
-# error: [invalid-type-form] "`ClassVar` is not allowed in function parameter annotations"
+# error: [invalid-type-form] "Type qualifier `typing.ClassVar` is not allowed in parameter annotations"
def f(x: ClassVar[int]) -> None:
pass
-# error: [invalid-type-form] "`ClassVar` is not allowed in function parameter annotations"
-# error: [invalid-type-form] "`ClassVar` cannot contain type variables"
+# error: [invalid-type-form] "Type qualifier `typing.ClassVar` is not allowed in parameter annotations"
def f[T](x: ClassVar[T]) -> T:
return x
-# error: [invalid-type-form] "`ClassVar` is not allowed in function return type annotations"
+# error: [invalid-type-form] "Type qualifier `typing.ClassVar` is not allowed in return type annotations"
def f() -> ClassVar[int]:
return 1
-# error: [invalid-type-form] "`ClassVar` is not allowed in function return type annotations"
-# error: [invalid-type-form] "`ClassVar` cannot contain type variables"
+# error: [invalid-type-form] "Type qualifier `typing.ClassVar` is not allowed in return type annotations"
def f[T](x: T) -> ClassVar[T]:
return x
diff --git a/crates/ty_python_semantic/resources/mdtest/type_qualifiers/final.md b/crates/ty_python_semantic/resources/mdtest/type_qualifiers/final.md
index 8ad6a860d7338f..8969e0f15e5a40 100644
--- a/crates/ty_python_semantic/resources/mdtest/type_qualifiers/final.md
+++ b/crates/ty_python_semantic/resources/mdtest/type_qualifiers/final.md
@@ -682,18 +682,18 @@ class C:
self.LEGAL_H: Final[int]
self.LEGAL_H = 1
-# error: [invalid-type-form] "`Final` is not allowed in function parameter annotations"
+# error: [invalid-type-form] "Type qualifier `typing.Final` is not allowed in parameter annotations"
def f(ILLEGAL: Final[int]) -> None:
pass
-# error: [invalid-type-form] "`Final` is not allowed in function parameter annotations"
+# error: [invalid-type-form] "Type qualifier `typing.Final` is not allowed in parameter annotations"
def f[T](ILLEGAL: Final[T]) -> T:
return ILLEGAL
-# error: [invalid-type-form] "`Final` is not allowed in function return type annotations"
+# error: [invalid-type-form] "Type qualifier `typing.Final` is not allowed in return type annotations"
def f() -> Final[None]: ...
-# error: [invalid-type-form] "`Final` is not allowed in function return type annotations"
+# error: [invalid-type-form] "Type qualifier `typing.Final` is not allowed in return type annotations"
def f[T](x: T) -> Final[T]:
return x
diff --git a/crates/ty_python_semantic/resources/mdtest/type_qualifiers/initvar.md b/crates/ty_python_semantic/resources/mdtest/type_qualifiers/initvar.md
index fcca32fb3320db..db32d2289ee468 100644
--- a/crates/ty_python_semantic/resources/mdtest/type_qualifiers/initvar.md
+++ b/crates/ty_python_semantic/resources/mdtest/type_qualifiers/initvar.md
@@ -149,10 +149,12 @@ from dataclasses import InitVar, dataclass
# error: [invalid-type-form] "`InitVar` annotations are only allowed in class-body scopes"
x: InitVar[int] = 1
-def f(x: InitVar[int]) -> None: # error: [invalid-type-form] "`InitVar` is not allowed in function parameter annotations"
+# error: [invalid-type-form] "Type qualifier `dataclasses.InitVar` is not allowed in parameter annotations"
+def f(x: InitVar[int]) -> None:
pass
-def g() -> InitVar[int]: # error: [invalid-type-form] "`InitVar` is not allowed in function return type annotations"
+# error: [invalid-type-form] "Type qualifier `dataclasses.InitVar` is not allowed in return type annotations"
+def g() -> InitVar[int]:
return 1
class C:
diff --git a/crates/ty_python_semantic/resources/mdtest/typed_dict.md b/crates/ty_python_semantic/resources/mdtest/typed_dict.md
index 91b3d8b0c51a15..77b0a4f4a1ea58 100644
--- a/crates/ty_python_semantic/resources/mdtest/typed_dict.md
+++ b/crates/ty_python_semantic/resources/mdtest/typed_dict.md
@@ -2778,11 +2778,11 @@ x: TypedDict = {"name": "Alice"}
from typing_extensions import Required, NotRequired, ReadOnly
def bad(
- # error: [invalid-type-form] "`Required` is not allowed in function parameter annotations"
+ # error: [invalid-type-form] "Type qualifier `typing.Required` is not allowed in parameter annotations"
a: Required[int],
- # error: [invalid-type-form] "`NotRequired` is not allowed in function parameter annotations"
+ # error: [invalid-type-form] "Type qualifier `typing.NotRequired` is not allowed in parameter annotations"
b: NotRequired[int],
- # error: [invalid-type-form] "`ReadOnly` is not allowed in function parameter annotations"
+ # error: [invalid-type-form] "Type qualifier `typing.ReadOnly` is not allowed in parameter annotations"
c: ReadOnly[int],
): ...
```
diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs
index ca3c071ffd187e..a9f0771dcb7154 100644
--- a/crates/ty_python_semantic/src/types.rs
+++ b/crates/ty_python_semantic/src/types.rs
@@ -6834,7 +6834,12 @@ pub struct InvalidTypeExpressionError<'db> {
}
impl<'db> InvalidTypeExpressionError<'db> {
- fn into_fallback_type(self, context: &InferContext, node: &impl Ranged) -> Type<'db> {
+ fn into_fallback_type(
+ self,
+ context: &InferContext,
+ node: &impl Ranged,
+ flags: InferenceFlags,
+ ) -> Type<'db> {
let InvalidTypeExpressionError {
fallback_type,
invalid_expressions,
@@ -6843,7 +6848,7 @@ impl<'db> InvalidTypeExpressionError<'db> {
let Some(builder) = context.report_lint(&INVALID_TYPE_FORM, node) else {
continue;
};
- let diagnostic = builder.into_diagnostic(error.reason(context.db()));
+ let diagnostic = builder.into_diagnostic(error.reason(context.db(), flags));
error.add_subdiagnostics(context.db(), diagnostic, node);
}
fallback_type
@@ -6883,12 +6888,8 @@ enum InvalidTypeExpression<'db> {
/// Same for `typing.Concatenate`, anywhere except for as the first parameter of a `Callable`
/// type expression
Concatenate,
- /// Type qualifiers are always invalid in *type expressions*,
- /// but these ones are okay with 0 arguments in *annotation expressions*
+ /// Type qualifiers are always invalid in type expressions
TypeQualifier(TypeQualifier),
- /// Type qualifiers that are invalid in type expressions,
- /// and which would require exactly one argument even if they appeared in an annotation expression
- TypeQualifierRequiresOneArgument(TypeQualifier),
/// `typing.Self` cannot be used in `@staticmethod` definitions.
TypingSelfInStaticMethod,
/// `typing.Self` cannot be used in metaclass definitions.
@@ -6899,14 +6900,17 @@ enum InvalidTypeExpression<'db> {
}
impl<'db> InvalidTypeExpression<'db> {
- const fn reason(self, db: &'db dyn Db) -> impl std::fmt::Display + 'db {
+ const fn reason(self, db: &'db dyn Db, flags: InferenceFlags) -> impl std::fmt::Display + 'db {
struct Display<'db> {
error: InvalidTypeExpression<'db>,
db: &'db dyn Db,
+ flags: InferenceFlags,
}
impl std::fmt::Display for Display<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let location = self.flags.type_expression_context();
+
match self.error {
InvalidTypeExpression::RequiresOneArgument(special_form) => write!(
f,
@@ -6921,47 +6925,68 @@ impl<'db> InvalidTypeExpression<'db> {
"`{special_form}` requires at least two arguments when used in a type expression",
),
InvalidTypeExpression::Protocol => {
- f.write_str("`typing.Protocol` is not allowed in type expressions")
+ write!(f, "`typing.Protocol` is not allowed in {location}s")
}
InvalidTypeExpression::Generic => {
- f.write_str("`typing.Generic` is not allowed in type expressions")
+ write!(f, "`typing.Generic` is not allowed in {location}s")
}
InvalidTypeExpression::Deprecated => {
- f.write_str("`warnings.deprecated` is not allowed in type expressions")
+ write!(f, "`warnings.deprecated` is not allowed in {location}s")
}
InvalidTypeExpression::Field => {
- f.write_str("`dataclasses.Field` is not allowed in type expressions")
+ write!(f, "`dataclasses.Field` is not allowed in {location}s")
}
- InvalidTypeExpression::ConstraintSet => f.write_str(
- "`ty_extensions.ConstraintSet` is not allowed in type expressions",
- ),
- InvalidTypeExpression::GenericContext => f.write_str(
- "`ty_extensions.GenericContext` is not allowed in type expressions",
+ InvalidTypeExpression::ConstraintSet => write!(
+ f,
+ "`ty_extensions.ConstraintSet` is not allowed in {location}s",
),
- InvalidTypeExpression::Specialization => f.write_str(
- "`ty_extensions.GenericContext` is not allowed in type expressions",
+ InvalidTypeExpression::GenericContext => {
+ write!(
+ f,
+ "`ty_extensions.GenericContext` is not allowed in {location}s"
+ )
+ }
+ InvalidTypeExpression::Specialization => write!(
+ f,
+ "`ty_extensions.GenericContext` is not allowed in {location}s",
),
InvalidTypeExpression::NamedTupleSpec => {
- f.write_str("`NamedTupleSpec` is not allowed in type expressions")
+ write!(f, "`NamedTupleSpec` is not allowed in {location}s")
}
- InvalidTypeExpression::TypedDict => f.write_str(
+ InvalidTypeExpression::TypedDict => write!(
+ f,
"The special form `typing.TypedDict` \
- is not allowed in type expressions",
+ is not allowed in {location}s",
),
InvalidTypeExpression::TypeAlias => f.write_str(
"`typing.TypeAlias` is only allowed \
as the sole annotation on an annotated assignment",
),
- InvalidTypeExpression::TypeQualifier(qualifier) => write!(
- f,
- "Type qualifier `{qualifier}` is not allowed in type expressions \
- (only in annotation expressions)",
- ),
- InvalidTypeExpression::TypeQualifierRequiresOneArgument(qualifier) => write!(
- f,
- "Type qualifier `{qualifier}` is not allowed in type expressions \
- (only in annotation expressions, and only with exactly one argument)",
- ),
+ InvalidTypeExpression::TypeQualifier(qualifier) => {
+ if self.flags.intersects(
+ InferenceFlags::IN_PARAMETER_ANNOTATION
+ | InferenceFlags::IN_RETURN_TYPE
+ | InferenceFlags::IN_TYPE_ALIAS,
+ ) {
+ write!(
+ f,
+ "Type qualifier `{qualifier}` is not allowed in {location}s",
+ )
+ } else if qualifier.requires_one_argument() {
+ write!(
+ f,
+ "Type qualifier `{qualifier}` is not allowed in type expressions \
+ (only in annotation expressions, and only with \
+ exactly one argument)",
+ )
+ } else {
+ write!(
+ f,
+ "Type qualifier `{qualifier}` is not allowed in type expressions \
+ (only in annotation expressions)"
+ )
+ }
+ }
InvalidTypeExpression::TypingSelfInStaticMethod => {
f.write_str("`Self` cannot be used in a static method")
}
@@ -6971,18 +6996,18 @@ impl<'db> InvalidTypeExpression<'db> {
InvalidTypeExpression::InvalidType(Type::FunctionLiteral(function), _) => {
write!(
f,
- "Function `{function}` is not valid in a type expression",
+ "Function `{function}` is not valid in a {location}",
function = function.name(self.db)
)
}
InvalidTypeExpression::InvalidType(Type::ModuleLiteral(module), _) => write!(
f,
- "Module `{module}` is not valid in a type expression",
+ "Module `{module}` is not valid in a {location}",
module = module.module(self.db).name(self.db)
),
InvalidTypeExpression::InvalidType(ty, _) => write!(
f,
- "Variable of type `{ty}` is not allowed in a type expression",
+ "Variable of type `{ty}` is not allowed in a {location}",
ty = ty.display(self.db)
),
InvalidTypeExpression::InvalidBareParamSpec(paramspec) => write!(
@@ -6997,7 +7022,11 @@ impl<'db> InvalidTypeExpression<'db> {
}
}
- Display { error: self, db }
+ Display {
+ error: self,
+ db,
+ flags,
+ }
}
fn add_subdiagnostics(
diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs
index fac6d20f0efddc..d987ab06bba7ff 100644
--- a/crates/ty_python_semantic/src/types/infer.rs
+++ b/crates/ty_python_semantic/src/types/infer.rs
@@ -979,7 +979,7 @@ impl<'db> ExpressionInference<'db> {
}
bitflags::bitflags! {
- #[derive(Debug, Clone, Copy, PartialEq, Eq)]
+ #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) struct InferenceFlags: u8 {
/// Whether to allow `ParamSpec` in type expressions.
///
@@ -997,9 +997,20 @@ bitflags::bitflags! {
/// Whether the visitor is currently visiting a vararg annotation
/// (e.g., `*args: int` or `**kwargs: int` in a function definition).
const IN_VARARG_ANNOTATION = 1 << 2;
+
+ /// Whether the visitor is currently visiting a return-type annotation
+ const IN_RETURN_TYPE = 1 << 3;
+
+ /// Whether the visitor is currently visiting a type alias value expression
+ const IN_TYPE_ALIAS = 1 << 4;
+
+ /// Whether the visitor is currently visiting a parameter annotation
+ const IN_PARAMETER_ANNOTATION = 1 << 5;
}
}
+impl get_size2::GetSize for InferenceFlags {}
+
impl InferenceFlags {
#[must_use = "Inference flags should always be restored to the original value after being temporarily modified"]
fn replace(&mut self, other: Self, set_to: bool) -> bool {
@@ -1007,4 +1018,16 @@ impl InferenceFlags {
self.set(other, set_to);
previously_contained_flag
}
+
+ pub(super) const fn type_expression_context(self) -> &'static str {
+ if self.contains(InferenceFlags::IN_RETURN_TYPE) {
+ "return type annotation"
+ } else if self.contains(InferenceFlags::IN_PARAMETER_ANNOTATION) {
+ "parameter annotation"
+ } else if self.contains(InferenceFlags::IN_TYPE_ALIAS) {
+ "type alias value"
+ } else {
+ "type expression"
+ }
+ }
}
diff --git a/crates/ty_python_semantic/src/types/infer/builder.rs b/crates/ty_python_semantic/src/types/infer/builder.rs
index a78fc100caa1e6..b6dddb7c44e0d5 100644
--- a/crates/ty_python_semantic/src/types/infer/builder.rs
+++ b/crates/ty_python_semantic/src/types/infer/builder.rs
@@ -1261,7 +1261,9 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
let previous_check_unbound_typevars = self
.inference_flags
.replace(InferenceFlags::CHECK_UNBOUND_TYPEVARS, true);
+ self.inference_flags |= InferenceFlags::IN_TYPE_ALIAS;
let value_ty = self.infer_type_expression(&type_alias.value);
+ self.inference_flags.remove(InferenceFlags::IN_TYPE_ALIAS);
self.inference_flags.set(
InferenceFlags::CHECK_UNBOUND_TYPEVARS,
previous_check_unbound_typevars,
diff --git a/crates/ty_python_semantic/src/types/infer/builder/annotation_expression.rs b/crates/ty_python_semantic/src/types/infer/builder/annotation_expression.rs
index f2bbc379d6722f..0846b84ac051dd 100644
--- a/crates/ty_python_semantic/src/types/infer/builder/annotation_expression.rs
+++ b/crates/ty_python_semantic/src/types/infer/builder/annotation_expression.rs
@@ -39,18 +39,6 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
self.infer_annotation_expression_inner(annotation, deferred_state, PEP613Policy::Allowed)
}
- /// Similar to [`infer_annotation_expression`], but accepts an optional annotation expression
- /// and returns [`None`] if the annotation is [`None`].
- ///
- /// [`infer_annotation_expression`]: TypeInferenceBuilder::infer_annotation_expression
- pub(super) fn infer_optional_annotation_expression(
- &mut self,
- annotation: Option<&ast::Expr>,
- deferred_state: DeferredExpressionState,
- ) -> Option> {
- annotation.map(|expr| self.infer_annotation_expression(expr, deferred_state))
- }
-
fn infer_annotation_expression_inner(
&mut self,
annotation: &ast::Expr,
@@ -140,17 +128,9 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
};
special_case.unwrap_or_else(|| {
- let result_ty = ty
- .default_specialize(builder.db())
- .in_type_expression(
- builder.db(),
- builder.scope(),
- builder.typevar_binding_context,
- builder.inference_flags,
- )
- .unwrap_or_else(|error| error.into_fallback_type(&builder.context, annotation));
- let result_ty = builder.check_for_unbound_type_variable(annotation, result_ty);
- TypeAndQualifiers::declared(result_ty)
+ TypeAndQualifiers::declared(
+ builder.infer_name_or_attribute_type_expression(ty, annotation),
+ )
})
}
@@ -164,21 +144,12 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
return TypeAndQualifiers::declared(self.infer_type_expression(annotation));
}
match attribute.ctx {
- ast::ExprContext::Load => {
- let attribute_type = self.infer_attribute_expression(attribute);
- if let Type::TypeVar(typevar) = attribute_type
- && typevar.paramspec_attr(self.db()).is_some()
- {
- TypeAndQualifiers::declared(attribute_type)
- } else {
- infer_name_or_attribute(
- attribute_type,
- annotation,
- self,
- pep_613_policy,
- )
- }
- }
+ ast::ExprContext::Load => infer_name_or_attribute(
+ self.infer_attribute_expression(attribute),
+ annotation,
+ self,
+ pep_613_policy,
+ ),
ast::ExprContext::Invalid => TypeAndQualifiers::declared(Type::unknown()),
ast::ExprContext::Store | ast::ExprContext::Del => TypeAndQualifiers::declared(
todo_type!("Attribute expression annotation in Store/Del context"),
@@ -223,7 +194,11 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
self.inference_flags,
)
.unwrap_or_else(|err| {
- err.into_fallback_type(&self.context, subscript)
+ err.into_fallback_type(
+ &self.context,
+ subscript,
+ self.inference_flags,
+ )
});
TypeAndQualifiers::declared(in_type_expression)
.with_qualifier(inferred.qualifiers())
@@ -344,7 +319,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
&mut self,
string: &ast::ExprStringLiteral,
) -> TypeAndQualifiers<'db> {
- match parse_string_annotation(&self.context, string) {
+ match parse_string_annotation(&self.context, self.inference_flags, string) {
Some(parsed) => {
self.string_annotations
.insert(ruff_python_ast::ExprRef::StringLiteral(string).into());
diff --git a/crates/ty_python_semantic/src/types/infer/builder/function.rs b/crates/ty_python_semantic/src/types/infer/builder/function.rs
index fc1365568432c4..0b22120b297933 100644
--- a/crates/ty_python_semantic/src/types/infer/builder/function.rs
+++ b/crates/ty_python_semantic/src/types/infer/builder/function.rs
@@ -1,5 +1,4 @@
use crate::{
- TypeQualifiers,
semantic_index::{
definition::{Definition, DefinitionKind},
scope::NodeWithScopeRef,
@@ -428,10 +427,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
let previous_typevar_binding_context = self.typevar_binding_context.replace(definition);
if !has_type_params {
- self.infer_return_type_annotation(
- function.returns.as_deref(),
- self.defer_annotations().into(),
- );
+ self.infer_return_type_annotation(function.returns.as_deref());
self.infer_parameters(function.parameters.as_ref());
}
@@ -488,32 +484,14 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
self.typevar_binding_context = previous_typevar_binding_context;
}
- fn infer_return_type_annotation(
- &mut self,
- returns: Option<&ast::Expr>,
- deferred_expression_state: DeferredExpressionState,
- ) {
- let Some(returns) = returns else {
- return;
- };
- let annotated = self.infer_annotation_expression(returns, deferred_expression_state);
-
- if annotated.qualifiers.is_empty() {
- return;
- }
- for qualifier in [
- TypeQualifiers::FINAL,
- TypeQualifiers::CLASS_VAR,
- TypeQualifiers::INIT_VAR,
- ] {
- if annotated.qualifiers.contains(qualifier)
- && let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, returns)
- {
- builder.into_diagnostic(format!(
- "`{name}` is not allowed in function return type annotations",
- name = qualifier.name()
- ));
- }
+ fn infer_return_type_annotation(&mut self, returns: Option<&ast::Expr>) {
+ if let Some(returns) = returns {
+ self.inference_flags |= InferenceFlags::IN_RETURN_TYPE;
+ self.infer_type_expression_with_state(
+ returns,
+ DeferredExpressionState::from(self.defer_annotations()),
+ );
+ self.inference_flags.remove(InferenceFlags::IN_RETURN_TYPE);
}
}
@@ -526,10 +504,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
let binding_context = self.index.expect_single_definition(function);
let previous_typevar_binding_context =
self.typevar_binding_context.replace(binding_context);
- self.infer_return_type_annotation(
- function.returns.as_deref(),
- self.defer_annotations().into(),
- );
+ self.infer_return_type_annotation(function.returns.as_deref());
self.infer_type_parameters(type_params);
self.infer_parameters(&function.parameters);
self.typevar_binding_context = previous_typevar_binding_context;
@@ -546,6 +521,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
kwarg,
} = parameters;
+ self.inference_flags |= InferenceFlags::IN_PARAMETER_ANNOTATION;
for param_with_default in parameters.iter_non_variadic_params() {
self.infer_parameter_with_default(param_with_default);
}
@@ -558,6 +534,8 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
if let Some(kwarg) = kwarg {
self.infer_parameter(kwarg);
}
+ self.inference_flags
+ .remove(InferenceFlags::IN_PARAMETER_ANNOTATION);
}
fn infer_parameter_with_default(&mut self, parameter_with_default: &ast::ParameterWithDefault) {
@@ -568,37 +546,11 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
default: _,
} = parameter_with_default;
- let annotated = self.infer_optional_annotation_expression(
- parameter.annotation.as_deref(),
- self.defer_annotations().into(),
- );
-
- let Some(annotated) = annotated else {
- return;
- };
-
- let qualifiers = annotated.qualifiers;
-
- if qualifiers.is_empty() {
- return;
- }
-
- for qualifier in [
- TypeQualifiers::FINAL,
- TypeQualifiers::CLASS_VAR,
- TypeQualifiers::INIT_VAR,
- TypeQualifiers::REQUIRED,
- TypeQualifiers::NOT_REQUIRED,
- TypeQualifiers::READ_ONLY,
- ] {
- if qualifiers.contains(qualifier)
- && let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, parameter)
- {
- builder.into_diagnostic(format!(
- "`{name}` is not allowed in function parameter annotations",
- name = qualifier.name()
- ));
- }
+ if let Some(annotation) = parameter.annotation.as_deref() {
+ self.infer_type_expression_with_state(
+ annotation,
+ DeferredExpressionState::from(self.defer_annotations()),
+ );
}
}
@@ -610,10 +562,12 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
annotation,
} = parameter;
- self.infer_optional_annotation_expression(
- annotation.as_deref(),
- self.defer_annotations().into(),
- );
+ if let Some(annotation) = annotation.as_deref() {
+ self.infer_type_expression_with_state(
+ annotation,
+ DeferredExpressionState::from(self.defer_annotations()),
+ );
+ }
}
/// Set initial declared type (if annotated) and inferred type for a function-parameter symbol,
diff --git a/crates/ty_python_semantic/src/types/infer/builder/type_expression.rs b/crates/ty_python_semantic/src/types/infer/builder/type_expression.rs
index c8bc1513c161bb..cd70240a19b371 100644
--- a/crates/ty_python_semantic/src/types/infer/builder/type_expression.rs
+++ b/crates/ty_python_semantic/src/types/infer/builder/type_expression.rs
@@ -1,6 +1,7 @@
use itertools::Either;
use ruff_python_ast::helpers::is_dotted_name;
use ruff_python_ast::{self as ast, PythonVersion};
+use ruff_text_size::Ranged;
use super::{DeferredExpressionState, TypeInferenceBuilder};
use crate::semantic_index::scope::ScopeKind;
@@ -26,6 +27,10 @@ use crate::{FxOrderSet, Program, add_inferred_python_version_hint_to_diagnostic}
/// Type expressions
impl<'db> TypeInferenceBuilder<'db, '_> {
+ pub(super) const fn type_expression_context(&self) -> &'static str {
+ self.inference_flags.type_expression_context()
+ }
+
/// Infer the type of a type expression.
pub(super) fn infer_type_expression(&mut self, expression: &ast::Expr) -> Type<'db> {
let previous_deferred_state = self.deferred_state;
@@ -51,7 +56,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
/// Similar to [`infer_type_expression`], but accepts a [`DeferredExpressionState`].
///
/// [`infer_type_expression`]: TypeInferenceBuilder::infer_type_expression
- fn infer_type_expression_with_state(
+ pub(super) fn infer_type_expression_with_state(
&mut self,
expression: &ast::Expr,
deferred_state: DeferredExpressionState,
@@ -64,7 +69,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
fn report_invalid_type_expression(
&self,
- expression: &ast::Expr,
+ expression: impl Ranged,
message: impl std::fmt::Display,
) -> Option> {
self.context
@@ -74,25 +79,39 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
})
}
+ pub(super) fn infer_name_or_attribute_type_expression(
+ &self,
+ ty: Type<'db>,
+ annotation: &ast::Expr,
+ ) -> Type<'db> {
+ if annotation.is_attribute_expr()
+ && let Type::TypeVar(tvar) = ty
+ && tvar.paramspec_attr(self.db()).is_some()
+ {
+ return ty;
+ }
+ let result_ty = ty
+ .default_specialize(self.db())
+ .in_type_expression(
+ self.db(),
+ self.scope(),
+ self.typevar_binding_context,
+ self.inference_flags,
+ )
+ .unwrap_or_else(|error| {
+ error.into_fallback_type(&self.context, annotation, self.inference_flags)
+ });
+ self.check_for_unbound_type_variable(annotation, result_ty)
+ }
+
/// Infer the type of a type expression without storing the result.
pub(super) fn infer_type_expression_no_store(&mut self, expression: &ast::Expr) -> Type<'db> {
// https://typing.python.org/en/latest/spec/annotations.html#grammar-token-expression-grammar-type_expression
match expression {
ast::Expr::Name(name) => match name.ctx {
ast::ExprContext::Load => {
- let ty = self
- .infer_name_expression(name)
- .default_specialize(self.db())
- .in_type_expression(
- self.db(),
- self.scope(),
- self.typevar_binding_context,
- self.inference_flags,
- )
- .unwrap_or_else(|error| {
- error.into_fallback_type(&self.context, expression)
- });
- self.check_for_unbound_type_variable(expression, ty)
+ let ty = self.infer_name_expression(name);
+ self.infer_name_or_attribute_type_expression(ty, expression)
}
ast::ExprContext::Invalid => Type::unknown(),
ast::ExprContext::Store | ast::ExprContext::Del => {
@@ -103,18 +122,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
ast::Expr::Attribute(attribute_expression) => {
if is_dotted_name(expression) {
match attribute_expression.ctx {
- ast::ExprContext::Load => self
- .infer_attribute_expression(attribute_expression)
- .default_specialize(self.db())
- .in_type_expression(
- self.db(),
- self.scope(),
- self.typevar_binding_context,
- self.inference_flags,
- )
- .unwrap_or_else(|error| {
- error.into_fallback_type(&self.context, expression)
- }),
+ ast::ExprContext::Load => {
+ let ty = self.infer_attribute_expression(attribute_expression);
+ self.infer_name_or_attribute_type_expression(ty, expression)
+ }
ast::ExprContext::Invalid => Type::unknown(),
ast::ExprContext::Store | ast::ExprContext::Del => {
todo_type!("Attribute expression annotation in Store/Del context")
@@ -126,8 +137,11 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
self.report_invalid_type_expression(
expression,
- "Only simple names, dotted names and subscripts \
- can be used in type expressions",
+ format_args!(
+ "Only simple names, dotted names and subscripts \
+ can be used in {}s",
+ self.type_expression_context()
+ ),
);
Type::unknown()
}
@@ -157,7 +171,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
self.report_invalid_type_expression(
expression,
- "Only simple names and dotted names can be subscripted in type expressions",
+ format_args!(
+ "Only simple names and dotted names can be subscripted in {}s",
+ self.type_expression_context()
+ ),
);
Type::unknown()
}
@@ -280,10 +297,11 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
&mut diagnostic,
);
} else if python_version < PythonVersion::PY314 {
- diagnostic.info(
- "All type expressions are evaluated at \
+ diagnostic.info(format_args!(
+ "All {}s are evaluated at \
runtime by default on Python <3.14",
- );
+ self.type_expression_context()
+ ));
add_inferred_python_version_hint_to_diagnostic(
self.db(),
&mut diagnostic,
@@ -333,7 +351,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
ast::Expr::BytesLiteral(bytes) => {
if let Some(mut diagnostic) = self.report_invalid_type_expression(
expression,
- "Bytes literals are not allowed in this context in a type expression",
+ format_args!(
+ "Bytes literals are not allowed in this context in a {}",
+ self.type_expression_context()
+ ),
) {
if let Some(single_element) = bytes.as_single_part_bytestring()
&& let Ok(valid_string) = String::from_utf8(single_element.value.to_vec())
@@ -353,7 +374,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
if let Some(mut diagnostic) = self.report_invalid_type_expression(
expression,
format_args!(
- "Int literals are not allowed in this context in a type expression"
+ "Int literals are not allowed in this context in a {}",
+ self.type_expression_context()
),
) {
if let Some(int) = int.as_i64() {
@@ -372,7 +394,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}) => {
self.report_invalid_type_expression(
expression,
- format_args!("Float literals are not allowed in type expressions"),
+ format_args!(
+ "Float literals are not allowed in {}s",
+ self.type_expression_context()
+ ),
);
Type::unknown()
}
@@ -383,7 +408,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}) => {
self.report_invalid_type_expression(
expression,
- format_args!("Complex literals are not allowed in type expressions"),
+ format_args!(
+ "Complex literals are not allowed in {}s",
+ self.type_expression_context()
+ ),
);
Type::unknown()
}
@@ -392,7 +420,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
if let Some(mut diagnostic) = self.report_invalid_type_expression(
expression,
format_args!(
- "Boolean literals are not allowed in this context in a type expression"
+ "Boolean literals are not allowed in this context in a {}",
+ self.type_expression_context()
),
) {
diagnostic.set_primary_message(format_args!(
@@ -413,7 +442,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
if let Some(mut diagnostic) = self.report_invalid_type_expression(
expression,
format_args!(
- "List literals are not allowed in this context in a type expression"
+ "List literals are not allowed in this context in a {}",
+ self.type_expression_context()
),
) && let [single_element] = &*list.elts
{
@@ -444,7 +474,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
if let Some(mut diagnostic) = self.report_invalid_type_expression(
expression,
format_args!(
- "Tuple literals are not allowed in this context in a type expression"
+ "Tuple literals are not allowed in this context in a {}",
+ self.type_expression_context()
),
) {
let mut speculative = self.speculate();
@@ -477,7 +508,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
self.report_invalid_type_expression(
expression,
- format_args!("Boolean operations are not allowed in type expressions"),
+ format_args!(
+ "Boolean operations are not allowed in {}s",
+ self.type_expression_context()
+ ),
);
Type::unknown()
}
@@ -488,7 +522,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
self.report_invalid_type_expression(
expression,
- format_args!("Named expressions are not allowed in type expressions"),
+ format_args!(
+ "Named expressions are not allowed in {}s",
+ self.type_expression_context()
+ ),
);
Type::unknown()
}
@@ -499,7 +536,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
self.report_invalid_type_expression(
expression,
- format_args!("Unary operations are not allowed in type expressions"),
+ format_args!(
+ "Unary operations are not allowed in {}s",
+ self.type_expression_context()
+ ),
);
Type::unknown()
}
@@ -510,7 +550,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
self.report_invalid_type_expression(
expression,
- format_args!("`lambda` expressions are not allowed in type expressions"),
+ format_args!(
+ "`lambda` expressions are not allowed in {}s",
+ self.type_expression_context()
+ ),
);
Type::unknown()
}
@@ -521,7 +564,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
self.report_invalid_type_expression(
expression,
- format_args!("`if` expressions are not allowed in type expressions"),
+ format_args!(
+ "`if` expressions are not allowed in {}s",
+ self.type_expression_context()
+ ),
);
Type::unknown()
}
@@ -532,7 +578,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
if let Some(mut diagnostic) = self.report_invalid_type_expression(
expression,
- format_args!("Dict literals are not allowed in type expressions"),
+ format_args!(
+ "Dict literals are not allowed in {}s",
+ self.type_expression_context()
+ ),
) && let [
ast::DictItem {
key: Some(key),
@@ -561,7 +610,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
if let Some(mut diagnostic) = self.report_invalid_type_expression(
expression,
- format_args!("Set literals are not allowed in type expressions"),
+ format_args!(
+ "Set literals are not allowed in {}s",
+ self.type_expression_context()
+ ),
) && let [single_element] = &*set.elts
{
let mut speculative_builder = self.speculate();
@@ -586,7 +638,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
self.report_invalid_type_expression(
expression,
- format_args!("Dict comprehensions are not allowed in type expressions"),
+ format_args!(
+ "Dict comprehensions are not allowed in {}s",
+ self.type_expression_context()
+ ),
);
Type::unknown()
}
@@ -597,7 +652,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
self.report_invalid_type_expression(
expression,
- format_args!("List comprehensions are not allowed in type expressions"),
+ format_args!(
+ "List comprehensions are not allowed in {}s",
+ self.type_expression_context()
+ ),
);
Type::unknown()
}
@@ -608,7 +666,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
self.report_invalid_type_expression(
expression,
- format_args!("Set comprehensions are not allowed in type expressions"),
+ format_args!(
+ "Set comprehensions are not allowed in {}s",
+ self.type_expression_context()
+ ),
);
Type::unknown()
}
@@ -619,7 +680,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
self.report_invalid_type_expression(
expression,
- format_args!("Generator expressions are not allowed in type expressions"),
+ format_args!(
+ "Generator expressions are not allowed in {}s",
+ self.type_expression_context()
+ ),
);
Type::unknown()
}
@@ -630,7 +694,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
self.report_invalid_type_expression(
expression,
- format_args!("`await` expressions are not allowed in type expressions"),
+ format_args!(
+ "`await` expressions are not allowed in {}s",
+ self.type_expression_context()
+ ),
);
Type::unknown()
}
@@ -641,7 +708,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
self.report_invalid_type_expression(
expression,
- format_args!("`yield` expressions are not allowed in type expressions"),
+ format_args!(
+ "`yield` expressions are not allowed in {}s",
+ self.type_expression_context()
+ ),
);
Type::unknown()
}
@@ -652,7 +722,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
self.report_invalid_type_expression(
expression,
- format_args!("`yield from` expressions are not allowed in type expressions"),
+ format_args!(
+ "`yield from` expressions are not allowed in {}s",
+ self.type_expression_context()
+ ),
);
Type::unknown()
}
@@ -663,7 +736,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
self.report_invalid_type_expression(
expression,
- format_args!("Comparison expressions are not allowed in type expressions"),
+ format_args!(
+ "Comparison expressions are not allowed in {}s",
+ self.type_expression_context()
+ ),
);
Type::unknown()
}
@@ -674,7 +750,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
self.report_invalid_type_expression(
expression,
- format_args!("Function calls are not allowed in type expressions"),
+ format_args!(
+ "Function calls are not allowed in {}s",
+ self.type_expression_context()
+ ),
);
Type::unknown()
}
@@ -685,7 +764,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
self.report_invalid_type_expression(
expression,
- "F-strings are not allowed in type expressions",
+ format_args!(
+ "F-strings are not allowed in {}s",
+ self.type_expression_context(),
+ ),
);
Type::unknown()
}
@@ -696,7 +778,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
self.report_invalid_type_expression(
expression,
- format_args!("T-strings are not allowed in type expressions"),
+ format_args!(
+ "T-strings are not allowed in {}s",
+ self.type_expression_context()
+ ),
);
Type::unknown()
}
@@ -707,7 +792,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
self.report_invalid_type_expression(
expression,
- format_args!("Slices are not allowed in type expressions"),
+ format_args!(
+ "Slices are not allowed in {}s",
+ self.type_expression_context()
+ ),
);
Type::unknown()
}
@@ -725,7 +813,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
ast::Expr::EllipsisLiteral(_) => {
self.report_invalid_type_expression(
expression,
- "`...` is not allowed in this context in a type expression",
+ format_args!(
+ "`...` is not allowed in this context in a {}",
+ self.type_expression_context(),
+ ),
);
Type::unknown()
}
@@ -771,7 +862,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
&mut self,
string: &ast::ExprStringLiteral,
) -> Type<'db> {
- match parse_string_annotation(&self.context, string) {
+ match parse_string_annotation(&self.context, self.inference_flags, string) {
Some(parsed) => {
self.string_annotations
.insert(ruff_python_ast::ExprRef::StringLiteral(string).into());
@@ -1234,7 +1325,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
builder.into_diagnostic(format_args!(
- "`typing.Protocol` is not allowed in type expressions",
+ "`typing.Protocol` is not allowed in {}s",
+ self.type_expression_context(),
));
}
Type::unknown()
@@ -1245,7 +1337,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
builder.into_diagnostic(format_args!(
- "`typing.Generic` is not allowed in type expressions",
+ "`typing.Generic` is not allowed in {}s",
+ self.type_expression_context(),
));
}
Type::unknown()
@@ -1256,7 +1349,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
builder.into_diagnostic(format_args!(
- "`warnings.deprecated` is not allowed in type expressions",
+ "`warnings.deprecated` is not allowed in {}s",
+ self.type_expression_context(),
));
}
Type::unknown()
@@ -1267,7 +1361,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
builder.into_diagnostic(format_args!(
- "`dataclasses.Field` is not allowed in type expressions",
+ "`dataclasses.Field` is not allowed in {}s",
+ self.type_expression_context(),
));
}
Type::unknown()
@@ -1278,7 +1373,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
builder.into_diagnostic(format_args!(
- "`ty_extensions.ConstraintSet` is not allowed in type expressions",
+ "`ty_extensions.ConstraintSet` is not allowed in {}s",
+ self.type_expression_context(),
));
}
Type::unknown()
@@ -1289,7 +1385,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
builder.into_diagnostic(format_args!(
- "`ty_extensions.GenericContext` is not allowed in type expressions",
+ "`ty_extensions.GenericContext` is not allowed in {}s",
+ self.type_expression_context(),
));
}
Type::unknown()
@@ -1300,7 +1397,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
builder.into_diagnostic(format_args!(
- "`ty_extensions.Specialization` is not allowed in type expressions",
+ "`ty_extensions.Specialization` is not allowed in {}s",
+ self.type_expression_context(),
));
}
Type::unknown()
@@ -1514,8 +1612,9 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
builder.into_diagnostic(format_args!(
- "Invalid subscript of object of type `{}` in type expression",
- value_ty.display(self.db())
+ "Invalid subscript of object of type `{}` in a {}",
+ value_ty.display(self.db()),
+ self.type_expression_context()
));
}
Type::unknown()
@@ -1682,7 +1781,9 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
)
.inner_type()
.in_type_expression(self.db(), self.scope(), None, self.inference_flags)
- .unwrap_or_else(|err| err.into_fallback_type(&self.context, subscript)),
+ .unwrap_or_else(|err| {
+ err.into_fallback_type(&self.context, subscript, self.inference_flags)
+ }),
SpecialFormType::Literal => match self.infer_literal_parameter_type(arguments_slice) {
Ok(ty) => ty,
Err(nodes) => {
@@ -1912,12 +2013,26 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
self.infer_parameterized_legacy_typing_alias(subscript, alias)
}
SpecialFormType::TypeQualifier(qualifier) => {
- if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
- let diag = builder.into_diagnostic(format_args!(
- "Type qualifier `{qualifier}` is not allowed in type expressions \
- (only in annotation expressions)",
- ));
- diagnostic::add_type_expression_reference_link(diag);
+ if self.inference_flags.intersects(
+ InferenceFlags::IN_PARAMETER_ANNOTATION
+ | InferenceFlags::IN_RETURN_TYPE
+ | InferenceFlags::IN_TYPE_ALIAS,
+ ) {
+ self.report_invalid_type_expression(
+ subscript,
+ format_args!(
+ "Type qualifier `{qualifier}` is not allowed in {}s",
+ self.inference_flags.type_expression_context(),
+ ),
+ );
+ } else {
+ self.report_invalid_type_expression(
+ subscript,
+ format_args!(
+ "Type qualifier `{qualifier}` is not allowed in type expressions \
+ (only in annotation expressions)",
+ ),
+ );
}
self.infer_type_expression(arguments_slice)
}
@@ -1981,7 +2096,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
SpecialFormType::Concatenate => {
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
let mut diag = builder.into_diagnostic(format_args!(
- "`typing.Concatenate` is not allowed in this context in a type expression",
+ "`typing.Concatenate` is not allowed in this context in a {}",
+ self.type_expression_context()
));
diag.info("`typing.Concatenate` is only valid:");
diag.info(" - as the first argument to `typing.Callable`");
@@ -2125,7 +2241,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
builder.into_diagnostic(format_args!(
- "`{special_form}` is not allowed in type expressions",
+ "`{special_form}` is not allowed in {}s",
+ self.type_expression_context(),
));
}
Type::unknown()
@@ -2331,7 +2448,9 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
}
}
ast::Expr::StringLiteral(string) => {
- if let Some(parsed) = parse_string_annotation(&self.context, string) {
+ if let Some(parsed) =
+ parse_string_annotation(&self.context, self.inference_flags, string)
+ {
self.string_annotations
.insert(ruff_python_ast::ExprRef::StringLiteral(string).into());
let node_key = self.enclosing_node_key(string.into());
@@ -2448,7 +2567,9 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
Some(ConcatenateTail::ParamSpec(typevar))
}
ast::Expr::StringLiteral(string) => {
- let Some(parsed) = parse_string_annotation(&self.context, string) else {
+ let Some(parsed) =
+ parse_string_annotation(&self.context, self.inference_flags, string)
+ else {
report_invalid_concatenate_last_arg(&self.context, expr, Type::unknown());
return None;
};
diff --git a/crates/ty_python_semantic/src/types/special_form.rs b/crates/ty_python_semantic/src/types/special_form.rs
index b1e44f71d6a589..fd6dd7ba23627c 100644
--- a/crates/ty_python_semantic/src/types/special_form.rs
+++ b/crates/ty_python_semantic/src/types/special_form.rs
@@ -745,7 +745,9 @@ impl SpecialFormType {
SpecialFormType::Tuple => Ok(Type::homogeneous_tuple(db, Type::unknown())),
SpecialFormType::Callable => Ok(Type::Callable(CallableType::unknown(db))),
SpecialFormType::LegacyStdlibAlias(alias) => Ok(alias.aliased_class().to_instance(db)),
- SpecialFormType::TypeQualifier(qualifier) => Err(qualifier.in_type_expression()),
+ SpecialFormType::TypeQualifier(qualifier) => {
+ Err(InvalidTypeExpression::TypeQualifier(qualifier))
+ }
}
}
}
@@ -884,17 +886,12 @@ impl TypeQualifier {
}
}
- const fn in_type_expression(self) -> InvalidTypeExpression<'static> {
+ /// Return `true` if this type qualifier requires exactly one argument
+ /// when used in a type expression.
+ pub(super) const fn requires_one_argument(self) -> bool {
match self {
- TypeQualifier::Final | TypeQualifier::ClassVar => {
- InvalidTypeExpression::TypeQualifier(self)
- }
- TypeQualifier::ReadOnly
- | TypeQualifier::NotRequired
- | TypeQualifier::InitVar
- | TypeQualifier::Required => {
- InvalidTypeExpression::TypeQualifierRequiresOneArgument(self)
- }
+ Self::Final | Self::ClassVar => false,
+ Self::Required | Self::NotRequired | Self::InitVar | Self::ReadOnly => true,
}
}
}
diff --git a/crates/ty_python_semantic/src/types/string_annotation.rs b/crates/ty_python_semantic/src/types/string_annotation.rs
index 4b730a55be7b30..0619e818457610 100644
--- a/crates/ty_python_semantic/src/types/string_annotation.rs
+++ b/crates/ty_python_semantic/src/types/string_annotation.rs
@@ -6,6 +6,7 @@ use ruff_text_size::Ranged;
use crate::declare_lint;
use crate::lint::{Level, LintStatus};
+use crate::types::infer::InferenceFlags;
use super::context::InferContext;
@@ -124,6 +125,7 @@ declare_lint! {
/// Parses the given expression as a string annotation.
pub(crate) fn parse_string_annotation(
context: &InferContext,
+ inference_flags: InferenceFlags,
string_expr: &ast::ExprStringLiteral,
) -> Option> {
let file = context.file();
@@ -139,7 +141,10 @@ pub(crate) fn parse_string_annotation(
if prefix.is_raw() {
if let Some(builder) = context.report_lint(&RAW_STRING_TYPE_ANNOTATION, string_literal)
{
- builder.into_diagnostic("Raw string literals are not allowed in type expressions");
+ builder.into_diagnostic(format_args!(
+ "Raw string literals are not allowed in {}s",
+ inference_flags.type_expression_context()
+ ));
}
// Compare the raw contents (without quotes) of the expression with the parsed contents
// contained in the string literal.
@@ -166,7 +171,10 @@ pub(crate) fn parse_string_annotation(
{
// The raw contents of the string doesn't match the parsed content. This could be the
// case for annotations that contain escape sequences.
- builder.into_diagnostic("Escape characters are not allowed in type expressions");
+ builder.into_diagnostic(format_args!(
+ "Escape characters are not allowed in {}s",
+ inference_flags.type_expression_context()
+ ));
}
} else if let Some(builder) =
context.report_lint(&IMPLICIT_CONCATENATED_STRING_TYPE_ANNOTATION, string_expr)