[ty] More low-hanging fruit for inlay hint goto-definition (#21548)

This commit is contained in:
Alex Waygood 2025-11-20 23:15:59 +00:00 committed by GitHub
parent eb7c098d6b
commit 06941c1987
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 418 additions and 71 deletions

View File

@ -588,6 +588,8 @@ mod tests {
y = x y = x
z = i(1) z = i(1)
w = z w = z
aa = b'foo'
bb = aa
", ",
); );
@ -599,6 +601,8 @@ mod tests {
y[: Literal[1]] = x y[: Literal[1]] = x
z[: int] = i(1) z[: int] = i(1)
w[: int] = z w[: int] = z
aa = b'foo'
bb[: Literal[b"foo"]] = aa
--------------------------------------------- ---------------------------------------------
info[inlay-hint-location]: Inlay Hint Target info[inlay-hint-location]: Inlay Hint Target
@ -630,12 +634,12 @@ mod tests {
350 | int(x, base=10) -> integer 350 | int(x, base=10) -> integer
| |
info: Source info: Source
--> main2.py:7:5 --> main2.py:6:13
| |
5 | x = 1 5 | x = 1
6 | y[: Literal[1]] = x 6 | y[: Literal[1]] = x
| ^
7 | z[: int] = i(1) 7 | z[: int] = i(1)
| ^^^
8 | w[: int] = z 8 | w[: int] = z
| |
@ -649,13 +653,71 @@ mod tests {
350 | int(x, base=10) -> integer 350 | int(x, base=10) -> integer
| |
info: Source info: Source
--> main2.py:8:5 --> main2.py:7:5
| |
5 | x = 1
6 | y[: Literal[1]] = x 6 | y[: Literal[1]] = x
7 | z[: int] = i(1) 7 | z[: int] = i(1)
8 | w[: int] = z
| ^^^ | ^^^
8 | w[: int] = z
9 | aa = b'foo'
| |
info[inlay-hint-location]: Inlay Hint Target
--> stdlib/builtins.pyi:348:7
|
347 | @disjoint_base
348 | class int:
| ^^^
349 | """int([x]) -> integer
350 | int(x, base=10) -> integer
|
info: Source
--> main2.py:8:5
|
6 | y[: Literal[1]] = x
7 | z[: int] = i(1)
8 | w[: int] = z
| ^^^
9 | aa = b'foo'
10 | bb[: Literal[b"foo"]] = aa
|
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:10:6
|
8 | w[: int] = z
9 | aa = b'foo'
10 | bb[: Literal[b"foo"]] = aa
| ^^^^^^^
|
info[inlay-hint-location]: Inlay Hint Target
--> stdlib/builtins.pyi:1448:7
|
1447 | @disjoint_base
1448 | class bytes(Sequence[int]):
| ^^^^^
1449 | """bytes(iterable_of_ints) -> bytes
1450 | bytes(string, encoding[, errors]) -> bytes
|
info: Source
--> main2.py:10:14
|
8 | w[: int] = z
9 | aa = b'foo'
10 | bb[: Literal[b"foo"]] = aa
| ^^^^^^
|
"#); "#);
} }
@ -706,6 +768,25 @@ mod tests {
10 | x4[: int], y4[: str] = (x3, y3) 10 | x4[: int], y4[: str] = (x3, y3)
| |
info[inlay-hint-location]: Inlay Hint Target
--> stdlib/builtins.pyi:348:7
|
347 | @disjoint_base
348 | class int:
| ^^^
349 | """int([x]) -> integer
350 | int(x, base=10) -> integer
|
info: Source
--> main2.py:8:14
|
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/typing.pyi:351:1 --> stdlib/typing.pyi:351:1
| |
@ -725,6 +806,25 @@ mod tests {
10 | x4[: int], y4[: str] = (x3, y3) 10 | x4[: int], y4[: str] = (x3, y3)
| |
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:8:32
|
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
| |
@ -848,6 +948,25 @@ mod tests {
10 | x4[: int], y4[: str] = x3, y3 10 | x4[: int], y4[: str] = x3, y3
| |
info[inlay-hint-location]: Inlay Hint Target
--> stdlib/builtins.pyi:348:7
|
347 | @disjoint_base
348 | class int:
| ^^^
349 | """int([x]) -> integer
350 | int(x, base=10) -> integer
|
info: Source
--> main2.py:8:14
|
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/typing.pyi:351:1 --> stdlib/typing.pyi:351:1
| |
@ -867,6 +986,25 @@ mod tests {
10 | x4[: int], y4[: str] = x3, y3 10 | x4[: int], y4[: str] = x3, y3
| |
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:8:32
|
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
| |
@ -1008,6 +1146,25 @@ mod tests {
10 | w[: tuple[int, str]] = z 10 | w[: tuple[int, str]] = z
| |
info[inlay-hint-location]: Inlay Hint Target
--> stdlib/builtins.pyi:348:7
|
347 | @disjoint_base
348 | class int:
| ^^^
349 | """int([x]) -> integer
350 | int(x, base=10) -> integer
|
info: Source
--> main2.py:8:19
|
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/typing.pyi:351:1 --> stdlib/typing.pyi:351:1
| |
@ -1027,6 +1184,25 @@ mod tests {
10 | w[: tuple[int, str]] = z 10 | w[: tuple[int, str]] = z
| |
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:8:31
|
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:2695:7 --> stdlib/builtins.pyi:2695:7
| |
@ -1183,6 +1359,25 @@ mod tests {
10 | x4[: int], (y4[: str], z4[: int]) = (x3, (y3, z3)) 10 | x4[: int], (y4[: str], z4[: int]) = (x3, (y3, z3))
| |
info[inlay-hint-location]: Inlay Hint Target
--> stdlib/builtins.pyi:348:7
|
347 | @disjoint_base
348 | class int:
| ^^^
349 | """int([x]) -> integer
350 | int(x, base=10) -> integer
|
info: Source
--> main2.py:8:14
|
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/typing.pyi:351:1 --> stdlib/typing.pyi:351:1
| |
@ -1202,6 +1397,25 @@ mod tests {
10 | x4[: int], (y4[: str], z4[: int]) = (x3, (y3, z3)) 10 | x4[: int], (y4[: str], z4[: int]) = (x3, (y3, z3))
| |
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:8:33
|
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/typing.pyi:351:1 --> stdlib/typing.pyi:351:1
| |
@ -1221,6 +1435,25 @@ mod tests {
10 | x4[: int], (y4[: str], z4[: int]) = (x3, (y3, z3)) 10 | x4[: int], (y4[: str], z4[: int]) = (x3, (y3, z3))
| |
info[inlay-hint-location]: Inlay Hint Target
--> stdlib/builtins.pyi:348:7
|
347 | @disjoint_base
348 | class int:
| ^^^
349 | """int([x]) -> integer
350 | int(x, base=10) -> integer
|
info: Source
--> main2.py:8:55
|
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
| |
@ -1375,6 +1608,25 @@ mod tests {
8 | w[: int] = z 8 | w[: int] = z
| |
info[inlay-hint-location]: Inlay Hint Target
--> stdlib/builtins.pyi:348:7
|
347 | @disjoint_base
348 | class int:
| ^^^
349 | """int([x]) -> integer
350 | int(x, base=10) -> integer
|
info: Source
--> main2.py:6:13
|
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
| |
@ -4988,6 +5240,78 @@ mod tests {
| ^^^^^^^ | ^^^^^^^
| |
info[inlay-hint-location]: Inlay Hint Target
--> stdlib/builtins.pyi:348:7
|
347 | @disjoint_base
348 | class int:
| ^^^
349 | """int([x]) -> integer
350 | int(x, base=10) -> integer
|
info: Source
--> main2.py:13:17
|
11 | else:
12 | x = None
13 | y[: Literal[1, 2, 3, "hello"] | None] = x
| ^
|
info[inlay-hint-location]: Inlay Hint Target
--> stdlib/builtins.pyi:348:7
|
347 | @disjoint_base
348 | class int:
| ^^^
349 | """int([x]) -> integer
350 | int(x, base=10) -> integer
|
info: Source
--> main2.py:13:20
|
11 | else:
12 | x = None
13 | y[: Literal[1, 2, 3, "hello"] | None] = x
| ^
|
info[inlay-hint-location]: Inlay Hint Target
--> stdlib/builtins.pyi:348:7
|
347 | @disjoint_base
348 | class int:
| ^^^
349 | """int([x]) -> integer
350 | int(x, base=10) -> integer
|
info: Source
--> main2.py:13:23
|
11 | else:
12 | x = None
13 | y[: Literal[1, 2, 3, "hello"] | None] = x
| ^
|
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:13:26
|
11 | else:
12 | x = None
13 | y[: Literal[1, 2, 3, "hello"] | None] = x
| ^^^^^^^
|
info[inlay-hint-location]: Inlay Hint Target info[inlay-hint-location]: Inlay Hint Target
--> stdlib/types.pyi:950:11 --> stdlib/types.pyi:950:11
| |
@ -5123,6 +5447,45 @@ mod tests {
"#); "#);
} }
#[test]
fn test_property_literal_type() {
let mut test = inlay_hint_test(
r"
class F:
@property
def whatever(self): ...
ab = F.whatever",
);
assert_snapshot!(test.inlay_hints(), @r"
class F:
@property
def whatever(self): ...
ab[: property] = F.whatever
---------------------------------------------
info[inlay-hint-location]: Inlay Hint Target
--> main.py:4:9
|
2 | class F:
3 | @property
4 | def whatever(self): ...
| ^^^^^^^^
5 |
6 | ab = F.whatever
|
info: Source
--> main2.py:6:6
|
4 | def whatever(self): ...
5 |
6 | ab[: property] = F.whatever
| ^^^^^^^^
|
");
}
#[test] #[test]
fn test_complex_parameter_combinations() { fn test_complex_parameter_combinations() {
let mut test = inlay_hint_test( let mut test = inlay_hint_test(

View File

@ -7601,6 +7601,11 @@ impl<'db> Type<'db> {
Self::TypeAlias(alias) => alias.value_type(db).definition(db), Self::TypeAlias(alias) => alias.value_type(db).definition(db),
Self::NewTypeInstance(newtype) => Some(TypeDefinition::NewType(newtype.definition(db))), Self::NewTypeInstance(newtype) => Some(TypeDefinition::NewType(newtype.definition(db))),
Self::PropertyInstance(property) => property
.getter(db)
.and_then(|getter|getter.definition(db))
.or_else(||property.setter(db).and_then(|setter|setter.definition(db))),
Self::StringLiteral(_) Self::StringLiteral(_)
| Self::BooleanLiteral(_) | Self::BooleanLiteral(_)
| Self::LiteralString | Self::LiteralString
@ -7612,7 +7617,6 @@ impl<'db> Type<'db> {
| Self::WrapperDescriptor(_) | Self::WrapperDescriptor(_)
| Self::DataclassDecorator(_) | Self::DataclassDecorator(_)
| Self::DataclassTransformer(_) | Self::DataclassTransformer(_)
| Self::PropertyInstance(_)
| Self::BoundSuper(_) => self.to_meta_type(db).definition(db), | Self::BoundSuper(_) => self.to_meta_type(db).definition(db),
Self::TypeVar(bound_typevar) => Some(TypeDefinition::TypeVar(bound_typevar.typevar(db).definition(db)?)), Self::TypeVar(bound_typevar) => Some(TypeDefinition::TypeVar(bound_typevar.typevar(db).definition(db)?)),
@ -7622,20 +7626,22 @@ impl<'db> Type<'db> {
Protocol::Synthesized(_) => None, Protocol::Synthesized(_) => None,
}, },
Type::TypedDict(typed_dict) => { Self::TypedDict(typed_dict) => {
Some(TypeDefinition::Class(typed_dict.defining_class().definition(db))) Some(TypeDefinition::Class(typed_dict.defining_class().definition(db)))
} }
Self::Union(_) | Self::Intersection(_) => None, Self::Union(_) | Self::Intersection(_) => None,
Self::SpecialForm(special_form) => special_form.definition(db), Self::SpecialForm(special_form) => special_form.definition(db),
Self::Never => Type::SpecialForm(SpecialFormType::Never).definition(db),
Self::Dynamic(DynamicType::Any) => Type::SpecialForm(SpecialFormType::Any).definition(db),
Self::Dynamic(DynamicType::Unknown) => Type::SpecialForm(SpecialFormType::Unknown).definition(db),
Self::AlwaysTruthy => Type::SpecialForm(SpecialFormType::AlwaysTruthy).definition(db),
Self::AlwaysFalsy => Type::SpecialForm(SpecialFormType::AlwaysFalsy).definition(db),
// These types have no definition // These types have no definition
Self::Dynamic(_) Self::Dynamic(DynamicType::Divergent(_) | DynamicType::Todo(_) | DynamicType::TodoTypeAlias | DynamicType::TodoUnpack)
| Self::Never
| Self::Callable(_) | Self::Callable(_)
| Self::AlwaysTruthy
| Self::AlwaysFalsy
| Self::TypeIs(_) => None, | Self::TypeIs(_) => None,
} }
} }

View File

@ -23,9 +23,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, DynamicType, IntersectionType, KnownBoundMethodType, BoundTypeVarIdentity, CallableType, IntersectionType, KnownBoundMethodType, KnownClass,
KnownClass, MaterializationKind, Protocol, ProtocolInstanceType, SpecialFormType, MaterializationKind, Protocol, ProtocolInstanceType, SpecialFormType, StringLiteralType,
StringLiteralType, SubclassOfInner, Type, UnionType, WrapperDescriptorKind, visitor, SubclassOfInner, Type, UnionType, WrapperDescriptorKind, visitor,
}; };
use ruff_db::parsed::parsed_module; use ruff_db::parsed::parsed_module;
@ -611,9 +611,7 @@ 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) => dynamic Type::Dynamic(dynamic) => write!(f.with_detail(TypeDetail::Type(self.ty)), "{dynamic}"),
.display_with(self.db, self.settings.clone())
.fmt_detailed(f),
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);
@ -662,7 +660,9 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
f.write_char('>') f.write_char('>')
} }
}, },
Type::PropertyInstance(_) => f.write_str("property"), Type::PropertyInstance(_) => f
.with_detail(TypeDetail::Type(self.ty))
.write_str("property"),
Type::ModuleLiteral(module) => { Type::ModuleLiteral(module) => {
write!( write!(
f.with_detail(TypeDetail::Type(self.ty)), f.with_detail(TypeDetail::Type(self.ty)),
@ -709,9 +709,10 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
f.with_detail(TypeDetail::Type(KnownClass::Type.to_class_literal(self.db))) f.with_detail(TypeDetail::Type(KnownClass::Type.to_class_literal(self.db)))
.write_str("type")?; .write_str("type")?;
f.write_char('[')?; f.write_char('[')?;
dynamic write!(
.display_with(self.db, self.settings.clone()) f.with_detail(TypeDetail::Type(Type::Dynamic(dynamic))),
.fmt_detailed(f)?; "{dynamic}"
)?;
f.write_char(']') f.write_char(']')
} }
}, },
@ -847,18 +848,33 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
Type::Intersection(intersection) => intersection Type::Intersection(intersection) => intersection
.display_with(self.db, self.settings.clone()) .display_with(self.db, self.settings.clone())
.fmt_detailed(f), .fmt_detailed(f),
Type::IntLiteral(n) => write!(f, "{n}"), Type::IntLiteral(n) => write!(f.with_detail(TypeDetail::Type(self.ty)), "{n}"),
Type::BooleanLiteral(boolean) => f.write_str(if boolean { "True" } else { "False" }), Type::BooleanLiteral(boolean) => f
.with_detail(TypeDetail::Type(self.ty))
.write_str(if boolean { "True" } else { "False" }),
Type::StringLiteral(string) => { Type::StringLiteral(string) => {
write!(f, "{}", string.display_with(self.db, self.settings.clone())) write!(
f.with_detail(TypeDetail::Type(self.ty)),
"{}",
string.display_with(self.db, self.settings.clone())
)
} }
// an alternative would be to use `Type::SpecialForm(SpecialFormType::LiteralString)` here,
// which would mean users would be able to jump to the definition of `LiteralString` from the
// inlay hint, but that seems less useful than the definition of `str` for a variable that is
// inferred as an *inhabitant* of `LiteralString` (since that variable will just be a string
// at runtime)
Type::LiteralString => f Type::LiteralString => f
.with_detail(TypeDetail::Type(self.ty)) .with_detail(TypeDetail::Type(self.ty))
.write_str("LiteralString"), .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);
escape.bytes_repr(TripleQuotes::No).write(f) write!(
f.with_detail(TypeDetail::Type(self.ty)),
"{}",
escape.bytes_repr(TripleQuotes::No)
)
} }
Type::EnumLiteral(enum_literal) => { Type::EnumLiteral(enum_literal) => {
enum_literal enum_literal
@ -1162,48 +1178,6 @@ impl Display for DisplayFunctionType<'_> {
} }
} }
impl<'db> DynamicType<'db> {
fn display_with<'a>(
&'a self,
db: &'db dyn Db,
settings: DisplaySettings<'db>,
) -> DisplayDynamicType<'a, 'db> {
DisplayDynamicType {
dynamic_type: self,
db,
settings,
}
}
}
struct DisplayDynamicType<'a, 'db> {
dynamic_type: &'a DynamicType<'db>,
#[allow(dead_code)]
db: &'db dyn Db,
#[allow(dead_code)]
settings: DisplaySettings<'db>,
}
impl<'db> FmtDetailed<'db> for DisplayDynamicType<'_, 'db> {
fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result {
match self.dynamic_type {
DynamicType::Any => write!(
f.with_detail(TypeDetail::Type(Type::SpecialForm(SpecialFormType::Any))),
"{}",
self.dynamic_type,
),
DynamicType::Unknown => write!(
f.with_detail(TypeDetail::Type(Type::SpecialForm(
SpecialFormType::Unknown
))),
"{}",
self.dynamic_type,
),
_ => write!(f, "{}", self.dynamic_type),
}
}
}
impl<'db> GenericAlias<'db> { impl<'db> GenericAlias<'db> {
pub(crate) fn display(self, db: &'db dyn Db) -> DisplayGenericAlias<'db> { pub(crate) fn display(self, db: &'db dyn Db) -> DisplayGenericAlias<'db> {
self.display_with(db, DisplaySettings::default()) self.display_with(db, DisplaySettings::default())
@ -1237,16 +1211,20 @@ impl<'db> FmtDetailed<'db> for DisplayGenericAlias<'db> {
.display_with(self.db, self.settings.clone()) .display_with(self.db, self.settings.clone())
.fmt_detailed(f) .fmt_detailed(f)
} else { } else {
let prefix = match self.specialization.materialization_kind(self.db) { let prefix_details = match self.specialization.materialization_kind(self.db) {
None => "", None => None,
Some(MaterializationKind::Top) => "Top[", Some(MaterializationKind::Top) => Some(("Top", SpecialFormType::Top)),
Some(MaterializationKind::Bottom) => "Bottom[", Some(MaterializationKind::Bottom) => Some(("Bottom", SpecialFormType::Bottom)),
}; };
let suffix = match self.specialization.materialization_kind(self.db) { let suffix = match self.specialization.materialization_kind(self.db) {
None => "", None => "",
Some(_) => "]", Some(_) => "]",
}; };
f.write_str(prefix)?; if let Some((name, form)) = prefix_details {
f.with_detail(TypeDetail::Type(Type::SpecialForm(form)))
.write_str(name)?;
f.write_char('[')?;
}
self.origin self.origin
.display_with(self.db, self.settings.clone()) .display_with(self.db, self.settings.clone())
.fmt_detailed(f)?; .fmt_detailed(f)?;