mirror of https://github.com/astral-sh/ruff
[ty] Add more TypeDetails to the display code (#21541)
As far as I know this change is largely non-functional, largely because of https://github.com/astral-sh/ty/issues/1601 It's possible some of these like `Type::KnownInstance` produce something useful sometimes. `LiteralString` is a new introduction, although its goto-type jumps to `str` which is a bit sad (considering that part of the SpecialForm discourse for now). Also wrt the generics testing followup: turns out the snapshot tests were full of those already.
This commit is contained in:
parent
0761ea42d9
commit
78ce17ce8f
|
|
@ -4143,6 +4143,43 @@ mod tests {
|
||||||
");
|
");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_literal_string() {
|
||||||
|
let mut test = inlay_hint_test(
|
||||||
|
r#"
|
||||||
|
from typing import LiteralString
|
||||||
|
def my_func(x: LiteralString):
|
||||||
|
y = x
|
||||||
|
my_func(x="hello")"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_snapshot!(test.inlay_hints(), @r#"
|
||||||
|
from typing import LiteralString
|
||||||
|
def my_func(x: LiteralString):
|
||||||
|
y[: LiteralString] = x
|
||||||
|
my_func(x="hello")
|
||||||
|
---------------------------------------------
|
||||||
|
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:9
|
||||||
|
|
|
||||||
|
2 | from typing import LiteralString
|
||||||
|
3 | def my_func(x: LiteralString):
|
||||||
|
4 | y[: LiteralString] = x
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
5 | my_func(x="hello")
|
||||||
|
|
|
||||||
|
"#);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_complex_parameter_combinations() {
|
fn test_complex_parameter_combinations() {
|
||||||
let mut test = inlay_hint_test(
|
let mut test = inlay_hint_test(
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,9 @@ use crate::types::signatures::{CallableSignature, Parameter, Parameters, Signatu
|
||||||
use crate::types::tuple::TupleSpec;
|
use crate::types::tuple::TupleSpec;
|
||||||
use crate::types::visitor::TypeVisitor;
|
use crate::types::visitor::TypeVisitor;
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
BoundTypeVarIdentity, CallableType, IntersectionType, KnownBoundMethodType, KnownClass,
|
BoundTypeVarIdentity, CallableType, DynamicType, IntersectionType, KnownBoundMethodType,
|
||||||
MaterializationKind, Protocol, ProtocolInstanceType, StringLiteralType, SubclassOfInner, Type,
|
KnownClass, MaterializationKind, Protocol, ProtocolInstanceType, SpecialFormType,
|
||||||
UnionType, WrapperDescriptorKind, visitor,
|
StringLiteralType, SubclassOfInner, Type, UnionType, WrapperDescriptorKind, visitor,
|
||||||
};
|
};
|
||||||
use ruff_db::parsed::parsed_module;
|
use ruff_db::parsed::parsed_module;
|
||||||
|
|
||||||
|
|
@ -470,7 +470,11 @@ impl<'db> FmtDetailed<'db> for DisplayType<'db> {
|
||||||
| Type::StringLiteral(_)
|
| Type::StringLiteral(_)
|
||||||
| Type::BytesLiteral(_)
|
| Type::BytesLiteral(_)
|
||||||
| Type::EnumLiteral(_) => {
|
| Type::EnumLiteral(_) => {
|
||||||
f.write_str("Literal[")?;
|
f.with_detail(TypeDetail::Type(Type::SpecialForm(
|
||||||
|
SpecialFormType::Literal,
|
||||||
|
)))
|
||||||
|
.write_str("Literal")?;
|
||||||
|
f.write_char('[')?;
|
||||||
representation.fmt_detailed(f)?;
|
representation.fmt_detailed(f)?;
|
||||||
f.write_str("]")
|
f.write_str("]")
|
||||||
}
|
}
|
||||||
|
|
@ -608,7 +612,16 @@ impl Display for DisplayRepresentation<'_> {
|
||||||
impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
|
impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
|
||||||
fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result {
|
fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result {
|
||||||
match self.ty {
|
match self.ty {
|
||||||
Type::Dynamic(dynamic) => write!(f, "{dynamic}"),
|
Type::Dynamic(dynamic) => {
|
||||||
|
if let DynamicType::Any = dynamic {
|
||||||
|
write!(
|
||||||
|
f.with_detail(TypeDetail::Type(Type::SpecialForm(SpecialFormType::Any))),
|
||||||
|
"{dynamic}"
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
write!(f, "{dynamic}")
|
||||||
|
}
|
||||||
|
}
|
||||||
Type::Never => f.with_detail(TypeDetail::Type(self.ty)).write_str("Never"),
|
Type::Never => f.with_detail(TypeDetail::Type(self.ty)).write_str("Never"),
|
||||||
Type::NominalInstance(instance) => {
|
Type::NominalInstance(instance) => {
|
||||||
let class = instance.class(self.db);
|
let class = instance.class(self.db);
|
||||||
|
|
@ -638,7 +651,12 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
|
||||||
.fmt_detailed(f),
|
.fmt_detailed(f),
|
||||||
},
|
},
|
||||||
Protocol::Synthesized(synthetic) => {
|
Protocol::Synthesized(synthetic) => {
|
||||||
f.write_str("<Protocol with members ")?;
|
f.write_char('<')?;
|
||||||
|
f.with_detail(TypeDetail::Type(Type::SpecialForm(
|
||||||
|
SpecialFormType::Protocol,
|
||||||
|
)))
|
||||||
|
.write_str("Protocol")?;
|
||||||
|
f.write_str(" with members ")?;
|
||||||
let interface = synthetic.interface();
|
let interface = synthetic.interface();
|
||||||
let member_list = interface.members(self.db);
|
let member_list = interface.members(self.db);
|
||||||
let num_members = member_list.len();
|
let num_members = member_list.len();
|
||||||
|
|
@ -687,8 +705,14 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
|
||||||
}
|
}
|
||||||
SubclassOfInner::Dynamic(dynamic) => write!(f, "type[{dynamic}]"),
|
SubclassOfInner::Dynamic(dynamic) => write!(f, "type[{dynamic}]"),
|
||||||
},
|
},
|
||||||
Type::SpecialForm(special_form) => write!(f, "{special_form}"),
|
Type::SpecialForm(special_form) => {
|
||||||
Type::KnownInstance(known_instance) => write!(f, "{}", known_instance.repr(self.db)),
|
write!(f.with_detail(TypeDetail::Type(self.ty)), "{special_form}")
|
||||||
|
}
|
||||||
|
Type::KnownInstance(known_instance) => write!(
|
||||||
|
f.with_detail(TypeDetail::Type(self.ty)),
|
||||||
|
"{}",
|
||||||
|
known_instance.repr(self.db)
|
||||||
|
),
|
||||||
Type::FunctionLiteral(function) => function
|
Type::FunctionLiteral(function) => function
|
||||||
.display_with(self.db, self.settings.clone())
|
.display_with(self.db, self.settings.clone())
|
||||||
.fmt_detailed(f),
|
.fmt_detailed(f),
|
||||||
|
|
@ -724,7 +748,10 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
|
||||||
signatures => {
|
signatures => {
|
||||||
// TODO: How to display overloads?
|
// TODO: How to display overloads?
|
||||||
if !self.settings.multiline {
|
if !self.settings.multiline {
|
||||||
f.write_str("Overload[")?;
|
// TODO: This should ideally have a TypeDetail but we actually
|
||||||
|
// don't have a type for @overload (we just detect the decorator)
|
||||||
|
f.write_str("Overload")?;
|
||||||
|
f.write_char('[')?;
|
||||||
}
|
}
|
||||||
let separator = if self.settings.multiline { "\n" } else { ", " };
|
let separator = if self.settings.multiline { "\n" } else { ", " };
|
||||||
let mut join = f.join(separator);
|
let mut join = f.join(separator);
|
||||||
|
|
@ -815,7 +842,9 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
|
||||||
Type::StringLiteral(string) => {
|
Type::StringLiteral(string) => {
|
||||||
write!(f, "{}", string.display_with(self.db, self.settings.clone()))
|
write!(f, "{}", string.display_with(self.db, self.settings.clone()))
|
||||||
}
|
}
|
||||||
Type::LiteralString => f.write_str("LiteralString"),
|
Type::LiteralString => f
|
||||||
|
.with_detail(TypeDetail::Type(self.ty))
|
||||||
|
.write_str("LiteralString"),
|
||||||
Type::BytesLiteral(bytes) => {
|
Type::BytesLiteral(bytes) => {
|
||||||
let escape = AsciiEscape::with_preferred_quote(bytes.value(self.db), Quote::Double);
|
let escape = AsciiEscape::with_preferred_quote(bytes.value(self.db), Quote::Double);
|
||||||
|
|
||||||
|
|
@ -831,8 +860,12 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
|
||||||
Type::TypeVar(bound_typevar) => {
|
Type::TypeVar(bound_typevar) => {
|
||||||
write!(f, "{}", bound_typevar.identity(self.db).display(self.db))
|
write!(f, "{}", bound_typevar.identity(self.db).display(self.db))
|
||||||
}
|
}
|
||||||
Type::AlwaysTruthy => f.write_str("AlwaysTruthy"),
|
Type::AlwaysTruthy => f
|
||||||
Type::AlwaysFalsy => f.write_str("AlwaysFalsy"),
|
.with_detail(TypeDetail::Type(self.ty))
|
||||||
|
.write_str("AlwaysTruthy"),
|
||||||
|
Type::AlwaysFalsy => f
|
||||||
|
.with_detail(TypeDetail::Type(self.ty))
|
||||||
|
.write_str("AlwaysFalsy"),
|
||||||
Type::BoundSuper(bound_super) => {
|
Type::BoundSuper(bound_super) => {
|
||||||
f.write_str("<super: ")?;
|
f.write_str("<super: ")?;
|
||||||
Type::from(bound_super.pivot_class(self.db))
|
Type::from(bound_super.pivot_class(self.db))
|
||||||
|
|
@ -845,7 +878,9 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
|
||||||
f.write_str(">")
|
f.write_str(">")
|
||||||
}
|
}
|
||||||
Type::TypeIs(type_is) => {
|
Type::TypeIs(type_is) => {
|
||||||
f.write_str("TypeIs[")?;
|
f.with_detail(TypeDetail::Type(Type::SpecialForm(SpecialFormType::TypeIs)))
|
||||||
|
.write_str("TypeIs")?;
|
||||||
|
f.write_char('[')?;
|
||||||
type_is
|
type_is
|
||||||
.return_type(self.db)
|
.return_type(self.db)
|
||||||
.display_with(self.db, self.settings.singleline())
|
.display_with(self.db, self.settings.singleline())
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue