mirror of https://github.com/astral-sh/ruff
[ty] Add type definitions for `Type::SpecialForm`s (#21544)
This commit is contained in:
parent
6e84f4fd7a
commit
c4767f5aa8
|
|
@ -213,6 +213,7 @@ impl<'db> DefinitionsOrTargets<'db> {
|
||||||
| ty_python_semantic::types::TypeDefinition::Function(definition)
|
| ty_python_semantic::types::TypeDefinition::Function(definition)
|
||||||
| ty_python_semantic::types::TypeDefinition::TypeVar(definition)
|
| ty_python_semantic::types::TypeDefinition::TypeVar(definition)
|
||||||
| ty_python_semantic::types::TypeDefinition::TypeAlias(definition)
|
| ty_python_semantic::types::TypeDefinition::TypeAlias(definition)
|
||||||
|
| ty_python_semantic::types::TypeDefinition::SpecialForm(definition)
|
||||||
| ty_python_semantic::types::TypeDefinition::NewType(definition) => {
|
| ty_python_semantic::types::TypeDefinition::NewType(definition) => {
|
||||||
ResolvedDefinition::Definition(definition)
|
ResolvedDefinition::Definition(definition)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,134 @@ mod tests {
|
||||||
");
|
");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn goto_type_of_typing_dot_literal() {
|
||||||
|
let test = cursor_test(
|
||||||
|
r#"
|
||||||
|
from typing import Literal
|
||||||
|
|
||||||
|
a<CURSOR>b = Literal
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_snapshot!(test.goto_type_definition(), @r"
|
||||||
|
info[goto-type-definition]: Type definition
|
||||||
|
--> stdlib/typing.pyi:351:1
|
||||||
|
|
|
||||||
|
349 | Final: _SpecialForm
|
||||||
|
350 |
|
||||||
|
351 | Literal: _SpecialForm
|
||||||
|
| ^^^^^^^
|
||||||
|
352 | TypedDict: _SpecialForm
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main.py:4:1
|
||||||
|
|
|
||||||
|
2 | from typing import Literal
|
||||||
|
3 |
|
||||||
|
4 | ab = Literal
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is a slightly different case to the one above,
|
||||||
|
// since `Any` is a class in typeshed rather than a variable
|
||||||
|
#[test]
|
||||||
|
fn goto_type_of_typing_dot_any() {
|
||||||
|
let test = cursor_test(
|
||||||
|
r#"
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
a<CURSOR>b = Any
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_snapshot!(test.goto_type_definition(), @r#"
|
||||||
|
info[goto-type-definition]: Type definition
|
||||||
|
--> stdlib/typing.pyi:166:7
|
||||||
|
|
|
||||||
|
164 | # from _typeshed import AnnotationForm
|
||||||
|
165 |
|
||||||
|
166 | class Any:
|
||||||
|
| ^^^
|
||||||
|
167 | """Special type indicating an unconstrained type.
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main.py:4:1
|
||||||
|
|
|
||||||
|
2 | from typing import Any
|
||||||
|
3 |
|
||||||
|
4 | ab = Any
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Similarly, `Generic` is a `type[]` type in typeshed
|
||||||
|
#[test]
|
||||||
|
fn goto_type_of_typing_dot_generic() {
|
||||||
|
let test = cursor_test(
|
||||||
|
r#"
|
||||||
|
from typing import Generic
|
||||||
|
|
||||||
|
a<CURSOR>b = Generic
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_snapshot!(test.goto_type_definition(), @r"
|
||||||
|
info[goto-type-definition]: Type definition
|
||||||
|
--> stdlib/typing.pyi:770:1
|
||||||
|
|
|
||||||
|
768 | def __class_getitem__(cls, args: TypeVar | tuple[TypeVar, ...]) -> _Final: ...
|
||||||
|
769 |
|
||||||
|
770 | Generic: type[_Generic]
|
||||||
|
| ^^^^^^^
|
||||||
|
771 |
|
||||||
|
772 | class _ProtocolMeta(ABCMeta):
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main.py:4:1
|
||||||
|
|
|
||||||
|
2 | from typing import Generic
|
||||||
|
3 |
|
||||||
|
4 | ab = Generic
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn goto_type_of_ty_extensions_special_form() {
|
||||||
|
let test = cursor_test(
|
||||||
|
r#"
|
||||||
|
from ty_extensions import AlwaysTruthy
|
||||||
|
|
||||||
|
a<CURSOR>b = AlwaysTruthy
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_snapshot!(test.goto_type_definition(), @r"
|
||||||
|
info[goto-type-definition]: Type definition
|
||||||
|
--> stdlib/ty_extensions.pyi:21:1
|
||||||
|
|
|
||||||
|
19 | # Types
|
||||||
|
20 | Unknown = object()
|
||||||
|
21 | AlwaysTruthy = object()
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
22 | AlwaysFalsy = object()
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main.py:4:1
|
||||||
|
|
|
||||||
|
2 | from ty_extensions import AlwaysTruthy
|
||||||
|
3 |
|
||||||
|
4 | ab = AlwaysTruthy
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn goto_type_of_expression_with_function_type() {
|
fn goto_type_of_expression_with_function_type() {
|
||||||
let test = cursor_test(
|
let test = cursor_test(
|
||||||
|
|
|
||||||
|
|
@ -601,6 +601,25 @@ mod tests {
|
||||||
w[: int] = z
|
w[: int] = z
|
||||||
|
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/typing.pyi:351:1
|
||||||
|
|
|
||||||
|
349 | Final: _SpecialForm
|
||||||
|
350 |
|
||||||
|
351 | Literal: _SpecialForm
|
||||||
|
| ^^^^^^^
|
||||||
|
352 | TypedDict: _SpecialForm
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:6:5
|
||||||
|
|
|
||||||
|
5 | x = 1
|
||||||
|
6 | y[: Literal[1]] = x
|
||||||
|
| ^^^^^^^
|
||||||
|
7 | z[: int] = i(1)
|
||||||
|
8 | w[: int] = z
|
||||||
|
|
|
||||||
|
|
||||||
info[inlay-hint-location]: Inlay Hint Target
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
--> stdlib/builtins.pyi:348:7
|
--> stdlib/builtins.pyi:348:7
|
||||||
|
|
|
|
||||||
|
|
@ -668,6 +687,44 @@ mod tests {
|
||||||
x4[: int], y4[: str] = (x3, y3)
|
x4[: int], y4[: str] = (x3, y3)
|
||||||
|
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/typing.pyi:351:1
|
||||||
|
|
|
||||||
|
349 | Final: _SpecialForm
|
||||||
|
350 |
|
||||||
|
351 | Literal: _SpecialForm
|
||||||
|
| ^^^^^^^
|
||||||
|
352 | TypedDict: _SpecialForm
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:8:6
|
||||||
|
|
|
||||||
|
7 | x1, y1 = (1, 'abc')
|
||||||
|
8 | x2[: Literal[1]], y2[: Literal["abc"]] = (x1, y1)
|
||||||
|
| ^^^^^^^
|
||||||
|
9 | x3[: int], y3[: str] = (i(1), s('abc'))
|
||||||
|
10 | x4[: int], y4[: str] = (x3, y3)
|
||||||
|
|
|
||||||
|
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/typing.pyi:351:1
|
||||||
|
|
|
||||||
|
349 | Final: _SpecialForm
|
||||||
|
350 |
|
||||||
|
351 | Literal: _SpecialForm
|
||||||
|
| ^^^^^^^
|
||||||
|
352 | TypedDict: _SpecialForm
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:8:24
|
||||||
|
|
|
||||||
|
7 | x1, y1 = (1, 'abc')
|
||||||
|
8 | x2[: Literal[1]], y2[: Literal["abc"]] = (x1, y1)
|
||||||
|
| ^^^^^^^
|
||||||
|
9 | x3[: int], y3[: str] = (i(1), s('abc'))
|
||||||
|
10 | x4[: int], y4[: str] = (x3, y3)
|
||||||
|
|
|
||||||
|
|
||||||
info[inlay-hint-location]: Inlay Hint Target
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
--> stdlib/builtins.pyi:348:7
|
--> stdlib/builtins.pyi:348:7
|
||||||
|
|
|
|
||||||
|
|
@ -772,6 +829,44 @@ mod tests {
|
||||||
x4[: int], y4[: str] = x3, y3
|
x4[: int], y4[: str] = x3, y3
|
||||||
|
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/typing.pyi:351:1
|
||||||
|
|
|
||||||
|
349 | Final: _SpecialForm
|
||||||
|
350 |
|
||||||
|
351 | Literal: _SpecialForm
|
||||||
|
| ^^^^^^^
|
||||||
|
352 | TypedDict: _SpecialForm
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:8:6
|
||||||
|
|
|
||||||
|
7 | x1, y1 = 1, 'abc'
|
||||||
|
8 | x2[: Literal[1]], y2[: Literal["abc"]] = x1, y1
|
||||||
|
| ^^^^^^^
|
||||||
|
9 | x3[: int], y3[: str] = i(1), s('abc')
|
||||||
|
10 | x4[: int], y4[: str] = x3, y3
|
||||||
|
|
|
||||||
|
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/typing.pyi:351:1
|
||||||
|
|
|
||||||
|
349 | Final: _SpecialForm
|
||||||
|
350 |
|
||||||
|
351 | Literal: _SpecialForm
|
||||||
|
| ^^^^^^^
|
||||||
|
352 | TypedDict: _SpecialForm
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:8:24
|
||||||
|
|
|
||||||
|
7 | x1, y1 = 1, 'abc'
|
||||||
|
8 | x2[: Literal[1]], y2[: Literal["abc"]] = x1, y1
|
||||||
|
| ^^^^^^^
|
||||||
|
9 | x3[: int], y3[: str] = i(1), s('abc')
|
||||||
|
10 | x4[: int], y4[: str] = x3, y3
|
||||||
|
|
|
||||||
|
|
||||||
info[inlay-hint-location]: Inlay Hint Target
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
--> stdlib/builtins.pyi:348:7
|
--> stdlib/builtins.pyi:348:7
|
||||||
|
|
|
|
||||||
|
|
@ -876,6 +971,44 @@ mod tests {
|
||||||
w[: tuple[int, str]] = z
|
w[: tuple[int, str]] = z
|
||||||
|
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/typing.pyi:351:1
|
||||||
|
|
|
||||||
|
349 | Final: _SpecialForm
|
||||||
|
350 |
|
||||||
|
351 | Literal: _SpecialForm
|
||||||
|
| ^^^^^^^
|
||||||
|
352 | TypedDict: _SpecialForm
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:8:11
|
||||||
|
|
|
||||||
|
7 | x = (1, 'abc')
|
||||||
|
8 | y[: tuple[Literal[1], Literal["abc"]]] = x
|
||||||
|
| ^^^^^^^
|
||||||
|
9 | z[: tuple[int, str]] = (i(1), s('abc'))
|
||||||
|
10 | w[: tuple[int, str]] = z
|
||||||
|
|
|
||||||
|
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/typing.pyi:351:1
|
||||||
|
|
|
||||||
|
349 | Final: _SpecialForm
|
||||||
|
350 |
|
||||||
|
351 | Literal: _SpecialForm
|
||||||
|
| ^^^^^^^
|
||||||
|
352 | TypedDict: _SpecialForm
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:8:23
|
||||||
|
|
|
||||||
|
7 | x = (1, 'abc')
|
||||||
|
8 | y[: tuple[Literal[1], Literal["abc"]]] = x
|
||||||
|
| ^^^^^^^
|
||||||
|
9 | z[: tuple[int, str]] = (i(1), s('abc'))
|
||||||
|
10 | w[: tuple[int, str]] = z
|
||||||
|
|
|
||||||
|
|
||||||
info[inlay-hint-location]: Inlay Hint Target
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
--> stdlib/builtins.pyi:348:7
|
--> stdlib/builtins.pyi:348:7
|
||||||
|
|
|
|
||||||
|
|
@ -978,6 +1111,63 @@ mod tests {
|
||||||
x3[: int], (y3[: str], z3[: int]) = (i(1), (s('abc'), i(2)))
|
x3[: int], (y3[: str], z3[: int]) = (i(1), (s('abc'), i(2)))
|
||||||
x4[: int], (y4[: str], z4[: int]) = (x3, (y3, z3))
|
x4[: int], (y4[: str], z4[: int]) = (x3, (y3, z3))
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/typing.pyi:351:1
|
||||||
|
|
|
||||||
|
349 | Final: _SpecialForm
|
||||||
|
350 |
|
||||||
|
351 | Literal: _SpecialForm
|
||||||
|
| ^^^^^^^
|
||||||
|
352 | TypedDict: _SpecialForm
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:8:6
|
||||||
|
|
|
||||||
|
7 | x1, (y1, z1) = (1, ('abc', 2))
|
||||||
|
8 | x2[: Literal[1]], (y2[: Literal["abc"]], z2[: Literal[2]]) = (x1, (y1, z1))
|
||||||
|
| ^^^^^^^
|
||||||
|
9 | x3[: int], (y3[: str], z3[: int]) = (i(1), (s('abc'), i(2)))
|
||||||
|
10 | x4[: int], (y4[: str], z4[: int]) = (x3, (y3, z3))
|
||||||
|
|
|
||||||
|
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/typing.pyi:351:1
|
||||||
|
|
|
||||||
|
349 | Final: _SpecialForm
|
||||||
|
350 |
|
||||||
|
351 | Literal: _SpecialForm
|
||||||
|
| ^^^^^^^
|
||||||
|
352 | TypedDict: _SpecialForm
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:8:25
|
||||||
|
|
|
||||||
|
7 | x1, (y1, z1) = (1, ('abc', 2))
|
||||||
|
8 | x2[: Literal[1]], (y2[: Literal["abc"]], z2[: Literal[2]]) = (x1, (y1, z1))
|
||||||
|
| ^^^^^^^
|
||||||
|
9 | x3[: int], (y3[: str], z3[: int]) = (i(1), (s('abc'), i(2)))
|
||||||
|
10 | x4[: int], (y4[: str], z4[: int]) = (x3, (y3, z3))
|
||||||
|
|
|
||||||
|
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/typing.pyi:351:1
|
||||||
|
|
|
||||||
|
349 | Final: _SpecialForm
|
||||||
|
350 |
|
||||||
|
351 | Literal: _SpecialForm
|
||||||
|
| ^^^^^^^
|
||||||
|
352 | TypedDict: _SpecialForm
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:8:47
|
||||||
|
|
|
||||||
|
7 | x1, (y1, z1) = (1, ('abc', 2))
|
||||||
|
8 | x2[: Literal[1]], (y2[: Literal["abc"]], z2[: Literal[2]]) = (x1, (y1, z1))
|
||||||
|
| ^^^^^^^
|
||||||
|
9 | x3[: int], (y3[: str], z3[: int]) = (i(1), (s('abc'), i(2)))
|
||||||
|
10 | x4[: int], (y4[: str], z4[: int]) = (x3, (y3, z3))
|
||||||
|
|
|
||||||
|
|
||||||
info[inlay-hint-location]: Inlay Hint Target
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
--> stdlib/builtins.pyi:348:7
|
--> stdlib/builtins.pyi:348:7
|
||||||
|
|
|
|
||||||
|
|
@ -1113,6 +1303,25 @@ mod tests {
|
||||||
z: int = i(1)
|
z: int = i(1)
|
||||||
w[: int] = z
|
w[: int] = z
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/typing.pyi:351:1
|
||||||
|
|
|
||||||
|
349 | Final: _SpecialForm
|
||||||
|
350 |
|
||||||
|
351 | Literal: _SpecialForm
|
||||||
|
| ^^^^^^^
|
||||||
|
352 | TypedDict: _SpecialForm
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:6:5
|
||||||
|
|
|
||||||
|
5 | x: int = 1
|
||||||
|
6 | y[: Literal[1]] = x
|
||||||
|
| ^^^^^^^
|
||||||
|
7 | z: int = i(1)
|
||||||
|
8 | w[: int] = z
|
||||||
|
|
|
||||||
|
|
||||||
info[inlay-hint-location]: Inlay Hint Target
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
--> stdlib/builtins.pyi:348:7
|
--> stdlib/builtins.pyi:348:7
|
||||||
|
|
|
|
||||||
|
|
|
||||||
|
|
@ -1109,7 +1109,7 @@ from typing import List, Dict
|
||||||
# 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 type expression"
|
||||||
InvalidList = List[1]
|
InvalidList = List[1]
|
||||||
|
|
||||||
# error: [invalid-type-form] "`typing.typing.List` requires exactly one argument"
|
# error: [invalid-type-form] "`typing.List` requires exactly one argument"
|
||||||
ListTooManyArgs = List[int, str]
|
ListTooManyArgs = List[int, str]
|
||||||
|
|
||||||
# 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 type expression"
|
||||||
|
|
@ -1118,10 +1118,10 @@ InvalidDict1 = Dict[1, str]
|
||||||
# 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 type expression"
|
||||||
InvalidDict2 = Dict[str, 2]
|
InvalidDict2 = Dict[str, 2]
|
||||||
|
|
||||||
# error: [invalid-type-form] "`typing.typing.Dict` requires exactly two arguments, got 1"
|
# error: [invalid-type-form] "`typing.Dict` requires exactly two arguments, got 1"
|
||||||
DictTooFewArgs = Dict[str]
|
DictTooFewArgs = Dict[str]
|
||||||
|
|
||||||
# error: [invalid-type-form] "`typing.typing.Dict` requires exactly two arguments, got 3"
|
# error: [invalid-type-form] "`typing.Dict` requires exactly two arguments, got 3"
|
||||||
DictTooManyArgs = Dict[str, int, float]
|
DictTooManyArgs = Dict[str, int, float]
|
||||||
|
|
||||||
def _(
|
def _(
|
||||||
|
|
|
||||||
|
|
@ -7503,7 +7503,7 @@ impl<'db> Type<'db> {
|
||||||
name = enum_literal.name(db)
|
name = enum_literal.name(db)
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Type::SpecialForm(special_form) => Type::string_literal(db, special_form.repr()),
|
Type::SpecialForm(special_form) => Type::string_literal(db, &special_form.to_string()),
|
||||||
Type::KnownInstance(known_instance) => Type::StringLiteral(StringLiteralType::new(
|
Type::KnownInstance(known_instance) => Type::StringLiteral(StringLiteralType::new(
|
||||||
db,
|
db,
|
||||||
known_instance.repr(db).to_compact_string(),
|
known_instance.repr(db).to_compact_string(),
|
||||||
|
|
@ -7525,7 +7525,7 @@ impl<'db> Type<'db> {
|
||||||
Type::string_literal(db, &format!("'{}'", literal.value(db).escape_default()))
|
Type::string_literal(db, &format!("'{}'", literal.value(db).escape_default()))
|
||||||
}
|
}
|
||||||
Type::LiteralString => Type::LiteralString,
|
Type::LiteralString => Type::LiteralString,
|
||||||
Type::SpecialForm(special_form) => Type::string_literal(db, special_form.repr()),
|
Type::SpecialForm(special_form) => Type::string_literal(db, &special_form.to_string()),
|
||||||
Type::KnownInstance(known_instance) => Type::StringLiteral(StringLiteralType::new(
|
Type::KnownInstance(known_instance) => Type::StringLiteral(StringLiteralType::new(
|
||||||
db,
|
db,
|
||||||
known_instance.repr(db).to_compact_string(),
|
known_instance.repr(db).to_compact_string(),
|
||||||
|
|
@ -7604,13 +7604,14 @@ impl<'db> Type<'db> {
|
||||||
|
|
||||||
Self::Union(_) | Self::Intersection(_) => None,
|
Self::Union(_) | Self::Intersection(_) => None,
|
||||||
|
|
||||||
|
Self::SpecialForm(special_form) => special_form.definition(db),
|
||||||
|
|
||||||
// These types have no definition
|
// These types have no definition
|
||||||
Self::Dynamic(_)
|
Self::Dynamic(_)
|
||||||
| Self::Never
|
| Self::Never
|
||||||
| Self::Callable(_)
|
| Self::Callable(_)
|
||||||
| Self::AlwaysTruthy
|
| Self::AlwaysTruthy
|
||||||
| Self::AlwaysFalsy
|
| Self::AlwaysFalsy
|
||||||
| Self::SpecialForm(_)
|
|
||||||
| Self::TypeIs(_) => None,
|
| Self::TypeIs(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4828,7 +4828,7 @@ impl KnownClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the module in which we should look up the definition for this class
|
/// Return the module in which we should look up the definition for this class
|
||||||
fn canonical_module(self, db: &dyn Db) -> KnownModule {
|
pub(super) fn canonical_module(self, db: &dyn Db) -> KnownModule {
|
||||||
match self {
|
match self {
|
||||||
Self::Bool
|
Self::Bool
|
||||||
| Self::Object
|
| Self::Object
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ pub enum TypeDefinition<'db> {
|
||||||
TypeVar(Definition<'db>),
|
TypeVar(Definition<'db>),
|
||||||
TypeAlias(Definition<'db>),
|
TypeAlias(Definition<'db>),
|
||||||
NewType(Definition<'db>),
|
NewType(Definition<'db>),
|
||||||
|
SpecialForm(Definition<'db>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeDefinition<'_> {
|
impl TypeDefinition<'_> {
|
||||||
|
|
@ -23,6 +24,7 @@ impl TypeDefinition<'_> {
|
||||||
| Self::Function(definition)
|
| Self::Function(definition)
|
||||||
| Self::TypeVar(definition)
|
| Self::TypeVar(definition)
|
||||||
| Self::TypeAlias(definition)
|
| Self::TypeAlias(definition)
|
||||||
|
| Self::SpecialForm(definition)
|
||||||
| Self::NewType(definition) => {
|
| Self::NewType(definition) => {
|
||||||
let module = parsed_module(db, definition.file(db)).load(db);
|
let module = parsed_module(db, definition.file(db)).load(db);
|
||||||
Some(definition.focus_range(db, &module))
|
Some(definition.focus_range(db, &module))
|
||||||
|
|
@ -41,6 +43,7 @@ impl TypeDefinition<'_> {
|
||||||
| Self::Function(definition)
|
| Self::Function(definition)
|
||||||
| Self::TypeVar(definition)
|
| Self::TypeVar(definition)
|
||||||
| Self::TypeAlias(definition)
|
| Self::TypeAlias(definition)
|
||||||
|
| Self::SpecialForm(definition)
|
||||||
| Self::NewType(definition) => {
|
| Self::NewType(definition) => {
|
||||||
let module = parsed_module(db, definition.file(db)).load(db);
|
let module = parsed_module(db, definition.file(db)).load(db);
|
||||||
Some(definition.full_range(db, &module))
|
Some(definition.full_range(db, &module))
|
||||||
|
|
|
||||||
|
|
@ -10872,7 +10872,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
|
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
|
||||||
builder.into_diagnostic(format_args!(
|
builder.into_diagnostic(format_args!(
|
||||||
"`typing.{}` requires exactly one argument",
|
"`typing.{}` requires exactly one argument",
|
||||||
special_form.repr()
|
special_form.name()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Type::unknown()
|
Type::unknown()
|
||||||
|
|
@ -10907,7 +10907,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
{
|
{
|
||||||
builder.into_diagnostic(format_args!(
|
builder.into_diagnostic(format_args!(
|
||||||
"`typing.{}` requires exactly two arguments, got {}",
|
"`typing.{}` requires exactly two arguments, got {}",
|
||||||
special_form.repr(),
|
special_form.name(),
|
||||||
arguments.len()
|
arguments.len()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
@ -10931,7 +10931,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
|
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
|
||||||
builder.into_diagnostic(format_args!(
|
builder.into_diagnostic(format_args!(
|
||||||
"`typing.{}` requires exactly two arguments, got 1",
|
"`typing.{}` requires exactly two arguments, got 1",
|
||||||
special_form.repr()
|
special_form.name()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1318,10 +1318,9 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
self.infer_type_expression(arguments_slice);
|
self.infer_type_expression(arguments_slice);
|
||||||
|
|
||||||
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
|
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, subscript) {
|
||||||
let diag = builder.into_diagnostic(format_args!(
|
let diag = builder.into_diagnostic(
|
||||||
"Special form `{}` expected exactly one type parameter",
|
"Special form `typing.TypeIs` expected exactly one type parameter",
|
||||||
special_form.repr()
|
);
|
||||||
));
|
|
||||||
diagnostic::add_type_expression_reference_link(diag);
|
diagnostic::add_type_expression_reference_link(diag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,10 @@
|
||||||
use super::{ClassType, Type, class::KnownClass};
|
use super::{ClassType, Type, class::KnownClass};
|
||||||
use crate::db::Db;
|
use crate::db::Db;
|
||||||
use crate::module_resolver::{KnownModule, file_to_module};
|
use crate::module_resolver::{KnownModule, file_to_module};
|
||||||
|
use crate::resolve_module;
|
||||||
|
use crate::semantic_index::place::ScopedPlaceId;
|
||||||
|
use crate::semantic_index::{FileScopeId, place_table, use_def_map};
|
||||||
|
use crate::types::TypeDefinition;
|
||||||
use ruff_db::files::File;
|
use ruff_db::files::File;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
|
@ -435,59 +439,132 @@ impl SpecialFormType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the repr of the symbol at runtime
|
/// Return the name of the symbol at runtime
|
||||||
pub(super) const fn repr(self) -> &'static str {
|
pub(super) const fn name(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
SpecialFormType::Any => "typing.Any",
|
SpecialFormType::Any => "Any",
|
||||||
SpecialFormType::Annotated => "typing.Annotated",
|
SpecialFormType::Annotated => "Annotated",
|
||||||
SpecialFormType::Literal => "typing.Literal",
|
SpecialFormType::Literal => "Literal",
|
||||||
SpecialFormType::LiteralString => "typing.LiteralString",
|
SpecialFormType::LiteralString => "LiteralString",
|
||||||
SpecialFormType::Optional => "typing.Optional",
|
SpecialFormType::Optional => "Optional",
|
||||||
SpecialFormType::Union => "typing.Union",
|
SpecialFormType::Union => "Union",
|
||||||
SpecialFormType::NoReturn => "typing.NoReturn",
|
SpecialFormType::NoReturn => "NoReturn",
|
||||||
SpecialFormType::Never => "typing.Never",
|
SpecialFormType::Never => "Never",
|
||||||
SpecialFormType::Tuple => "typing.Tuple",
|
SpecialFormType::Tuple => "Tuple",
|
||||||
SpecialFormType::Type => "typing.Type",
|
SpecialFormType::Type => "Type",
|
||||||
SpecialFormType::TypingSelf => "typing.Self",
|
SpecialFormType::TypingSelf => "Self",
|
||||||
SpecialFormType::Final => "typing.Final",
|
SpecialFormType::Final => "Final",
|
||||||
SpecialFormType::ClassVar => "typing.ClassVar",
|
SpecialFormType::ClassVar => "ClassVar",
|
||||||
SpecialFormType::Callable => "typing.Callable",
|
SpecialFormType::Callable => "Callable",
|
||||||
SpecialFormType::Concatenate => "typing.Concatenate",
|
SpecialFormType::Concatenate => "Concatenate",
|
||||||
SpecialFormType::Unpack => "typing.Unpack",
|
SpecialFormType::Unpack => "Unpack",
|
||||||
SpecialFormType::Required => "typing.Required",
|
SpecialFormType::Required => "Required",
|
||||||
SpecialFormType::NotRequired => "typing.NotRequired",
|
SpecialFormType::NotRequired => "NotRequired",
|
||||||
SpecialFormType::TypeAlias => "typing.TypeAlias",
|
SpecialFormType::TypeAlias => "TypeAlias",
|
||||||
SpecialFormType::TypeGuard => "typing.TypeGuard",
|
SpecialFormType::TypeGuard => "TypeGuard",
|
||||||
SpecialFormType::TypedDict => "typing.TypedDict",
|
SpecialFormType::TypedDict => "TypedDict",
|
||||||
SpecialFormType::TypeIs => "typing.TypeIs",
|
SpecialFormType::TypeIs => "TypeIs",
|
||||||
SpecialFormType::List => "typing.List",
|
SpecialFormType::List => "List",
|
||||||
SpecialFormType::Dict => "typing.Dict",
|
SpecialFormType::Dict => "Dict",
|
||||||
SpecialFormType::DefaultDict => "typing.DefaultDict",
|
SpecialFormType::DefaultDict => "DefaultDict",
|
||||||
SpecialFormType::Set => "typing.Set",
|
SpecialFormType::Set => "Set",
|
||||||
SpecialFormType::FrozenSet => "typing.FrozenSet",
|
SpecialFormType::FrozenSet => "FrozenSet",
|
||||||
SpecialFormType::Counter => "typing.Counter",
|
SpecialFormType::Counter => "Counter",
|
||||||
SpecialFormType::Deque => "typing.Deque",
|
SpecialFormType::Deque => "Deque",
|
||||||
SpecialFormType::ChainMap => "typing.ChainMap",
|
SpecialFormType::ChainMap => "ChainMap",
|
||||||
SpecialFormType::OrderedDict => "typing.OrderedDict",
|
SpecialFormType::OrderedDict => "OrderedDict",
|
||||||
SpecialFormType::ReadOnly => "typing.ReadOnly",
|
SpecialFormType::ReadOnly => "ReadOnly",
|
||||||
SpecialFormType::Unknown => "ty_extensions.Unknown",
|
SpecialFormType::Unknown => "Unknown",
|
||||||
SpecialFormType::AlwaysTruthy => "ty_extensions.AlwaysTruthy",
|
SpecialFormType::AlwaysTruthy => "AlwaysTruthy",
|
||||||
SpecialFormType::AlwaysFalsy => "ty_extensions.AlwaysFalsy",
|
SpecialFormType::AlwaysFalsy => "AlwaysFalsy",
|
||||||
SpecialFormType::Not => "ty_extensions.Not",
|
SpecialFormType::Not => "Not",
|
||||||
SpecialFormType::Intersection => "ty_extensions.Intersection",
|
SpecialFormType::Intersection => "Intersection",
|
||||||
SpecialFormType::TypeOf => "ty_extensions.TypeOf",
|
SpecialFormType::TypeOf => "TypeOf",
|
||||||
SpecialFormType::CallableTypeOf => "ty_extensions.CallableTypeOf",
|
SpecialFormType::CallableTypeOf => "CallableTypeOf",
|
||||||
SpecialFormType::Top => "ty_extensions.Top",
|
SpecialFormType::Top => "Top",
|
||||||
SpecialFormType::Bottom => "ty_extensions.Bottom",
|
SpecialFormType::Bottom => "Bottom",
|
||||||
SpecialFormType::Protocol => "typing.Protocol",
|
SpecialFormType::Protocol => "Protocol",
|
||||||
SpecialFormType::Generic => "typing.Generic",
|
SpecialFormType::Generic => "Generic",
|
||||||
SpecialFormType::NamedTuple => "typing.NamedTuple",
|
SpecialFormType::NamedTuple => "NamedTuple",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the module(s) in which this special form could be defined
|
||||||
|
fn definition_modules(self) -> &'static [KnownModule] {
|
||||||
|
match self {
|
||||||
|
SpecialFormType::Any
|
||||||
|
| SpecialFormType::Annotated
|
||||||
|
| SpecialFormType::Literal
|
||||||
|
| SpecialFormType::LiteralString
|
||||||
|
| SpecialFormType::Optional
|
||||||
|
| SpecialFormType::Union
|
||||||
|
| SpecialFormType::NoReturn
|
||||||
|
| SpecialFormType::Never
|
||||||
|
| SpecialFormType::Tuple
|
||||||
|
| SpecialFormType::Type
|
||||||
|
| SpecialFormType::TypingSelf
|
||||||
|
| SpecialFormType::Final
|
||||||
|
| SpecialFormType::ClassVar
|
||||||
|
| SpecialFormType::Callable
|
||||||
|
| SpecialFormType::Concatenate
|
||||||
|
| SpecialFormType::Unpack
|
||||||
|
| SpecialFormType::Required
|
||||||
|
| SpecialFormType::NotRequired
|
||||||
|
| SpecialFormType::TypeAlias
|
||||||
|
| SpecialFormType::TypeGuard
|
||||||
|
| SpecialFormType::TypedDict
|
||||||
|
| SpecialFormType::TypeIs
|
||||||
|
| SpecialFormType::ReadOnly
|
||||||
|
| SpecialFormType::Protocol
|
||||||
|
| SpecialFormType::Generic
|
||||||
|
| SpecialFormType::NamedTuple
|
||||||
|
| SpecialFormType::List
|
||||||
|
| SpecialFormType::Dict
|
||||||
|
| SpecialFormType::DefaultDict
|
||||||
|
| SpecialFormType::Set
|
||||||
|
| SpecialFormType::FrozenSet
|
||||||
|
| SpecialFormType::Counter
|
||||||
|
| SpecialFormType::Deque
|
||||||
|
| SpecialFormType::ChainMap
|
||||||
|
| SpecialFormType::OrderedDict => &[KnownModule::Typing, KnownModule::TypingExtensions],
|
||||||
|
|
||||||
|
SpecialFormType::Unknown
|
||||||
|
| SpecialFormType::AlwaysTruthy
|
||||||
|
| SpecialFormType::AlwaysFalsy
|
||||||
|
| SpecialFormType::Not
|
||||||
|
| SpecialFormType::Intersection
|
||||||
|
| SpecialFormType::TypeOf
|
||||||
|
| SpecialFormType::CallableTypeOf
|
||||||
|
| SpecialFormType::Top
|
||||||
|
| SpecialFormType::Bottom => &[KnownModule::TyExtensions],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn definition(self, db: &dyn Db) -> Option<TypeDefinition<'_>> {
|
||||||
|
self.definition_modules()
|
||||||
|
.iter()
|
||||||
|
.find_map(|module| {
|
||||||
|
let file = resolve_module(db, &module.name())?.file(db)?;
|
||||||
|
let scope = FileScopeId::global().to_scope_id(db, file);
|
||||||
|
let symbol_id = place_table(db, scope).symbol_id(self.name())?;
|
||||||
|
|
||||||
|
use_def_map(db, scope)
|
||||||
|
.end_of_scope_bindings(ScopedPlaceId::Symbol(symbol_id))
|
||||||
|
.next()?
|
||||||
|
.binding
|
||||||
|
.definition()
|
||||||
|
})
|
||||||
|
.map(TypeDefinition::SpecialForm)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for SpecialFormType {
|
impl std::fmt::Display for SpecialFormType {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.write_str(self.repr())
|
write!(
|
||||||
|
f,
|
||||||
|
"{}.{}",
|
||||||
|
self.definition_modules()[0].as_str(),
|
||||||
|
self.name()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue