mirror of https://github.com/astral-sh/ruff
[ty] Enable even more goto-definition on inlay hints (#21950)
## Summary Working on py-fuzzer recently (AKA, a Python project!) reminded me how cool our "inlay hint goto-definition feature" is. So this PR adds a bunch more of that! I also made a couple of other minor changes to type display. For example, in the playground, this snippet: ```py def f(): ... reveal_type(f.__get__) ``` currently leads to this diagnostic: ``` Revealed type: `<method-wrapper `__get__` of `f`>` (revealed-type) [Ln 2, Col 13] ``` But the fact that we have backticks both around the type display and inside the type display isn't _great_ there. This PR changes it to ``` Revealed type: `<method-wrapper '__get__' of function 'f'>` (revealed-type) [Ln 2, Col 13] ``` which avoids the nested-backticks issue in diagnostics, and is more similar to our display for various other `Type` variants such as class-literal types (`<class 'Foo'>`, etc., not ``<class `Foo`>``). ## Test Plan inlay snapshots added; mdtests updated
This commit is contained in:
parent
dec4154c8a
commit
a722df6a73
|
|
@ -6017,9 +6017,9 @@ mod tests {
|
||||||
fn test_function_signature_inlay_hint() {
|
fn test_function_signature_inlay_hint() {
|
||||||
let mut test = inlay_hint_test(
|
let mut test = inlay_hint_test(
|
||||||
"
|
"
|
||||||
def foo(x: int, *y: bool, z: str | int | list[str]): ...
|
def foo(x: int, *y: bool, z: str | int | list[str]): ...
|
||||||
|
|
||||||
a = foo",
|
a = foo",
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_snapshot!(test.inlay_hints(), @r#"
|
assert_snapshot!(test.inlay_hints(), @r#"
|
||||||
|
|
@ -6158,18 +6158,35 @@ mod tests {
|
||||||
fn test_module_inlay_hint() {
|
fn test_module_inlay_hint() {
|
||||||
let mut test = inlay_hint_test(
|
let mut test = inlay_hint_test(
|
||||||
"
|
"
|
||||||
import foo
|
import foo
|
||||||
|
|
||||||
a = foo",
|
a = foo",
|
||||||
);
|
);
|
||||||
|
|
||||||
test.with_extra_file("foo.py", "'''Foo module'''");
|
test.with_extra_file("foo.py", "'''Foo module'''");
|
||||||
|
|
||||||
assert_snapshot!(test.inlay_hints(), @r"
|
assert_snapshot!(test.inlay_hints(), @r#"
|
||||||
import foo
|
import foo
|
||||||
|
|
||||||
a[: <module 'foo'>] = foo
|
a[: <module 'foo'>] = foo
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/types.pyi:423:7
|
||||||
|
|
|
||||||
|
422 | @disjoint_base
|
||||||
|
423 | class ModuleType:
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
424 | """Create a module object.
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:4:6
|
||||||
|
|
|
||||||
|
2 | import foo
|
||||||
|
3 |
|
||||||
|
4 | a[: <module 'foo'>] = foo
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
|
||||||
info[inlay-hint-location]: Inlay Hint Target
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
--> foo.py:1:1
|
--> foo.py:1:1
|
||||||
|
|
|
|
||||||
|
|
@ -6177,32 +6194,531 @@ mod tests {
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
info: Source
|
info: Source
|
||||||
--> main2.py:4:5
|
--> main2.py:4:14
|
||||||
|
|
|
|
||||||
2 | import foo
|
2 | import foo
|
||||||
3 |
|
3 |
|
||||||
4 | a[: <module 'foo'>] = foo
|
4 | a[: <module 'foo'>] = foo
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^
|
||||||
|
|
|
|
||||||
");
|
"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_literal_type_alias_inlay_hint() {
|
fn test_literal_type_alias_inlay_hint() {
|
||||||
let mut test = inlay_hint_test(
|
let mut test = inlay_hint_test(
|
||||||
"
|
"
|
||||||
from typing import Literal
|
from typing import Literal
|
||||||
|
|
||||||
a = Literal['a', 'b', 'c']",
|
a = Literal['a', 'b', 'c']",
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_snapshot!(test.inlay_hints(), @r#"
|
assert_snapshot!(test.inlay_hints(), @r#"
|
||||||
from typing import Literal
|
from typing import Literal
|
||||||
|
|
||||||
a[: <special form 'Literal["a", "b", "c"]'>] = Literal['a', 'b', 'c']
|
a[: <special form 'Literal["a", "b", "c"]'>] = Literal['a', 'b', 'c']
|
||||||
|
---------------------------------------------
|
||||||
|
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:4:20
|
||||||
|
|
|
||||||
|
2 | from typing import Literal
|
||||||
|
3 |
|
||||||
|
4 | a[: <special form 'Literal["a", "b", "c"]'>] = Literal['a', 'b', 'c']
|
||||||
|
| ^^^^^^^
|
||||||
|
|
|
||||||
|
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/builtins.pyi:915:7
|
||||||
|
|
|
||||||
|
914 | @disjoint_base
|
||||||
|
915 | class str(Sequence[str]):
|
||||||
|
| ^^^
|
||||||
|
916 | """str(object='') -> str
|
||||||
|
917 | str(bytes_or_buffer[, encoding[, errors]]) -> str
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:4:28
|
||||||
|
|
|
||||||
|
2 | from typing import Literal
|
||||||
|
3 |
|
||||||
|
4 | a[: <special form 'Literal["a", "b", "c"]'>] = Literal['a', 'b', 'c']
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/builtins.pyi:915:7
|
||||||
|
|
|
||||||
|
914 | @disjoint_base
|
||||||
|
915 | class str(Sequence[str]):
|
||||||
|
| ^^^
|
||||||
|
916 | """str(object='') -> str
|
||||||
|
917 | str(bytes_or_buffer[, encoding[, errors]]) -> str
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:4:33
|
||||||
|
|
|
||||||
|
2 | from typing import Literal
|
||||||
|
3 |
|
||||||
|
4 | a[: <special form 'Literal["a", "b", "c"]'>] = Literal['a', 'b', 'c']
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/builtins.pyi:915:7
|
||||||
|
|
|
||||||
|
914 | @disjoint_base
|
||||||
|
915 | class str(Sequence[str]):
|
||||||
|
| ^^^
|
||||||
|
916 | """str(object='') -> str
|
||||||
|
917 | str(bytes_or_buffer[, encoding[, errors]]) -> str
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:4:38
|
||||||
|
|
|
||||||
|
2 | from typing import Literal
|
||||||
|
3 |
|
||||||
|
4 | a[: <special form 'Literal["a", "b", "c"]'>] = Literal['a', 'b', 'c']
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
"#);
|
"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_wrapper_descriptor_inlay_hint() {
|
||||||
|
let mut test = inlay_hint_test(
|
||||||
|
"
|
||||||
|
from types import FunctionType
|
||||||
|
|
||||||
|
a = FunctionType.__get__",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_snapshot!(test.inlay_hints(), @r#"
|
||||||
|
from types import FunctionType
|
||||||
|
|
||||||
|
a[: <wrapper-descriptor '__get__' of 'function' objects>] = FunctionType.__get__
|
||||||
|
---------------------------------------------
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/types.pyi:670:7
|
||||||
|
|
|
||||||
|
669 | @final
|
||||||
|
670 | class WrapperDescriptorType:
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
671 | @property
|
||||||
|
672 | def __name__(self) -> str: ...
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:4:6
|
||||||
|
|
|
||||||
|
2 | from types import FunctionType
|
||||||
|
3 |
|
||||||
|
4 | a[: <wrapper-descriptor '__get__' of 'function' objects>] = FunctionType.__get__
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/types.pyi:77:7
|
||||||
|
|
|
||||||
|
75 | # Make sure this class definition stays roughly in line with `builtins.function`
|
||||||
|
76 | @final
|
||||||
|
77 | class FunctionType:
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
78 | """Create a function object.
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:4:39
|
||||||
|
|
|
||||||
|
2 | from types import FunctionType
|
||||||
|
3 |
|
||||||
|
4 | a[: <wrapper-descriptor '__get__' of 'function' objects>] = FunctionType.__get__
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_method_wrapper_inlay_hint() {
|
||||||
|
let mut test = inlay_hint_test(
|
||||||
|
"
|
||||||
|
def f(): ...
|
||||||
|
|
||||||
|
a = f.__call__",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_snapshot!(test.inlay_hints(), @r#"
|
||||||
|
def f(): ...
|
||||||
|
|
||||||
|
a[: <method-wrapper '__call__' of function 'f'>] = f.__call__
|
||||||
|
---------------------------------------------
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/types.pyi:684:7
|
||||||
|
|
|
||||||
|
683 | @final
|
||||||
|
684 | class MethodWrapperType:
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
685 | @property
|
||||||
|
686 | def __self__(self) -> object: ...
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:4:6
|
||||||
|
|
|
||||||
|
2 | def f(): ...
|
||||||
|
3 |
|
||||||
|
4 | a[: <method-wrapper '__call__' of function 'f'>] = f.__call__
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/types.pyi:134:9
|
||||||
|
|
|
||||||
|
132 | ) -> Self: ...
|
||||||
|
133 |
|
||||||
|
134 | def __call__(self, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
| ^^^^^^^^
|
||||||
|
135 | """Call self as a function."""
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:4:22
|
||||||
|
|
|
||||||
|
2 | def f(): ...
|
||||||
|
3 |
|
||||||
|
4 | a[: <method-wrapper '__call__' of function 'f'>] = f.__call__
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/types.pyi:77:7
|
||||||
|
|
|
||||||
|
75 | # Make sure this class definition stays roughly in line with `builtins.function`
|
||||||
|
76 | @final
|
||||||
|
77 | class FunctionType:
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
78 | """Create a function object.
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:4:35
|
||||||
|
|
|
||||||
|
2 | def f(): ...
|
||||||
|
3 |
|
||||||
|
4 | a[: <method-wrapper '__call__' of function 'f'>] = f.__call__
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> main.py:2:5
|
||||||
|
|
|
||||||
|
2 | def f(): ...
|
||||||
|
| ^
|
||||||
|
3 |
|
||||||
|
4 | a = f.__call__
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:4:45
|
||||||
|
|
|
||||||
|
2 | def f(): ...
|
||||||
|
3 |
|
||||||
|
4 | a[: <method-wrapper '__call__' of function 'f'>] = f.__call__
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_newtype_inlay_hint() {
|
||||||
|
let mut test = inlay_hint_test(
|
||||||
|
"
|
||||||
|
from typing import NewType
|
||||||
|
|
||||||
|
N = NewType('N', str)
|
||||||
|
|
||||||
|
Y = N",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_snapshot!(test.inlay_hints(), @r#"
|
||||||
|
from typing import NewType
|
||||||
|
|
||||||
|
N[: <NewType pseudo-class 'N'>] = NewType([name=]'N', [tp=]str)
|
||||||
|
|
||||||
|
Y[: <NewType pseudo-class 'N'>] = N
|
||||||
|
---------------------------------------------
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/typing.pyi:615:11
|
||||||
|
|
|
||||||
|
613 | TypeGuard: _SpecialForm
|
||||||
|
614 |
|
||||||
|
615 | class NewType:
|
||||||
|
| ^^^^^^^
|
||||||
|
616 | """NewType creates simple unique types with almost zero runtime overhead.
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:4:6
|
||||||
|
|
|
||||||
|
2 | from typing import NewType
|
||||||
|
3 |
|
||||||
|
4 | N[: <NewType pseudo-class 'N'>] = NewType([name=]'N', [tp=]str)
|
||||||
|
| ^^^^^^^
|
||||||
|
5 |
|
||||||
|
6 | Y[: <NewType pseudo-class 'N'>] = N
|
||||||
|
|
|
||||||
|
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> main.py:4:1
|
||||||
|
|
|
||||||
|
2 | from typing import NewType
|
||||||
|
3 |
|
||||||
|
4 | N = NewType('N', str)
|
||||||
|
| ^
|
||||||
|
5 |
|
||||||
|
6 | Y = N
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:4:28
|
||||||
|
|
|
||||||
|
2 | from typing import NewType
|
||||||
|
3 |
|
||||||
|
4 | N[: <NewType pseudo-class 'N'>] = NewType([name=]'N', [tp=]str)
|
||||||
|
| ^
|
||||||
|
5 |
|
||||||
|
6 | Y[: <NewType pseudo-class 'N'>] = N
|
||||||
|
|
|
||||||
|
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/typing.pyi:637:28
|
||||||
|
|
|
||||||
|
635 | """
|
||||||
|
636 |
|
||||||
|
637 | def __init__(self, name: str, tp: Any) -> None: ... # AnnotationForm
|
||||||
|
| ^^^^
|
||||||
|
638 | if sys.version_info >= (3, 11):
|
||||||
|
639 | @staticmethod
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:4:44
|
||||||
|
|
|
||||||
|
2 | from typing import NewType
|
||||||
|
3 |
|
||||||
|
4 | N[: <NewType pseudo-class 'N'>] = NewType([name=]'N', [tp=]str)
|
||||||
|
| ^^^^
|
||||||
|
5 |
|
||||||
|
6 | Y[: <NewType pseudo-class 'N'>] = N
|
||||||
|
|
|
||||||
|
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/typing.pyi:637:39
|
||||||
|
|
|
||||||
|
635 | """
|
||||||
|
636 |
|
||||||
|
637 | def __init__(self, name: str, tp: Any) -> None: ... # AnnotationForm
|
||||||
|
| ^^
|
||||||
|
638 | if sys.version_info >= (3, 11):
|
||||||
|
639 | @staticmethod
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:4:56
|
||||||
|
|
|
||||||
|
2 | from typing import NewType
|
||||||
|
3 |
|
||||||
|
4 | N[: <NewType pseudo-class 'N'>] = NewType([name=]'N', [tp=]str)
|
||||||
|
| ^^
|
||||||
|
5 |
|
||||||
|
6 | Y[: <NewType pseudo-class 'N'>] = N
|
||||||
|
|
|
||||||
|
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/typing.pyi:615:11
|
||||||
|
|
|
||||||
|
613 | TypeGuard: _SpecialForm
|
||||||
|
614 |
|
||||||
|
615 | class NewType:
|
||||||
|
| ^^^^^^^
|
||||||
|
616 | """NewType creates simple unique types with almost zero runtime overhead.
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:6:6
|
||||||
|
|
|
||||||
|
4 | N[: <NewType pseudo-class 'N'>] = NewType([name=]'N', [tp=]str)
|
||||||
|
5 |
|
||||||
|
6 | Y[: <NewType pseudo-class 'N'>] = N
|
||||||
|
| ^^^^^^^
|
||||||
|
|
|
||||||
|
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> main.py:4:1
|
||||||
|
|
|
||||||
|
2 | from typing import NewType
|
||||||
|
3 |
|
||||||
|
4 | N = NewType('N', str)
|
||||||
|
| ^
|
||||||
|
5 |
|
||||||
|
6 | Y = N
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:6:28
|
||||||
|
|
|
||||||
|
4 | N[: <NewType pseudo-class 'N'>] = NewType([name=]'N', [tp=]str)
|
||||||
|
5 |
|
||||||
|
6 | Y[: <NewType pseudo-class 'N'>] = N
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_meta_typevar_inlay_hint() {
|
||||||
|
let mut test = inlay_hint_test(
|
||||||
|
"
|
||||||
|
def f[T](x: type[T]):
|
||||||
|
y = x",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_snapshot!(test.inlay_hints(), @r#"
|
||||||
|
def f[T](x: type[T]):
|
||||||
|
y[: type[T@f]] = x
|
||||||
|
---------------------------------------------
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/builtins.pyi:247:7
|
||||||
|
|
|
||||||
|
246 | @disjoint_base
|
||||||
|
247 | class type:
|
||||||
|
| ^^^^
|
||||||
|
248 | """type(object) -> the object's type
|
||||||
|
249 | type(name, bases, dict, **kwds) -> a new type
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:3:9
|
||||||
|
|
|
||||||
|
2 | def f[T](x: type[T]):
|
||||||
|
3 | y[: type[T@f]] = x
|
||||||
|
| ^^^^
|
||||||
|
|
|
||||||
|
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> main.py:2:7
|
||||||
|
|
|
||||||
|
2 | def f[T](x: type[T]):
|
||||||
|
| ^
|
||||||
|
3 | y = x
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:3:14
|
||||||
|
|
|
||||||
|
2 | def f[T](x: type[T]):
|
||||||
|
3 | y[: type[T@f]] = x
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
|
||||||
|
---------------------------------------------
|
||||||
|
info[inlay-hint-edit]: File after edits
|
||||||
|
info: Source
|
||||||
|
|
||||||
|
def f[T](x: type[T]):
|
||||||
|
y: type[T@f] = x
|
||||||
|
"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_subscripted_protocol_inlay_hint() {
|
||||||
|
let mut test = inlay_hint_test(
|
||||||
|
"
|
||||||
|
from typing import Protocol, TypeVar
|
||||||
|
T = TypeVar('T')
|
||||||
|
Strange = Protocol[T]",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_snapshot!(test.inlay_hints(), @r"
|
||||||
|
from typing import Protocol, TypeVar
|
||||||
|
T[: typing.TypeVar] = TypeVar([name=]'T')
|
||||||
|
Strange[: <special form 'typing.Protocol[T]'>] = Protocol[T]
|
||||||
|
---------------------------------------------
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> main.py:3:1
|
||||||
|
|
|
||||||
|
2 | from typing import Protocol, TypeVar
|
||||||
|
3 | T = TypeVar('T')
|
||||||
|
| ^
|
||||||
|
4 | Strange = Protocol[T]
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:3:5
|
||||||
|
|
|
||||||
|
2 | from typing import Protocol, TypeVar
|
||||||
|
3 | T[: typing.TypeVar] = TypeVar([name=]'T')
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
4 | Strange[: <special form 'typing.Protocol[T]'>] = Protocol[T]
|
||||||
|
|
|
||||||
|
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/typing.pyi:276:13
|
||||||
|
|
|
||||||
|
274 | def __new__(
|
||||||
|
275 | cls,
|
||||||
|
276 | name: str,
|
||||||
|
| ^^^^
|
||||||
|
277 | *constraints: Any, # AnnotationForm
|
||||||
|
278 | bound: Any | None = None, # AnnotationForm
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:3:32
|
||||||
|
|
|
||||||
|
2 | from typing import Protocol, TypeVar
|
||||||
|
3 | T[: typing.TypeVar] = TypeVar([name=]'T')
|
||||||
|
| ^^^^
|
||||||
|
4 | Strange[: <special form 'typing.Protocol[T]'>] = Protocol[T]
|
||||||
|
|
|
||||||
|
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> stdlib/typing.pyi:341:1
|
||||||
|
|
|
||||||
|
340 | Union: _SpecialForm
|
||||||
|
341 | Protocol: _SpecialForm
|
||||||
|
| ^^^^^^^^
|
||||||
|
342 | Callable: _SpecialForm
|
||||||
|
343 | Type: _SpecialForm
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:4:26
|
||||||
|
|
|
||||||
|
2 | from typing import Protocol, TypeVar
|
||||||
|
3 | T[: typing.TypeVar] = TypeVar([name=]'T')
|
||||||
|
4 | Strange[: <special form 'typing.Protocol[T]'>] = Protocol[T]
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
|
||||||
|
info[inlay-hint-location]: Inlay Hint Target
|
||||||
|
--> main.py:3:1
|
||||||
|
|
|
||||||
|
2 | from typing import Protocol, TypeVar
|
||||||
|
3 | T = TypeVar('T')
|
||||||
|
| ^
|
||||||
|
4 | Strange = Protocol[T]
|
||||||
|
|
|
||||||
|
info: Source
|
||||||
|
--> main2.py:4:42
|
||||||
|
|
|
||||||
|
2 | from typing import Protocol, TypeVar
|
||||||
|
3 | T[: typing.TypeVar] = TypeVar([name=]'T')
|
||||||
|
4 | Strange[: <special form 'typing.Protocol[T]'>] = Protocol[T]
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
|
||||||
|
---------------------------------------------
|
||||||
|
info[inlay-hint-edit]: File after edits
|
||||||
|
info: Source
|
||||||
|
|
||||||
|
from typing import Protocol, TypeVar
|
||||||
|
T: typing.TypeVar = TypeVar('T')
|
||||||
|
Strange = Protocol[T]
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
struct InlayHintLocationDiagnostic {
|
struct InlayHintLocationDiagnostic {
|
||||||
source: FileRange,
|
source: FileRange,
|
||||||
target: FileRange,
|
target: FileRange,
|
||||||
|
|
|
||||||
|
|
@ -2162,8 +2162,8 @@ Some attributes are special-cased, however:
|
||||||
import types
|
import types
|
||||||
from ty_extensions import static_assert, TypeOf, is_subtype_of
|
from ty_extensions import static_assert, TypeOf, is_subtype_of
|
||||||
|
|
||||||
reveal_type(f.__get__) # revealed: <method-wrapper `__get__` of `f`>
|
reveal_type(f.__get__) # revealed: <method-wrapper '__get__' of function 'f'>
|
||||||
reveal_type(f.__call__) # revealed: <method-wrapper `__call__` of `f`>
|
reveal_type(f.__call__) # revealed: <method-wrapper '__call__' of function 'f'>
|
||||||
static_assert(is_subtype_of(TypeOf[f.__get__], types.MethodWrapperType))
|
static_assert(is_subtype_of(TypeOf[f.__get__], types.MethodWrapperType))
|
||||||
static_assert(is_subtype_of(TypeOf[f.__call__], types.MethodWrapperType))
|
static_assert(is_subtype_of(TypeOf[f.__call__], types.MethodWrapperType))
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,8 @@ from inspect import getattr_static
|
||||||
|
|
||||||
reveal_type(getattr_static(C, "f")) # revealed: def f(self, x: int) -> str
|
reveal_type(getattr_static(C, "f")) # revealed: def f(self, x: int) -> str
|
||||||
|
|
||||||
reveal_type(getattr_static(C, "f").__get__) # revealed: <method-wrapper `__get__` of `f`>
|
# revealed: <method-wrapper '__get__' of function 'f'>
|
||||||
|
reveal_type(getattr_static(C, "f").__get__)
|
||||||
|
|
||||||
reveal_type(getattr_static(C, "f").__get__(None, C)) # revealed: def f(self, x: int) -> str
|
reveal_type(getattr_static(C, "f").__get__(None, C)) # revealed: def f(self, x: int) -> str
|
||||||
reveal_type(getattr_static(C, "f").__get__(C(), C)) # revealed: bound method C.f(x: int) -> str
|
reveal_type(getattr_static(C, "f").__get__(C(), C)) # revealed: bound method C.f(x: int) -> str
|
||||||
|
|
@ -258,7 +259,7 @@ class C:
|
||||||
|
|
||||||
method_wrapper = getattr_static(C, "f").__get__
|
method_wrapper = getattr_static(C, "f").__get__
|
||||||
|
|
||||||
reveal_type(method_wrapper) # revealed: <method-wrapper `__get__` of `f`>
|
reveal_type(method_wrapper) # revealed: <method-wrapper '__get__' of function 'f'>
|
||||||
|
|
||||||
# All of these are fine:
|
# All of these are fine:
|
||||||
method_wrapper(C(), C)
|
method_wrapper(C(), C)
|
||||||
|
|
@ -414,7 +415,8 @@ class C:
|
||||||
def f(cls): ...
|
def f(cls): ...
|
||||||
|
|
||||||
reveal_type(getattr_static(C, "f")) # revealed: def f(cls) -> Unknown
|
reveal_type(getattr_static(C, "f")) # revealed: def f(cls) -> Unknown
|
||||||
reveal_type(getattr_static(C, "f").__get__) # revealed: <method-wrapper `__get__` of `f`>
|
# revealed: <method-wrapper '__get__' of function 'f'>
|
||||||
|
reveal_type(getattr_static(C, "f").__get__)
|
||||||
```
|
```
|
||||||
|
|
||||||
But we correctly model how the `classmethod` descriptor works:
|
But we correctly model how the `classmethod` descriptor works:
|
||||||
|
|
@ -632,7 +634,7 @@ class MyClass:
|
||||||
|
|
||||||
static_assert(is_assignable_to(types.FunctionType, Callable))
|
static_assert(is_assignable_to(types.FunctionType, Callable))
|
||||||
|
|
||||||
# revealed: <wrapper-descriptor `__get__` of `function` objects>
|
# revealed: <wrapper-descriptor '__get__' of 'function' objects>
|
||||||
reveal_type(types.FunctionType.__get__)
|
reveal_type(types.FunctionType.__get__)
|
||||||
static_assert(is_assignable_to(TypeOf[types.FunctionType.__get__], Callable))
|
static_assert(is_assignable_to(TypeOf[types.FunctionType.__get__], Callable))
|
||||||
|
|
||||||
|
|
@ -640,7 +642,7 @@ static_assert(is_assignable_to(TypeOf[types.FunctionType.__get__], Callable))
|
||||||
reveal_type(f)
|
reveal_type(f)
|
||||||
static_assert(is_assignable_to(TypeOf[f], Callable))
|
static_assert(is_assignable_to(TypeOf[f], Callable))
|
||||||
|
|
||||||
# revealed: <method-wrapper `__get__` of `f`>
|
# revealed: <method-wrapper '__get__' of function 'f'>
|
||||||
reveal_type(f.__get__)
|
reveal_type(f.__get__)
|
||||||
static_assert(is_assignable_to(TypeOf[f.__get__], Callable))
|
static_assert(is_assignable_to(TypeOf[f.__get__], Callable))
|
||||||
|
|
||||||
|
|
@ -648,11 +650,11 @@ static_assert(is_assignable_to(TypeOf[f.__get__], Callable))
|
||||||
reveal_type(types.FunctionType.__call__)
|
reveal_type(types.FunctionType.__call__)
|
||||||
static_assert(is_assignable_to(TypeOf[types.FunctionType.__call__], Callable))
|
static_assert(is_assignable_to(TypeOf[types.FunctionType.__call__], Callable))
|
||||||
|
|
||||||
# revealed: <method-wrapper `__call__` of `f`>
|
# revealed: <method-wrapper '__call__' of function 'f'>
|
||||||
reveal_type(f.__call__)
|
reveal_type(f.__call__)
|
||||||
static_assert(is_assignable_to(TypeOf[f.__call__], Callable))
|
static_assert(is_assignable_to(TypeOf[f.__call__], Callable))
|
||||||
|
|
||||||
# revealed: <wrapper-descriptor `__get__` of `property` objects>
|
# revealed: <wrapper-descriptor '__get__' of 'property' objects>
|
||||||
reveal_type(property.__get__)
|
reveal_type(property.__get__)
|
||||||
static_assert(is_assignable_to(TypeOf[property.__get__], Callable))
|
static_assert(is_assignable_to(TypeOf[property.__get__], Callable))
|
||||||
|
|
||||||
|
|
@ -661,15 +663,15 @@ reveal_type(MyClass.my_property)
|
||||||
static_assert(is_assignable_to(TypeOf[property], Callable))
|
static_assert(is_assignable_to(TypeOf[property], Callable))
|
||||||
static_assert(not is_assignable_to(TypeOf[MyClass.my_property], Callable))
|
static_assert(not is_assignable_to(TypeOf[MyClass.my_property], Callable))
|
||||||
|
|
||||||
# revealed: <method-wrapper `__get__` of `property` object>
|
# revealed: <method-wrapper '__get__' of property 'my_property'>
|
||||||
reveal_type(MyClass.my_property.__get__)
|
reveal_type(MyClass.my_property.__get__)
|
||||||
static_assert(is_assignable_to(TypeOf[MyClass.my_property.__get__], Callable))
|
static_assert(is_assignable_to(TypeOf[MyClass.my_property.__get__], Callable))
|
||||||
|
|
||||||
# revealed: <wrapper-descriptor `__set__` of `property` objects>
|
# revealed: <wrapper-descriptor '__set__' of 'property' objects>
|
||||||
reveal_type(property.__set__)
|
reveal_type(property.__set__)
|
||||||
static_assert(is_assignable_to(TypeOf[property.__set__], Callable))
|
static_assert(is_assignable_to(TypeOf[property.__set__], Callable))
|
||||||
|
|
||||||
# revealed: <method-wrapper `__set__` of `property` object>
|
# revealed: <method-wrapper '__set__' of property 'my_property'>
|
||||||
reveal_type(MyClass.my_property.__set__)
|
reveal_type(MyClass.my_property.__set__)
|
||||||
static_assert(is_assignable_to(TypeOf[MyClass.my_property.__set__], Callable))
|
static_assert(is_assignable_to(TypeOf[MyClass.my_property.__set__], Callable))
|
||||||
|
|
||||||
|
|
@ -677,7 +679,7 @@ static_assert(is_assignable_to(TypeOf[MyClass.my_property.__set__], Callable))
|
||||||
reveal_type(str.startswith)
|
reveal_type(str.startswith)
|
||||||
static_assert(is_assignable_to(TypeOf[str.startswith], Callable))
|
static_assert(is_assignable_to(TypeOf[str.startswith], Callable))
|
||||||
|
|
||||||
# revealed: <method-wrapper `startswith` of `str` object>
|
# revealed: <method-wrapper 'startswith' of string 'foo'>
|
||||||
reveal_type("foo".startswith)
|
reveal_type("foo".startswith)
|
||||||
static_assert(is_assignable_to(TypeOf["foo".startswith], Callable))
|
static_assert(is_assignable_to(TypeOf["foo".startswith], Callable))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -596,14 +596,14 @@ def f(x: object) -> str:
|
||||||
return "a"
|
return "a"
|
||||||
|
|
||||||
reveal_type(f) # revealed: def f(x: object) -> str
|
reveal_type(f) # revealed: def f(x: object) -> str
|
||||||
reveal_type(f.__get__) # revealed: <method-wrapper `__get__` of `f`>
|
reveal_type(f.__get__) # revealed: <method-wrapper '__get__' of function 'f'>
|
||||||
static_assert(is_subtype_of(TypeOf[f.__get__], types.MethodWrapperType))
|
static_assert(is_subtype_of(TypeOf[f.__get__], types.MethodWrapperType))
|
||||||
reveal_type(f.__get__(None, type(f))) # revealed: def f(x: object) -> str
|
reveal_type(f.__get__(None, type(f))) # revealed: def f(x: object) -> str
|
||||||
reveal_type(f.__get__(None, type(f))(1)) # revealed: str
|
reveal_type(f.__get__(None, type(f))(1)) # revealed: str
|
||||||
|
|
||||||
wrapper_descriptor = getattr_static(f, "__get__")
|
wrapper_descriptor = getattr_static(f, "__get__")
|
||||||
|
|
||||||
reveal_type(wrapper_descriptor) # revealed: <wrapper-descriptor `__get__` of `function` objects>
|
reveal_type(wrapper_descriptor) # revealed: <wrapper-descriptor '__get__' of 'function' objects>
|
||||||
reveal_type(wrapper_descriptor(f, None, type(f))) # revealed: def f(x: object) -> str
|
reveal_type(wrapper_descriptor(f, None, type(f))) # revealed: def f(x: object) -> str
|
||||||
static_assert(is_subtype_of(TypeOf[wrapper_descriptor], types.WrapperDescriptorType))
|
static_assert(is_subtype_of(TypeOf[wrapper_descriptor], types.WrapperDescriptorType))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ class C[T]:
|
||||||
return "a"
|
return "a"
|
||||||
|
|
||||||
reveal_type(getattr_static(C[int], "f")) # revealed: def f(self, x: int) -> str
|
reveal_type(getattr_static(C[int], "f")) # revealed: def f(self, x: int) -> str
|
||||||
reveal_type(getattr_static(C[int], "f").__get__) # revealed: <method-wrapper `__get__` of `f`>
|
reveal_type(getattr_static(C[int], "f").__get__) # revealed: <method-wrapper '__get__' of function 'f'>
|
||||||
reveal_type(getattr_static(C[int], "f").__get__(None, C[int])) # revealed: def f(self, x: int) -> str
|
reveal_type(getattr_static(C[int], "f").__get__(None, C[int])) # revealed: def f(self, x: int) -> str
|
||||||
# revealed: bound method C[int].f(x: int) -> str
|
# revealed: bound method C[int].f(x: int) -> str
|
||||||
reveal_type(getattr_static(C[int], "f").__get__(C[int](), C[int]))
|
reveal_type(getattr_static(C[int], "f").__get__(C[int](), C[int]))
|
||||||
|
|
|
||||||
|
|
@ -271,8 +271,8 @@ method, which means that it is a *data* descriptor (if there is no setter, `__se
|
||||||
available but yields an `AttributeError` at runtime).
|
available but yields an `AttributeError` at runtime).
|
||||||
|
|
||||||
```py
|
```py
|
||||||
reveal_type(type(attr_property).__get__) # revealed: <wrapper-descriptor `__get__` of `property` objects>
|
reveal_type(type(attr_property).__get__) # revealed: <wrapper-descriptor '__get__' of 'property' objects>
|
||||||
reveal_type(type(attr_property).__set__) # revealed: <wrapper-descriptor `__set__` of `property` objects>
|
reveal_type(type(attr_property).__set__) # revealed: <wrapper-descriptor '__set__' of 'property' objects>
|
||||||
```
|
```
|
||||||
|
|
||||||
When we access `c.attr`, the `__get__` method of the `property` class is called, passing the
|
When we access `c.attr`, the `__get__` method of the `property` class is called, passing the
|
||||||
|
|
|
||||||
|
|
@ -8314,6 +8314,7 @@ impl<'db> Type<'db> {
|
||||||
KnownInstanceType::TypeAliasType(type_alias) => {
|
KnownInstanceType::TypeAliasType(type_alias) => {
|
||||||
type_alias.definition(db).map(TypeDefinition::TypeAlias)
|
type_alias.definition(db).map(TypeDefinition::TypeAlias)
|
||||||
}
|
}
|
||||||
|
KnownInstanceType::NewType(newtype) => Some(TypeDefinition::NewType(newtype.definition(db))),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ use ruff_text_size::{TextLen, TextRange, TextSize};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
use crate::Db;
|
use crate::Db;
|
||||||
|
use crate::place::Place;
|
||||||
use crate::types::class::{ClassLiteral, ClassType, GenericAlias};
|
use crate::types::class::{ClassLiteral, ClassType, GenericAlias};
|
||||||
use crate::types::function::{FunctionType, OverloadLiteral};
|
use crate::types::function::{FunctionType, OverloadLiteral};
|
||||||
use crate::types::generics::{GenericContext, Specialization};
|
use crate::types::generics::{GenericContext, Specialization};
|
||||||
|
|
@ -642,11 +643,13 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
|
||||||
Type::PropertyInstance(_) => f.with_type(self.ty).write_str("property"),
|
Type::PropertyInstance(_) => f.with_type(self.ty).write_str("property"),
|
||||||
Type::ModuleLiteral(module) => {
|
Type::ModuleLiteral(module) => {
|
||||||
f.set_invalid_syntax();
|
f.set_invalid_syntax();
|
||||||
write!(
|
f.write_char('<')?;
|
||||||
f.with_type(self.ty),
|
f.with_type(KnownClass::ModuleType.to_class_literal(self.db))
|
||||||
"<module '{}'>",
|
.write_str("module")?;
|
||||||
module.module(self.db).name(self.db)
|
f.write_str(" '")?;
|
||||||
)
|
f.with_type(self.ty)
|
||||||
|
.write_str(module.module(self.db).name(self.db))?;
|
||||||
|
f.write_str("'>")
|
||||||
}
|
}
|
||||||
Type::ClassLiteral(class) => {
|
Type::ClassLiteral(class) => {
|
||||||
f.set_invalid_syntax();
|
f.set_invalid_syntax();
|
||||||
|
|
@ -692,11 +695,17 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
|
||||||
write!(f.with_type(Type::Dynamic(dynamic)), "{dynamic}")?;
|
write!(f.with_type(Type::Dynamic(dynamic)), "{dynamic}")?;
|
||||||
f.write_char(']')
|
f.write_char(']')
|
||||||
}
|
}
|
||||||
SubclassOfInner::TypeVar(bound_typevar) => write!(
|
SubclassOfInner::TypeVar(bound_typevar) => {
|
||||||
f,
|
f.with_type(KnownClass::Type.to_class_literal(self.db))
|
||||||
"type[{}]",
|
.write_str("type")?;
|
||||||
bound_typevar.identity(self.db).display(self.db)
|
f.write_char('[')?;
|
||||||
),
|
write!(
|
||||||
|
f.with_type(Type::TypeVar(bound_typevar)),
|
||||||
|
"{}",
|
||||||
|
bound_typevar.identity(self.db).display(self.db)
|
||||||
|
)?;
|
||||||
|
f.write_char(']')
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Type::SpecialForm(special_form) => {
|
Type::SpecialForm(special_form) => {
|
||||||
f.set_invalid_syntax();
|
f.set_invalid_syntax();
|
||||||
|
|
@ -763,61 +772,115 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
|
||||||
}
|
}
|
||||||
Type::KnownBoundMethod(method_type) => {
|
Type::KnownBoundMethod(method_type) => {
|
||||||
f.set_invalid_syntax();
|
f.set_invalid_syntax();
|
||||||
match method_type {
|
let (cls, member_name, cls_name, ty, ty_name) = match method_type {
|
||||||
KnownBoundMethodType::FunctionTypeDunderGet(function) => {
|
KnownBoundMethodType::FunctionTypeDunderGet(function) => (
|
||||||
write!(
|
KnownClass::FunctionType,
|
||||||
f,
|
"__get__",
|
||||||
"<method-wrapper `__get__` of `{function}`>",
|
"function",
|
||||||
function = function.name(self.db),
|
Type::FunctionLiteral(function),
|
||||||
)
|
Some(&**function.name(self.db)),
|
||||||
}
|
),
|
||||||
KnownBoundMethodType::FunctionTypeDunderCall(function) => {
|
KnownBoundMethodType::FunctionTypeDunderCall(function) => (
|
||||||
write!(
|
KnownClass::FunctionType,
|
||||||
f,
|
"__call__",
|
||||||
"<method-wrapper `__call__` of `{function}`>",
|
"function",
|
||||||
function = function.name(self.db),
|
Type::FunctionLiteral(function),
|
||||||
)
|
Some(&**function.name(self.db)),
|
||||||
}
|
),
|
||||||
KnownBoundMethodType::PropertyDunderGet(_) => {
|
KnownBoundMethodType::PropertyDunderGet(property) => (
|
||||||
f.write_str("<method-wrapper `__get__` of `property` object>")
|
KnownClass::Property,
|
||||||
}
|
"__get__",
|
||||||
KnownBoundMethodType::PropertyDunderSet(_) => {
|
"property",
|
||||||
f.write_str("<method-wrapper `__set__` of `property` object>")
|
Type::PropertyInstance(property),
|
||||||
}
|
property
|
||||||
KnownBoundMethodType::StrStartswith(_) => {
|
.getter(self.db)
|
||||||
f.write_str("<method-wrapper `startswith` of `str` object>")
|
.and_then(Type::as_function_literal)
|
||||||
}
|
.map(|getter| &**getter.name(self.db)),
|
||||||
|
),
|
||||||
|
KnownBoundMethodType::PropertyDunderSet(property) => (
|
||||||
|
KnownClass::Property,
|
||||||
|
"__set__",
|
||||||
|
"property",
|
||||||
|
Type::PropertyInstance(property),
|
||||||
|
property
|
||||||
|
.getter(self.db)
|
||||||
|
.and_then(Type::as_function_literal)
|
||||||
|
.map(|getter| &**getter.name(self.db)),
|
||||||
|
),
|
||||||
|
KnownBoundMethodType::StrStartswith(literal) => (
|
||||||
|
KnownClass::Property,
|
||||||
|
"startswith",
|
||||||
|
"string",
|
||||||
|
Type::StringLiteral(literal),
|
||||||
|
Some(literal.value(self.db)),
|
||||||
|
),
|
||||||
KnownBoundMethodType::ConstraintSetRange => {
|
KnownBoundMethodType::ConstraintSetRange => {
|
||||||
f.write_str("bound method `ConstraintSet.range`")
|
return f.write_str("bound method `ConstraintSet.range`");
|
||||||
}
|
}
|
||||||
KnownBoundMethodType::ConstraintSetAlways => {
|
KnownBoundMethodType::ConstraintSetAlways => {
|
||||||
f.write_str("bound method `ConstraintSet.always`")
|
return f.write_str("bound method `ConstraintSet.always`");
|
||||||
}
|
}
|
||||||
KnownBoundMethodType::ConstraintSetNever => {
|
KnownBoundMethodType::ConstraintSetNever => {
|
||||||
f.write_str("bound method `ConstraintSet.never`")
|
return f.write_str("bound method `ConstraintSet.never`");
|
||||||
}
|
}
|
||||||
KnownBoundMethodType::ConstraintSetImpliesSubtypeOf(_) => {
|
KnownBoundMethodType::ConstraintSetImpliesSubtypeOf(_) => {
|
||||||
f.write_str("bound method `ConstraintSet.implies_subtype_of`")
|
return f.write_str("bound method `ConstraintSet.implies_subtype_of`");
|
||||||
}
|
}
|
||||||
KnownBoundMethodType::ConstraintSetSatisfies(_) => {
|
KnownBoundMethodType::ConstraintSetSatisfies(_) => {
|
||||||
f.write_str("bound method `ConstraintSet.satisfies`")
|
return f.write_str("bound method `ConstraintSet.satisfies`");
|
||||||
}
|
}
|
||||||
KnownBoundMethodType::ConstraintSetSatisfiedByAllTypeVars(_) => {
|
KnownBoundMethodType::ConstraintSetSatisfiedByAllTypeVars(_) => {
|
||||||
f.write_str("bound method `ConstraintSet.satisfied_by_all_typevars`")
|
return f
|
||||||
|
.write_str("bound method `ConstraintSet.satisfied_by_all_typevars`");
|
||||||
}
|
}
|
||||||
KnownBoundMethodType::GenericContextSpecializeConstrained(_) => {
|
KnownBoundMethodType::GenericContextSpecializeConstrained(_) => {
|
||||||
f.write_str("bound method `GenericContext.specialize_constrained`")
|
return f.write_str("bound method `GenericContext.specialize_constrained`");
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let class_ty = cls.to_class_literal(self.db);
|
||||||
|
f.write_char('<')?;
|
||||||
|
f.with_type(KnownClass::MethodWrapperType.to_class_literal(self.db))
|
||||||
|
.write_str("method-wrapper")?;
|
||||||
|
f.write_str(" '")?;
|
||||||
|
if let Place::Defined(member_ty, _, _) = class_ty.member(self.db, member_name).place
|
||||||
|
{
|
||||||
|
f.with_type(member_ty).write_str(member_name)?;
|
||||||
|
} else {
|
||||||
|
f.write_str(member_name)?;
|
||||||
|
}
|
||||||
|
f.write_str("' of ")?;
|
||||||
|
f.with_type(class_ty).write_str(cls_name)?;
|
||||||
|
if let Some(name) = ty_name {
|
||||||
|
f.write_str(" '")?;
|
||||||
|
f.with_type(ty).write_str(name)?;
|
||||||
|
f.write_str("'>")
|
||||||
|
} else {
|
||||||
|
f.write_str("' object>")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type::WrapperDescriptor(kind) => {
|
Type::WrapperDescriptor(kind) => {
|
||||||
f.set_invalid_syntax();
|
f.set_invalid_syntax();
|
||||||
let (method, object) = match kind {
|
let (method, object, cls) = match kind {
|
||||||
WrapperDescriptorKind::FunctionTypeDunderGet => ("__get__", "function"),
|
WrapperDescriptorKind::FunctionTypeDunderGet => {
|
||||||
WrapperDescriptorKind::PropertyDunderGet => ("__get__", "property"),
|
("__get__", "function", KnownClass::FunctionType)
|
||||||
WrapperDescriptorKind::PropertyDunderSet => ("__set__", "property"),
|
}
|
||||||
|
WrapperDescriptorKind::PropertyDunderGet => {
|
||||||
|
("__get__", "property", KnownClass::Property)
|
||||||
|
}
|
||||||
|
WrapperDescriptorKind::PropertyDunderSet => {
|
||||||
|
("__set__", "property", KnownClass::Property)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
write!(f, "<wrapper-descriptor `{method}` of `{object}` objects>")
|
f.write_char('<')?;
|
||||||
|
f.with_type(KnownClass::WrapperDescriptorType.to_class_literal(self.db))
|
||||||
|
.write_str("wrapper-descriptor")?;
|
||||||
|
f.write_str(" '")?;
|
||||||
|
f.write_str(method)?;
|
||||||
|
f.write_str("' of '")?;
|
||||||
|
f.with_type(cls.to_class_literal(self.db))
|
||||||
|
.write_str(object)?;
|
||||||
|
f.write_str("' objects>")
|
||||||
}
|
}
|
||||||
Type::DataclassDecorator(_) => {
|
Type::DataclassDecorator(_) => {
|
||||||
f.set_invalid_syntax();
|
f.set_invalid_syntax();
|
||||||
|
|
@ -907,7 +970,10 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
|
||||||
.fmt_detailed(f),
|
.fmt_detailed(f),
|
||||||
Type::TypedDict(TypedDictType::Synthesized(synthesized)) => {
|
Type::TypedDict(TypedDictType::Synthesized(synthesized)) => {
|
||||||
f.set_invalid_syntax();
|
f.set_invalid_syntax();
|
||||||
f.write_str("<TypedDict with items ")?;
|
f.write_char('<')?;
|
||||||
|
f.with_type(Type::SpecialForm(SpecialFormType::TypedDict))
|
||||||
|
.write_str("TypedDict")?;
|
||||||
|
f.write_str(" with items ")?;
|
||||||
let items = synthesized.items(self.db);
|
let items = synthesized.items(self.db);
|
||||||
for (i, name) in items.keys().enumerate() {
|
for (i, name) in items.keys().enumerate() {
|
||||||
let is_last = i == items.len() - 1;
|
let is_last = i == items.len() - 1;
|
||||||
|
|
@ -1318,10 +1384,13 @@ impl<'db> DisplayGenericContext<'_, 'db> {
|
||||||
f.set_invalid_syntax();
|
f.set_invalid_syntax();
|
||||||
let typevar = bound_typevar.typevar(self.db);
|
let typevar = bound_typevar.typevar(self.db);
|
||||||
if typevar.is_paramspec(self.db) {
|
if typevar.is_paramspec(self.db) {
|
||||||
write!(f, "**{}", typevar.name(self.db))?;
|
f.write_str("**")?;
|
||||||
} else {
|
|
||||||
f.write_str(typevar.name(self.db))?;
|
|
||||||
}
|
}
|
||||||
|
write!(
|
||||||
|
f.with_type(Type::TypeVar(*bound_typevar)),
|
||||||
|
"{}",
|
||||||
|
typevar.name(self.db)
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
f.write_char(']')
|
f.write_char(']')
|
||||||
}
|
}
|
||||||
|
|
@ -1334,7 +1403,11 @@ impl<'db> DisplayGenericContext<'_, 'db> {
|
||||||
f.write_str(", ")?;
|
f.write_str(", ")?;
|
||||||
}
|
}
|
||||||
f.set_invalid_syntax();
|
f.set_invalid_syntax();
|
||||||
write!(f, "{}", bound_typevar.identity(self.db).display(self.db))?;
|
write!(
|
||||||
|
f.with_type(Type::TypeVar(bound_typevar)),
|
||||||
|
"{}",
|
||||||
|
bound_typevar.identity(self.db).display(self.db)
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
f.write_char(']')
|
f.write_char(']')
|
||||||
}
|
}
|
||||||
|
|
@ -2262,15 +2335,17 @@ impl<'db> FmtDetailed<'db> for DisplayKnownInstanceRepr<'db> {
|
||||||
KnownInstanceType::SubscriptedProtocol(generic_context) => {
|
KnownInstanceType::SubscriptedProtocol(generic_context) => {
|
||||||
f.set_invalid_syntax();
|
f.set_invalid_syntax();
|
||||||
f.write_str("<special form '")?;
|
f.write_str("<special form '")?;
|
||||||
f.with_type(ty).write_str("typing.Protocol")?;
|
f.with_type(Type::SpecialForm(SpecialFormType::Protocol))
|
||||||
f.write_str(&generic_context.display(self.db).to_string())?;
|
.write_str("typing.Protocol")?;
|
||||||
|
generic_context.display(self.db).fmt_detailed(f)?;
|
||||||
f.write_str("'>")
|
f.write_str("'>")
|
||||||
}
|
}
|
||||||
KnownInstanceType::SubscriptedGeneric(generic_context) => {
|
KnownInstanceType::SubscriptedGeneric(generic_context) => {
|
||||||
f.set_invalid_syntax();
|
f.set_invalid_syntax();
|
||||||
f.write_str("<special form '")?;
|
f.write_str("<special form '")?;
|
||||||
f.with_type(ty).write_str("typing.Generic")?;
|
f.with_type(Type::SpecialForm(SpecialFormType::Generic))
|
||||||
f.write_str(&generic_context.display(self.db).to_string())?;
|
.write_str("typing.Generic")?;
|
||||||
|
generic_context.display(self.db).fmt_detailed(f)?;
|
||||||
f.write_str("'>")
|
f.write_str("'>")
|
||||||
}
|
}
|
||||||
KnownInstanceType::TypeAliasType(alias) => {
|
KnownInstanceType::TypeAliasType(alias) => {
|
||||||
|
|
@ -2278,15 +2353,9 @@ impl<'db> FmtDetailed<'db> for DisplayKnownInstanceRepr<'db> {
|
||||||
f.set_invalid_syntax();
|
f.set_invalid_syntax();
|
||||||
f.write_str("<type alias '")?;
|
f.write_str("<type alias '")?;
|
||||||
f.with_type(ty).write_str(alias.name(self.db))?;
|
f.with_type(ty).write_str(alias.name(self.db))?;
|
||||||
f.write_str(
|
specialization
|
||||||
&specialization
|
.display_short(self.db, TupleSpecialization::No, DisplaySettings::default())
|
||||||
.display_short(
|
.fmt_detailed(f)?;
|
||||||
self.db,
|
|
||||||
TupleSpecialization::No,
|
|
||||||
DisplaySettings::default(),
|
|
||||||
)
|
|
||||||
.to_string(),
|
|
||||||
)?;
|
|
||||||
f.write_str("'>")
|
f.write_str("'>")
|
||||||
} else {
|
} else {
|
||||||
f.with_type(ty).write_str("typing.TypeAliasType")
|
f.with_type(ty).write_str("typing.TypeAliasType")
|
||||||
|
|
@ -2306,7 +2375,9 @@ impl<'db> FmtDetailed<'db> for DisplayKnownInstanceRepr<'db> {
|
||||||
KnownInstanceType::Field(field) => {
|
KnownInstanceType::Field(field) => {
|
||||||
f.with_type(ty).write_str("dataclasses.Field")?;
|
f.with_type(ty).write_str("dataclasses.Field")?;
|
||||||
if let Some(default_ty) = field.default_type(self.db) {
|
if let Some(default_ty) = field.default_type(self.db) {
|
||||||
write!(f, "[{}]", default_ty.display(self.db))?;
|
f.write_char('[')?;
|
||||||
|
write!(f.with_type(default_ty), "{}", default_ty.display(self.db))?;
|
||||||
|
f.write_char(']')?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -2325,51 +2396,58 @@ impl<'db> FmtDetailed<'db> for DisplayKnownInstanceRepr<'db> {
|
||||||
KnownInstanceType::UnionType(union) => {
|
KnownInstanceType::UnionType(union) => {
|
||||||
f.set_invalid_syntax();
|
f.set_invalid_syntax();
|
||||||
f.write_char('<')?;
|
f.write_char('<')?;
|
||||||
f.with_type(ty).write_str("types.UnionType")?;
|
f.with_type(KnownClass::UnionType.to_class_literal(self.db))
|
||||||
|
.write_str("types.UnionType")?;
|
||||||
f.write_str(" special form")?;
|
f.write_str(" special form")?;
|
||||||
if let Ok(ty) = union.union_type(self.db) {
|
if let Ok(ty) = union.union_type(self.db) {
|
||||||
write!(f, " '{}'", ty.display(self.db))?;
|
f.write_str(" '")?;
|
||||||
|
ty.display(self.db).fmt_detailed(f)?;
|
||||||
|
f.write_char('\'')?;
|
||||||
}
|
}
|
||||||
f.write_char('>')
|
f.write_char('>')
|
||||||
}
|
}
|
||||||
KnownInstanceType::Literal(inner) => {
|
KnownInstanceType::Literal(inner) => {
|
||||||
f.set_invalid_syntax();
|
f.set_invalid_syntax();
|
||||||
write!(
|
f.write_str("<special form '")?;
|
||||||
f,
|
inner.inner(self.db).display(self.db).fmt_detailed(f)?;
|
||||||
"<special form '{}'>",
|
f.write_str("'>")
|
||||||
inner.inner(self.db).display(self.db)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
KnownInstanceType::Annotated(inner) => {
|
KnownInstanceType::Annotated(inner) => {
|
||||||
f.set_invalid_syntax();
|
f.set_invalid_syntax();
|
||||||
f.write_str("<special form '")?;
|
f.write_str("<special form '")?;
|
||||||
f.with_type(ty).write_str("typing.Annotated")?;
|
f.with_type(Type::SpecialForm(SpecialFormType::Annotated))
|
||||||
write!(
|
.write_str("typing.Annotated")?;
|
||||||
f,
|
f.write_char('[')?;
|
||||||
"[{}, <metadata>]'>",
|
inner.inner(self.db).display(self.db).fmt_detailed(f)?;
|
||||||
inner.inner(self.db).display(self.db)
|
f.write_str(", <metadata>]'>")
|
||||||
)
|
|
||||||
}
|
}
|
||||||
KnownInstanceType::Callable(callable) => {
|
KnownInstanceType::Callable(callable) => {
|
||||||
f.set_invalid_syntax();
|
f.set_invalid_syntax();
|
||||||
f.write_char('<')?;
|
f.write_char('<')?;
|
||||||
f.with_type(ty).write_str("typing.Callable")?;
|
f.with_type(Type::SpecialForm(SpecialFormType::Callable))
|
||||||
write!(f, " special form '{}'>", callable.display(self.db))
|
.write_str("typing.Callable")?;
|
||||||
|
f.write_str(" special form '")?;
|
||||||
|
callable.display(self.db).fmt_detailed(f)?;
|
||||||
|
f.write_str("'>")
|
||||||
}
|
}
|
||||||
KnownInstanceType::TypeGenericAlias(inner) => {
|
KnownInstanceType::TypeGenericAlias(inner) => {
|
||||||
f.set_invalid_syntax();
|
f.set_invalid_syntax();
|
||||||
f.write_str("<special form '")?;
|
f.write_str("<special form '")?;
|
||||||
write!(
|
f.with_type(KnownClass::Type.to_class_literal(self.db))
|
||||||
f.with_type(ty),
|
.write_str("type")?;
|
||||||
"type[{}]",
|
f.write_char('[')?;
|
||||||
inner.inner(self.db).display(self.db)
|
inner.inner(self.db).display(self.db).fmt_detailed(f)?;
|
||||||
)?;
|
f.write_str("]'>")
|
||||||
f.write_str("'>")
|
|
||||||
}
|
}
|
||||||
KnownInstanceType::LiteralStringAlias(_) => f.write_str("str"),
|
KnownInstanceType::LiteralStringAlias(_) => f
|
||||||
|
.with_type(KnownClass::Str.to_class_literal(self.db))
|
||||||
|
.write_str("str"),
|
||||||
KnownInstanceType::NewType(declaration) => {
|
KnownInstanceType::NewType(declaration) => {
|
||||||
f.set_invalid_syntax();
|
f.set_invalid_syntax();
|
||||||
f.write_str("<NewType pseudo-class '")?;
|
f.write_char('<')?;
|
||||||
|
f.with_type(KnownClass::NewType.to_class_literal(self.db))
|
||||||
|
.write_str("NewType")?;
|
||||||
|
f.write_str(" pseudo-class '")?;
|
||||||
f.with_type(ty).write_str(declaration.name(self.db))?;
|
f.with_type(ty).write_str(declaration.name(self.db))?;
|
||||||
f.write_str("'>")
|
f.write_str("'>")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue