Show more precise messages in invalid type expressions (#16850)

## Summary

Some error messages were not very specific; this PR improves them

## Test Plan

New mdtests added; existing mdtests tweaked
This commit is contained in:
Matthew Mckee 2025-03-19 17:00:30 +00:00 committed by GitHub
parent 98fdc0ebae
commit 4ed93b4311
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 171 additions and 122 deletions

View file

@ -29,7 +29,7 @@ It is invalid to parameterize `Annotated` with less than two arguments.
```py
from typing_extensions import Annotated
# error: [invalid-type-form] "`Annotated` requires at least two arguments when used in an annotation or type expression"
# error: [invalid-type-form] "`typing.Annotated` requires at least two arguments when used in a type expression"
def _(x: Annotated):
reveal_type(x) # revealed: Unknown
@ -39,11 +39,11 @@ def _(flag: bool):
else:
X = bool
# error: [invalid-type-form] "`Annotated` requires at least two arguments when used in an annotation or type expression"
# error: [invalid-type-form] "`typing.Annotated` requires at least two arguments when used in a type expression"
def f(y: X):
reveal_type(y) # revealed: Unknown | bool
# error: [invalid-type-form] "`Annotated` requires at least two arguments when used in an annotation or type expression"
# error: [invalid-type-form] "`typing.Annotated` requires at least two arguments when used in a type expression"
def _(x: Annotated | bool):
reveal_type(x) # revealed: Unknown | bool

View file

@ -18,7 +18,7 @@ def f(*args: Unpack[Ts]) -> tuple[Unpack[Ts]]:
# TODO: should understand the annotation
reveal_type(args) # revealed: tuple
reveal_type(Alias) # revealed: @Todo(Invalid or unsupported `KnownInstanceType` in `Type::to_type_expression`)
reveal_type(Alias) # revealed: @Todo(Support for `typing.TypeAlias`)
def g() -> TypeGuard[int]: ...
def h() -> TypeIs[int]: ...
@ -35,7 +35,26 @@ def i(callback: Callable[Concatenate[int, P], R_co], *args: P.args, **kwargs: P.
class Foo:
def method(self, x: Self):
reveal_type(x) # revealed: @Todo(Invalid or unsupported `KnownInstanceType` in `Type::to_type_expression`)
reveal_type(x) # revealed: @Todo(Support for `typing.Self`)
```
## Type expressions
One thing that is supported is error messages for using special forms in type expressions.
```py
from typing_extensions import Unpack, TypeGuard, TypeIs, Concatenate
def _(
a: Unpack, # error: [invalid-type-form] "`typing.Unpack` requires exactly one argument when used in a type expression"
b: TypeGuard, # error: [invalid-type-form] "`typing.TypeGuard` requires exactly one argument when used in a type expression"
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` requires at least two arguments when used in a type expression"
) -> None:
reveal_type(a) # revealed: Unknown
reveal_type(b) # revealed: Unknown
reveal_type(c) # revealed: Unknown
reveal_type(d) # revealed: Unknown
```
## Inheritance

View file

@ -1,6 +1,6 @@
# Unsupported type qualifiers
## Not yet supported
## Not yet fully supported
Several type qualifiers are unsupported by red-knot currently. However, we also don't emit
false-positive errors if you use one in an annotation:
@ -19,6 +19,33 @@ class Bar(TypedDict):
z: ReadOnly[bytes]
```
## Type expressions
One thing that is supported is error messages for using type qualifiers in type expressions.
```py
from typing_extensions import Final, ClassVar, Required, NotRequired, ReadOnly
def _(
a: (
Final # error: [invalid-type-form] "Type qualifier `typing.Final` is not allowed in type expressions (only in annotation expressions)"
| int
),
b: (
ClassVar # error: [invalid-type-form] "Type qualifier `typing.ClassVar` is not allowed in type expressions (only in annotation expressions)"
| int
),
c: Required, # error: [invalid-type-form] "Type qualifier `typing.Required` is not allowed in type expressions (only in annotation expressions, and only with exactly one argument)"
d: NotRequired, # error: [invalid-type-form] "Type qualifier `typing.NotRequired` is not allowed in type expressions (only in annotation expressions, and only with exactly one argument)"
e: ReadOnly, # error: [invalid-type-form] "Type qualifier `typing.ReadOnly` is not allowed in type expressions (only in annotation expressions, and only with exactly one argument)"
) -> None:
reveal_type(a) # revealed: Unknown | int
reveal_type(b) # revealed: Unknown | int
reveal_type(c) # revealed: Unknown
reveal_type(d) # revealed: Unknown
reveal_type(e) # revealed: Unknown
```
## Inheritance
You can't inherit from a type qualifier.