Skip to content

Commit 78ce17c

Browse files
authored
[ty] Add more TypeDetails to the display code (#21541)
As far as I know this change is largely non-functional, largely because of astral-sh/ty#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.
1 parent 0761ea4 commit 78ce17c

File tree

2 files changed

+85
-13
lines changed

2 files changed

+85
-13
lines changed

crates/ty_ide/src/inlay_hints.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4143,6 +4143,43 @@ mod tests {
41434143
");
41444144
}
41454145

4146+
#[test]
4147+
fn test_literal_string() {
4148+
let mut test = inlay_hint_test(
4149+
r#"
4150+
from typing import LiteralString
4151+
def my_func(x: LiteralString):
4152+
y = x
4153+
my_func(x="hello")"#,
4154+
);
4155+
4156+
assert_snapshot!(test.inlay_hints(), @r#"
4157+
from typing import LiteralString
4158+
def my_func(x: LiteralString):
4159+
y[: LiteralString] = x
4160+
my_func(x="hello")
4161+
---------------------------------------------
4162+
info[inlay-hint-location]: Inlay Hint Target
4163+
--> stdlib/builtins.pyi:915:7
4164+
|
4165+
914 | @disjoint_base
4166+
915 | class str(Sequence[str]):
4167+
| ^^^
4168+
916 | """str(object='') -> str
4169+
917 | str(bytes_or_buffer[, encoding[, errors]]) -> str
4170+
|
4171+
info: Source
4172+
--> main2.py:4:9
4173+
|
4174+
2 | from typing import LiteralString
4175+
3 | def my_func(x: LiteralString):
4176+
4 | y[: LiteralString] = x
4177+
| ^^^^^^^^^^^^^
4178+
5 | my_func(x="hello")
4179+
|
4180+
"#);
4181+
}
4182+
41464183
#[test]
41474184
fn test_complex_parameter_combinations() {
41484185
let mut test = inlay_hint_test(

crates/ty_python_semantic/src/types/display.rs

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ use crate::types::signatures::{CallableSignature, Parameter, Parameters, Signatu
2424
use crate::types::tuple::TupleSpec;
2525
use crate::types::visitor::TypeVisitor;
2626
use crate::types::{
27-
BoundTypeVarIdentity, CallableType, IntersectionType, KnownBoundMethodType, KnownClass,
28-
MaterializationKind, Protocol, ProtocolInstanceType, StringLiteralType, SubclassOfInner, Type,
29-
UnionType, WrapperDescriptorKind, visitor,
27+
BoundTypeVarIdentity, CallableType, DynamicType, IntersectionType, KnownBoundMethodType,
28+
KnownClass, MaterializationKind, Protocol, ProtocolInstanceType, SpecialFormType,
29+
StringLiteralType, SubclassOfInner, Type, UnionType, WrapperDescriptorKind, visitor,
3030
};
3131
use ruff_db::parsed::parsed_module;
3232

@@ -470,7 +470,11 @@ impl<'db> FmtDetailed<'db> for DisplayType<'db> {
470470
| Type::StringLiteral(_)
471471
| Type::BytesLiteral(_)
472472
| Type::EnumLiteral(_) => {
473-
f.write_str("Literal[")?;
473+
f.with_detail(TypeDetail::Type(Type::SpecialForm(
474+
SpecialFormType::Literal,
475+
)))
476+
.write_str("Literal")?;
477+
f.write_char('[')?;
474478
representation.fmt_detailed(f)?;
475479
f.write_str("]")
476480
}
@@ -608,7 +612,16 @@ impl Display for DisplayRepresentation<'_> {
608612
impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
609613
fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result {
610614
match self.ty {
611-
Type::Dynamic(dynamic) => write!(f, "{dynamic}"),
615+
Type::Dynamic(dynamic) => {
616+
if let DynamicType::Any = dynamic {
617+
write!(
618+
f.with_detail(TypeDetail::Type(Type::SpecialForm(SpecialFormType::Any))),
619+
"{dynamic}"
620+
)
621+
} else {
622+
write!(f, "{dynamic}")
623+
}
624+
}
612625
Type::Never => f.with_detail(TypeDetail::Type(self.ty)).write_str("Never"),
613626
Type::NominalInstance(instance) => {
614627
let class = instance.class(self.db);
@@ -638,7 +651,12 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
638651
.fmt_detailed(f),
639652
},
640653
Protocol::Synthesized(synthetic) => {
641-
f.write_str("<Protocol with members ")?;
654+
f.write_char('<')?;
655+
f.with_detail(TypeDetail::Type(Type::SpecialForm(
656+
SpecialFormType::Protocol,
657+
)))
658+
.write_str("Protocol")?;
659+
f.write_str(" with members ")?;
642660
let interface = synthetic.interface();
643661
let member_list = interface.members(self.db);
644662
let num_members = member_list.len();
@@ -687,8 +705,14 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
687705
}
688706
SubclassOfInner::Dynamic(dynamic) => write!(f, "type[{dynamic}]"),
689707
},
690-
Type::SpecialForm(special_form) => write!(f, "{special_form}"),
691-
Type::KnownInstance(known_instance) => write!(f, "{}", known_instance.repr(self.db)),
708+
Type::SpecialForm(special_form) => {
709+
write!(f.with_detail(TypeDetail::Type(self.ty)), "{special_form}")
710+
}
711+
Type::KnownInstance(known_instance) => write!(
712+
f.with_detail(TypeDetail::Type(self.ty)),
713+
"{}",
714+
known_instance.repr(self.db)
715+
),
692716
Type::FunctionLiteral(function) => function
693717
.display_with(self.db, self.settings.clone())
694718
.fmt_detailed(f),
@@ -724,7 +748,10 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
724748
signatures => {
725749
// TODO: How to display overloads?
726750
if !self.settings.multiline {
727-
f.write_str("Overload[")?;
751+
// TODO: This should ideally have a TypeDetail but we actually
752+
// don't have a type for @overload (we just detect the decorator)
753+
f.write_str("Overload")?;
754+
f.write_char('[')?;
728755
}
729756
let separator = if self.settings.multiline { "\n" } else { ", " };
730757
let mut join = f.join(separator);
@@ -815,7 +842,9 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
815842
Type::StringLiteral(string) => {
816843
write!(f, "{}", string.display_with(self.db, self.settings.clone()))
817844
}
818-
Type::LiteralString => f.write_str("LiteralString"),
845+
Type::LiteralString => f
846+
.with_detail(TypeDetail::Type(self.ty))
847+
.write_str("LiteralString"),
819848
Type::BytesLiteral(bytes) => {
820849
let escape = AsciiEscape::with_preferred_quote(bytes.value(self.db), Quote::Double);
821850

@@ -831,8 +860,12 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
831860
Type::TypeVar(bound_typevar) => {
832861
write!(f, "{}", bound_typevar.identity(self.db).display(self.db))
833862
}
834-
Type::AlwaysTruthy => f.write_str("AlwaysTruthy"),
835-
Type::AlwaysFalsy => f.write_str("AlwaysFalsy"),
863+
Type::AlwaysTruthy => f
864+
.with_detail(TypeDetail::Type(self.ty))
865+
.write_str("AlwaysTruthy"),
866+
Type::AlwaysFalsy => f
867+
.with_detail(TypeDetail::Type(self.ty))
868+
.write_str("AlwaysFalsy"),
836869
Type::BoundSuper(bound_super) => {
837870
f.write_str("<super: ")?;
838871
Type::from(bound_super.pivot_class(self.db))
@@ -845,7 +878,9 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
845878
f.write_str(">")
846879
}
847880
Type::TypeIs(type_is) => {
848-
f.write_str("TypeIs[")?;
881+
f.with_detail(TypeDetail::Type(Type::SpecialForm(SpecialFormType::TypeIs)))
882+
.write_str("TypeIs")?;
883+
f.write_char('[')?;
849884
type_is
850885
.return_type(self.db)
851886
.display_with(self.db, self.settings.singleline())

0 commit comments

Comments
 (0)