mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-28 21:05:08 +00:00
[red-knot] Make' Type::in_type_expression()' exhaustive for Type::KnownInstance (#16836)
<!-- Thank you for contributing to Ruff! To help us out with reviewing, please consider the following: - Does this pull request include a summary of the change? (See below.) - Does this pull request include a descriptive title? - Does this pull request include references to any relevant issues? --> ## Summary fixes #15048 We want to handle more types from Type::KnownInstance ## Test Plan Add tests for each type added explicitly in the match --------- Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com>
This commit is contained in:
parent
f3f3e55d97
commit
3a5f1d46c0
7 changed files with 108 additions and 10 deletions
|
@ -156,7 +156,7 @@ def f():
|
|||
```py
|
||||
from typing import Literal
|
||||
|
||||
# error: [invalid-type-form] "`Literal` requires at least one argument when used in a type expression"
|
||||
# error: [invalid-type-form] "`typing.Literal` requires at least one argument when used in a type expression"
|
||||
def _(x: Literal):
|
||||
reveal_type(x) # revealed: Unknown
|
||||
```
|
||||
|
|
|
@ -45,3 +45,13 @@ def f():
|
|||
# revealed: int | None
|
||||
reveal_type(a)
|
||||
```
|
||||
|
||||
## Invalid
|
||||
|
||||
```py
|
||||
from typing import Optional
|
||||
|
||||
# error: [invalid-type-form] "`typing.Optional` requires exactly one argument when used in a type expression"
|
||||
def f(x: Optional) -> None:
|
||||
reveal_type(x) # revealed: Unknown
|
||||
```
|
||||
|
|
|
@ -59,3 +59,13 @@ def f():
|
|||
# revealed: int | str
|
||||
reveal_type(a)
|
||||
```
|
||||
|
||||
## Invalid
|
||||
|
||||
```py
|
||||
from typing import Union
|
||||
|
||||
# error: [invalid-type-form] "`typing.Union` requires at least one argument when used in a type expression"
|
||||
def f(x: Union) -> None:
|
||||
reveal_type(x) # revealed: Unknown
|
||||
```
|
||||
|
|
|
@ -846,5 +846,19 @@ def mixed(
|
|||
reveal_type(i4) # revealed: Any & Unknown
|
||||
```
|
||||
|
||||
## Invalid
|
||||
|
||||
```py
|
||||
from knot_extensions import Intersection, Not
|
||||
|
||||
# error: [invalid-type-form] "`knot_extensions.Intersection` requires at least one argument when used in a type expression"
|
||||
def f(x: Intersection) -> None:
|
||||
reveal_type(x) # revealed: Unknown
|
||||
|
||||
# error: [invalid-type-form] "`knot_extensions.Not` requires exactly one argument when used in a type expression"
|
||||
def f(x: Not) -> None:
|
||||
reveal_type(x) # revealed: Unknown
|
||||
```
|
||||
|
||||
[complement laws]: https://en.wikipedia.org/wiki/Complement_(set_theory)
|
||||
[de morgan's laws]: https://en.wikipedia.org/wiki/De_Morgan%27s_laws
|
||||
|
|
|
@ -13,3 +13,13 @@ def _(some_int: int, some_literal_int: Literal[1], some_indexable: SupportsIndex
|
|||
b: SupportsIndex = some_literal_int
|
||||
c: SupportsIndex = some_indexable
|
||||
```
|
||||
|
||||
## Invalid
|
||||
|
||||
```py
|
||||
from typing import Protocol
|
||||
|
||||
# error: [invalid-type-form] "`typing.Protocol` is not allowed in type expressions"
|
||||
def f(x: Protocol) -> None:
|
||||
reveal_type(x) # revealed: Unknown
|
||||
```
|
||||
|
|
|
@ -392,6 +392,10 @@ def type_of_annotation() -> None:
|
|||
|
||||
# error: "Special form `knot_extensions.TypeOf` expected exactly one type parameter"
|
||||
t: TypeOf[int, str, bytes]
|
||||
|
||||
# error: [invalid-type-form] "`knot_extensions.TypeOf` requires exactly one argument when used in a type expression"
|
||||
def f(x: TypeOf) -> None:
|
||||
reveal_type(x) # revealed: Unknown
|
||||
```
|
||||
|
||||
## `CallableTypeFromFunction`
|
||||
|
@ -418,6 +422,10 @@ def f3(x: int, y: str) -> None:
|
|||
c1: CallableTypeFromFunction[f1, f2]
|
||||
# error: [invalid-type-form] "Expected the first argument to `knot_extensions.CallableTypeFromFunction` to be a function literal, but got `Literal[int]`"
|
||||
c2: CallableTypeFromFunction[int]
|
||||
|
||||
# error: [invalid-type-form] "`knot_extensions.CallableTypeFromFunction` requires exactly one argument when used in a type expression"
|
||||
def f(x: CallableTypeFromFunction) -> None:
|
||||
reveal_type(x) # revealed: Unknown
|
||||
```
|
||||
|
||||
Using it in annotation to reveal the signature of the function:
|
||||
|
|
|
@ -3276,10 +3276,6 @@ impl<'db> Type<'db> {
|
|||
],
|
||||
fallback_type: Type::unknown(),
|
||||
}),
|
||||
Type::KnownInstance(KnownInstanceType::Literal) => Err(InvalidTypeExpressionError {
|
||||
invalid_expressions: smallvec::smallvec![InvalidTypeExpression::BareLiteral],
|
||||
fallback_type: Type::unknown(),
|
||||
}),
|
||||
Type::KnownInstance(KnownInstanceType::Unknown) => Ok(Type::unknown()),
|
||||
Type::KnownInstance(KnownInstanceType::AlwaysTruthy) => Ok(Type::AlwaysTruthy),
|
||||
Type::KnownInstance(KnownInstanceType::AlwaysFalsy) => Ok(Type::AlwaysFalsy),
|
||||
|
@ -3289,7 +3285,44 @@ impl<'db> Type<'db> {
|
|||
GeneralCallableType::unknown(db),
|
||||
)))
|
||||
}
|
||||
Type::KnownInstance(_) => Ok(todo_type!(
|
||||
Type::KnownInstance(
|
||||
KnownInstanceType::Literal
|
||||
| KnownInstanceType::Union
|
||||
| KnownInstanceType::Intersection,
|
||||
) => Err(InvalidTypeExpressionError {
|
||||
invalid_expressions: smallvec::smallvec![InvalidTypeExpression::RequiresArguments(
|
||||
*self
|
||||
)],
|
||||
fallback_type: Type::unknown(),
|
||||
}),
|
||||
Type::KnownInstance(
|
||||
KnownInstanceType::Optional
|
||||
| KnownInstanceType::Not
|
||||
| KnownInstanceType::TypeOf
|
||||
| KnownInstanceType::CallableTypeFromFunction,
|
||||
) => Err(InvalidTypeExpressionError {
|
||||
invalid_expressions: smallvec::smallvec![
|
||||
InvalidTypeExpression::RequiresOneArgument(*self)
|
||||
],
|
||||
fallback_type: Type::unknown(),
|
||||
}),
|
||||
Type::KnownInstance(KnownInstanceType::Protocol) => Err(InvalidTypeExpressionError {
|
||||
invalid_expressions: smallvec::smallvec![
|
||||
InvalidTypeExpression::ProtocolInTypeExpression
|
||||
],
|
||||
fallback_type: Type::unknown(),
|
||||
}),
|
||||
Type::KnownInstance(
|
||||
KnownInstanceType::TypingSelf
|
||||
| KnownInstanceType::ReadOnly
|
||||
| KnownInstanceType::TypeAlias
|
||||
| KnownInstanceType::NotRequired
|
||||
| KnownInstanceType::Concatenate
|
||||
| KnownInstanceType::TypeIs
|
||||
| KnownInstanceType::TypeGuard
|
||||
| KnownInstanceType::Unpack
|
||||
| KnownInstanceType::Required,
|
||||
) => Ok(todo_type!(
|
||||
"Invalid or unsupported `KnownInstanceType` in `Type::to_type_expression`"
|
||||
)),
|
||||
Type::Instance(_) => Ok(todo_type!(
|
||||
|
@ -3562,8 +3595,12 @@ impl<'db> InvalidTypeExpressionError<'db> {
|
|||
enum InvalidTypeExpression<'db> {
|
||||
/// `x: Annotated` is invalid as an annotation
|
||||
BareAnnotated,
|
||||
/// `x: Literal` is invalid as an annotation
|
||||
BareLiteral,
|
||||
/// Some types always require at least one argument when used in a type expression
|
||||
RequiresArguments(Type<'db>),
|
||||
/// Some types always require exactly one argument when used in a type expression
|
||||
RequiresOneArgument(Type<'db>),
|
||||
/// The `Protocol` type is invalid in type expressions
|
||||
ProtocolInTypeExpression,
|
||||
/// The `ClassVar` type qualifier was used in a type expression
|
||||
ClassVarInTypeExpression,
|
||||
/// The `Final` type qualifier was used in a type expression
|
||||
|
@ -3585,8 +3622,17 @@ impl<'db> InvalidTypeExpression<'db> {
|
|||
InvalidTypeExpression::BareAnnotated => f.write_str(
|
||||
"`Annotated` requires at least two arguments when used in an annotation or type expression"
|
||||
),
|
||||
InvalidTypeExpression::BareLiteral => f.write_str(
|
||||
"`Literal` requires at least one argument when used in a type expression"
|
||||
InvalidTypeExpression::RequiresOneArgument(ty) => write!(
|
||||
f,
|
||||
"`{ty}` requires exactly one argument when used in a type expression",
|
||||
ty = ty.display(self.db)),
|
||||
InvalidTypeExpression::RequiresArguments(ty) => write!(
|
||||
f,
|
||||
"`{ty}` requires at least one argument when used in a type expression",
|
||||
ty = ty.display(self.db)
|
||||
),
|
||||
InvalidTypeExpression::ProtocolInTypeExpression => f.write_str(
|
||||
"`typing.Protocol` is not allowed in type expressions"
|
||||
),
|
||||
InvalidTypeExpression::ClassVarInTypeExpression => f.write_str(
|
||||
"Type qualifier `typing.ClassVar` is not allowed in type expressions (only in annotation expressions)"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue