mirror of https://github.com/astral-sh/ruff
[ty] Add more random TypeDetails and tests (#21546)
This commit is contained in:
parent
290a5720cb
commit
1b28fc1f14
|
|
@ -971,6 +971,24 @@ mod tests {
|
|||
w[: tuple[int, str]] = z
|
||||
|
||||
---------------------------------------------
|
||||
info[inlay-hint-location]: Inlay Hint Target
|
||||
--> stdlib/builtins.pyi:2695:7
|
||||
|
|
||||
2694 | @disjoint_base
|
||||
2695 | class tuple(Sequence[_T_co]):
|
||||
| ^^^^^
|
||||
2696 | """Built-in immutable sequence.
|
||||
|
|
||||
info: Source
|
||||
--> main2.py:8:5
|
||||
|
|
||||
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
|
||||
|
|
||||
|
|
@ -1009,6 +1027,24 @@ mod tests {
|
|||
10 | w[: tuple[int, str]] = z
|
||||
|
|
||||
|
||||
info[inlay-hint-location]: Inlay Hint Target
|
||||
--> stdlib/builtins.pyi:2695:7
|
||||
|
|
||||
2694 | @disjoint_base
|
||||
2695 | class tuple(Sequence[_T_co]):
|
||||
| ^^^^^
|
||||
2696 | """Built-in immutable sequence.
|
||||
|
|
||||
info: Source
|
||||
--> main2.py:9:5
|
||||
|
|
||||
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/builtins.pyi:348:7
|
||||
|
|
||||
|
|
@ -1047,6 +1083,23 @@ mod tests {
|
|||
10 | w[: tuple[int, str]] = z
|
||||
|
|
||||
|
||||
info[inlay-hint-location]: Inlay Hint Target
|
||||
--> stdlib/builtins.pyi:2695:7
|
||||
|
|
||||
2694 | @disjoint_base
|
||||
2695 | class tuple(Sequence[_T_co]):
|
||||
| ^^^^^
|
||||
2696 | """Built-in immutable sequence.
|
||||
|
|
||||
info: Source
|
||||
--> main2.py:10:5
|
||||
|
|
||||
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/builtins.pyi:348:7
|
||||
|
|
||||
|
|
@ -2343,7 +2396,7 @@ mod tests {
|
|||
"#,
|
||||
);
|
||||
|
||||
assert_snapshot!(test.inlay_hints(), @r"
|
||||
assert_snapshot!(test.inlay_hints(), @r#"
|
||||
class MyClass:
|
||||
def __init__(self):
|
||||
self.x: int = 1
|
||||
|
|
@ -2373,6 +2426,24 @@ mod tests {
|
|||
8 | a[: MyClass], b[: MyClass] = MyClass(), MyClass()
|
||||
|
|
||||
|
||||
info[inlay-hint-location]: Inlay Hint Target
|
||||
--> stdlib/builtins.pyi:2695:7
|
||||
|
|
||||
2694 | @disjoint_base
|
||||
2695 | class tuple(Sequence[_T_co]):
|
||||
| ^^^^^
|
||||
2696 | """Built-in immutable sequence.
|
||||
|
|
||||
info: Source
|
||||
--> main2.py:7:5
|
||||
|
|
||||
6 | x[: MyClass] = MyClass()
|
||||
7 | y[: tuple[MyClass, MyClass]] = (MyClass(), MyClass())
|
||||
| ^^^^^
|
||||
8 | a[: MyClass], b[: MyClass] = MyClass(), MyClass()
|
||||
9 | c[: MyClass], d[: MyClass] = (MyClass(), MyClass())
|
||||
|
|
||||
|
||||
info[inlay-hint-location]: Inlay Hint Target
|
||||
--> main.py:2:7
|
||||
|
|
||||
|
|
@ -2478,7 +2549,7 @@ mod tests {
|
|||
9 | c[: MyClass], d[: MyClass] = (MyClass(), MyClass())
|
||||
| ^^^^^^^
|
||||
|
|
||||
");
|
||||
"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -2527,6 +2598,25 @@ mod tests {
|
|||
5 | self.y[: tuple[U@MyClass, U@MyClass]] = y
|
||||
|
|
||||
|
||||
info[inlay-hint-location]: Inlay Hint Target
|
||||
--> stdlib/builtins.pyi:2695:7
|
||||
|
|
||||
2694 | @disjoint_base
|
||||
2695 | class tuple(Sequence[_T_co]):
|
||||
| ^^^^^
|
||||
2696 | """Built-in immutable sequence.
|
||||
|
|
||||
info: Source
|
||||
--> main2.py:5:18
|
||||
|
|
||||
3 | def __init__(self, x: list[T], y: tuple[U, U]):
|
||||
4 | self.x[: list[T@MyClass]] = x
|
||||
5 | self.y[: tuple[U@MyClass, U@MyClass]] = y
|
||||
| ^^^^^
|
||||
6 |
|
||||
7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b"))
|
||||
|
|
||||
|
||||
info[inlay-hint-location]: Inlay Hint Target
|
||||
--> main.py:2:7
|
||||
|
|
||||
|
|
@ -2646,6 +2736,24 @@ mod tests {
|
|||
9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b…
|
||||
|
|
||||
|
||||
info[inlay-hint-location]: Inlay Hint Target
|
||||
--> stdlib/builtins.pyi:2695:7
|
||||
|
|
||||
2694 | @disjoint_base
|
||||
2695 | class tuple(Sequence[_T_co]):
|
||||
| ^^^^^
|
||||
2696 | """Built-in immutable sequence.
|
||||
|
|
||||
info: Source
|
||||
--> main2.py:8:5
|
||||
|
|
||||
7 | x[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b"))
|
||||
8 | y[: tuple[MyClass[Unknown | int, str], MyClass[Unknown | int, str]]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a",…
|
||||
| ^^^^^
|
||||
9 | a[: MyClass[Unknown | int, str]], b[: MyClass[Unknown | int, str]] = MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "b…
|
||||
10 | c[: MyClass[Unknown | int, str]], d[: MyClass[Unknown | int, str]] = (MyClass([x=][42], [y=]("a", "b")), MyClass([x=][42], [y=]("a", "…
|
||||
|
|
||||
|
||||
info[inlay-hint-location]: Inlay Hint Target
|
||||
--> main.py:2:7
|
||||
|
|
||||
|
|
@ -4830,6 +4938,191 @@ mod tests {
|
|||
"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_literal_group() {
|
||||
let mut test = inlay_hint_test(
|
||||
r#"
|
||||
def branch(cond: int):
|
||||
if cond < 10:
|
||||
x = 1
|
||||
elif cond < 20:
|
||||
x = 2
|
||||
elif cond < 30:
|
||||
x = 3
|
||||
elif cond < 40:
|
||||
x = "hello"
|
||||
else:
|
||||
x = None
|
||||
y = x"#,
|
||||
);
|
||||
|
||||
assert_snapshot!(test.inlay_hints(), @r#"
|
||||
def branch(cond: int):
|
||||
if cond < 10:
|
||||
x = 1
|
||||
elif cond < 20:
|
||||
x = 2
|
||||
elif cond < 30:
|
||||
x = 3
|
||||
elif cond < 40:
|
||||
x = "hello"
|
||||
else:
|
||||
x = None
|
||||
y[: Literal[1, 2, 3, "hello"] | None] = x
|
||||
---------------------------------------------
|
||||
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:13:9
|
||||
|
|
||||
11 | else:
|
||||
12 | x = None
|
||||
13 | y[: Literal[1, 2, 3, "hello"] | None] = x
|
||||
| ^^^^^^^
|
||||
|
|
||||
|
||||
info[inlay-hint-location]: Inlay Hint Target
|
||||
--> stdlib/types.pyi:950:11
|
||||
|
|
||||
948 | if sys.version_info >= (3, 10):
|
||||
949 | @final
|
||||
950 | class NoneType:
|
||||
| ^^^^^^^^
|
||||
951 | """The type of the None singleton."""
|
||||
|
|
||||
info: Source
|
||||
--> main2.py:13:37
|
||||
|
|
||||
11 | else:
|
||||
12 | x = None
|
||||
13 | y[: Literal[1, 2, 3, "hello"] | None] = x
|
||||
| ^^^^
|
||||
|
|
||||
"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generic_alias() {
|
||||
let mut test = inlay_hint_test(
|
||||
r"
|
||||
class Foo[T]: ...
|
||||
|
||||
a = Foo[int]",
|
||||
);
|
||||
|
||||
assert_snapshot!(test.inlay_hints(), @r#"
|
||||
class Foo[T]: ...
|
||||
|
||||
a[: <class 'Foo[int]'>] = Foo[int]
|
||||
---------------------------------------------
|
||||
info[inlay-hint-location]: Inlay Hint Target
|
||||
--> main.py:2:7
|
||||
|
|
||||
2 | class Foo[T]: ...
|
||||
| ^^^
|
||||
3 |
|
||||
4 | a = Foo[int]
|
||||
|
|
||||
info: Source
|
||||
--> main2.py:4:13
|
||||
|
|
||||
2 | class Foo[T]: ...
|
||||
3 |
|
||||
4 | a[: <class 'Foo[int]'>] = Foo[int]
|
||||
| ^^^
|
||||
|
|
||||
|
||||
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:4:17
|
||||
|
|
||||
2 | class Foo[T]: ...
|
||||
3 |
|
||||
4 | a[: <class 'Foo[int]'>] = Foo[int]
|
||||
| ^^^
|
||||
|
|
||||
"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_subclass_type() {
|
||||
let mut test = inlay_hint_test(
|
||||
r"
|
||||
def f(x: list[str]):
|
||||
y = type(x)",
|
||||
);
|
||||
|
||||
assert_snapshot!(test.inlay_hints(), @r#"
|
||||
def f(x: list[str]):
|
||||
y[: type[list[str]]] = type(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(x: list[str]):
|
||||
3 | y[: type[list[str]]] = type(x)
|
||||
| ^^^^
|
||||
|
|
||||
|
||||
info[inlay-hint-location]: Inlay Hint Target
|
||||
--> stdlib/builtins.pyi:2802:7
|
||||
|
|
||||
2801 | @disjoint_base
|
||||
2802 | class list(MutableSequence[_T]):
|
||||
| ^^^^
|
||||
2803 | """Built-in mutable sequence.
|
||||
|
|
||||
info: Source
|
||||
--> main2.py:3:14
|
||||
|
|
||||
2 | def f(x: list[str]):
|
||||
3 | y[: type[list[str]]] = type(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:3:19
|
||||
|
|
||||
2 | def f(x: list[str]):
|
||||
3 | y[: type[list[str]]] = type(x)
|
||||
| ^^^
|
||||
|
|
||||
"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_complex_parameter_combinations() {
|
||||
let mut test = inlay_hint_test(
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ use std::collections::hash_map::Entry;
|
|||
use std::fmt::{self, Display, Formatter, Write};
|
||||
use std::rc::Rc;
|
||||
|
||||
use ruff_db::display::FormatterJoinExtension;
|
||||
use ruff_db::files::FilePath;
|
||||
use ruff_db::source::line_index;
|
||||
use ruff_python_ast::str::{Quote, TripleQuotes};
|
||||
|
|
@ -612,19 +611,9 @@ impl Display for DisplayRepresentation<'_> {
|
|||
impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
|
||||
fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result {
|
||||
match self.ty {
|
||||
Type::Dynamic(dynamic) => match dynamic {
|
||||
DynamicType::Any => write!(
|
||||
f.with_detail(TypeDetail::Type(Type::SpecialForm(SpecialFormType::Any))),
|
||||
"{dynamic}"
|
||||
),
|
||||
DynamicType::Unknown => write!(
|
||||
f.with_detail(TypeDetail::Type(Type::SpecialForm(
|
||||
SpecialFormType::Unknown
|
||||
))),
|
||||
"{dynamic}"
|
||||
),
|
||||
_ => write!(f, "{dynamic}"),
|
||||
},
|
||||
Type::Dynamic(dynamic) => dynamic
|
||||
.display_with(self.db, self.settings.clone())
|
||||
.fmt_detailed(f),
|
||||
Type::Never => f.with_detail(TypeDetail::Type(self.ty)).write_str("Never"),
|
||||
Type::NominalInstance(instance) => {
|
||||
let class = instance.class(self.db);
|
||||
|
|
@ -681,32 +670,50 @@ impl<'db> FmtDetailed<'db> for DisplayRepresentation<'db> {
|
|||
module.module(self.db).name(self.db)
|
||||
)
|
||||
}
|
||||
Type::ClassLiteral(class) => write!(
|
||||
f.with_detail(TypeDetail::Type(self.ty)),
|
||||
"<class '{}'>",
|
||||
class.display_with(self.db, self.settings.clone())
|
||||
),
|
||||
Type::GenericAlias(generic) => write!(
|
||||
f.with_detail(TypeDetail::Type(self.ty)),
|
||||
"<class '{}'>",
|
||||
generic.display_with(self.db, self.settings.singleline())
|
||||
),
|
||||
Type::ClassLiteral(class) => {
|
||||
let mut f = f.with_detail(TypeDetail::Type(self.ty));
|
||||
f.write_str("<class '")?;
|
||||
class
|
||||
.display_with(self.db, self.settings.clone())
|
||||
.fmt_detailed(&mut f)?;
|
||||
f.write_str("'>")
|
||||
}
|
||||
Type::GenericAlias(generic) => {
|
||||
let mut f = f.with_detail(TypeDetail::Type(self.ty));
|
||||
f.write_str("<class '")?;
|
||||
generic
|
||||
.display_with(self.db, self.settings.clone())
|
||||
.fmt_detailed(&mut f)?;
|
||||
f.write_str("'>")
|
||||
}
|
||||
Type::SubclassOf(subclass_of_ty) => match subclass_of_ty.subclass_of() {
|
||||
SubclassOfInner::Class(ClassType::NonGeneric(class)) => {
|
||||
f.write_str("type[")?;
|
||||
f.with_detail(TypeDetail::Type(KnownClass::Type.to_class_literal(self.db)))
|
||||
.write_str("type")?;
|
||||
f.write_char('[')?;
|
||||
class
|
||||
.display_with(self.db, self.settings.clone())
|
||||
.fmt_detailed(f)?;
|
||||
f.write_str("]")
|
||||
f.write_char(']')
|
||||
}
|
||||
SubclassOfInner::Class(ClassType::Generic(alias)) => {
|
||||
f.write_str("type[")?;
|
||||
f.with_detail(TypeDetail::Type(KnownClass::Type.to_class_literal(self.db)))
|
||||
.write_str("type")?;
|
||||
f.write_char('[')?;
|
||||
alias
|
||||
.display_with(self.db, self.settings.clone())
|
||||
.fmt_detailed(f)?;
|
||||
f.write_str("]")
|
||||
f.write_char(']')
|
||||
}
|
||||
SubclassOfInner::Dynamic(dynamic) => {
|
||||
f.with_detail(TypeDetail::Type(KnownClass::Type.to_class_literal(self.db)))
|
||||
.write_str("type")?;
|
||||
f.write_char('[')?;
|
||||
dynamic
|
||||
.display_with(self.db, self.settings.clone())
|
||||
.fmt_detailed(f)?;
|
||||
f.write_char(']')
|
||||
}
|
||||
SubclassOfInner::Dynamic(dynamic) => write!(f, "type[{dynamic}]"),
|
||||
},
|
||||
Type::SpecialForm(special_form) => {
|
||||
write!(f.with_detail(TypeDetail::Type(self.ty)), "{special_form}")
|
||||
|
|
@ -962,7 +969,11 @@ pub(crate) struct DisplayTuple<'a, 'db> {
|
|||
|
||||
impl<'db> FmtDetailed<'db> for DisplayTuple<'_, 'db> {
|
||||
fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result {
|
||||
f.write_str("tuple[")?;
|
||||
f.with_detail(TypeDetail::Type(
|
||||
KnownClass::Tuple.to_class_literal(self.db),
|
||||
))
|
||||
.write_str("tuple")?;
|
||||
f.write_char('[')?;
|
||||
match self.tuple {
|
||||
TupleSpec::Fixed(tuple) => {
|
||||
let elements = tuple.elements_slice();
|
||||
|
|
@ -998,7 +1009,13 @@ impl<'db> FmtDetailed<'db> for DisplayTuple<'_, 'db> {
|
|||
f.write_str(", ")?;
|
||||
}
|
||||
if !tuple.prefix.is_empty() || !tuple.suffix.is_empty() {
|
||||
f.write_str("*tuple[")?;
|
||||
f.write_char('*')?;
|
||||
// Might as well link the type again here too
|
||||
f.with_detail(TypeDetail::Type(
|
||||
KnownClass::Tuple.to_class_literal(self.db),
|
||||
))
|
||||
.write_str("tuple")?;
|
||||
f.write_char('[')?;
|
||||
}
|
||||
tuple
|
||||
.variable
|
||||
|
|
@ -1119,7 +1136,10 @@ impl<'db> FmtDetailed<'db> for DisplayFunctionType<'db> {
|
|||
signatures => {
|
||||
// TODO: How to display overloads?
|
||||
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 mut join = f.join(separator);
|
||||
|
|
@ -1142,6 +1162,48 @@ 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> {
|
||||
pub(crate) fn display(self, db: &'db dyn Db) -> DisplayGenericAlias<'db> {
|
||||
self.display_with(db, DisplaySettings::default())
|
||||
|
|
@ -1463,7 +1525,10 @@ impl<'db> FmtDetailed<'db> for DisplayCallableType<'_, 'db> {
|
|||
signatures => {
|
||||
// TODO: How to display overloads?
|
||||
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 mut join = f.join(separator);
|
||||
|
|
@ -1711,8 +1776,8 @@ struct DisplayOmitted {
|
|||
plural: &'static str,
|
||||
}
|
||||
|
||||
impl Display for DisplayOmitted {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
impl<'db> FmtDetailed<'db> for DisplayOmitted {
|
||||
fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result {
|
||||
let noun = if self.count == 1 {
|
||||
self.singular
|
||||
} else {
|
||||
|
|
@ -1722,6 +1787,12 @@ impl Display for DisplayOmitted {
|
|||
}
|
||||
}
|
||||
|
||||
impl Display for DisplayOmitted {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
self.fmt_detailed(&mut TypeWriter::Formatter(f))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> UnionType<'db> {
|
||||
fn display_with<'a>(
|
||||
&'a self,
|
||||
|
|
@ -1774,15 +1845,7 @@ impl<'db> FmtDetailed<'db> for DisplayUnionType<'_, 'db> {
|
|||
assert_ne!(total_entries, 0);
|
||||
|
||||
// Done manually because we have a mix of FmtDetailed and Display
|
||||
let mut is_first = true;
|
||||
let mut write_join = |f: &mut TypeWriter<'_, '_, 'db>| {
|
||||
if !is_first {
|
||||
f.write_str(" | ")
|
||||
} else {
|
||||
is_first = false;
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
let mut join = f.join(" | ");
|
||||
|
||||
let display_limit =
|
||||
UNION_POLICY.display_limit(total_entries, self.settings.preserve_full_unions);
|
||||
|
|
@ -1798,45 +1861,33 @@ impl<'db> FmtDetailed<'db> for DisplayUnionType<'_, 'db> {
|
|||
if is_condensable(*element) {
|
||||
if let Some(condensed_types) = condensed_types.take() {
|
||||
displayed_entries += 1;
|
||||
write_join(f)?;
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
DisplayLiteralGroup {
|
||||
literals: condensed_types,
|
||||
db: self.db,
|
||||
settings: self.settings.singleline(),
|
||||
}
|
||||
)?;
|
||||
join.entry(&DisplayLiteralGroup {
|
||||
literals: condensed_types,
|
||||
db: self.db,
|
||||
settings: self.settings.singleline(),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
displayed_entries += 1;
|
||||
write_join(f)?;
|
||||
DisplayMaybeParenthesizedType {
|
||||
join.entry(&DisplayMaybeParenthesizedType {
|
||||
ty: *element,
|
||||
db: self.db,
|
||||
settings: self.settings.singleline(),
|
||||
}
|
||||
.fmt_detailed(f)?;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if !self.settings.preserve_full_unions {
|
||||
let omitted_entries = total_entries.saturating_sub(displayed_entries);
|
||||
if omitted_entries > 0 {
|
||||
write_join(f)?;
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
DisplayOmitted {
|
||||
count: omitted_entries,
|
||||
singular: "union element",
|
||||
plural: "union elements",
|
||||
}
|
||||
)?;
|
||||
join.entry(&DisplayOmitted {
|
||||
count: omitted_entries,
|
||||
singular: "union element",
|
||||
plural: "union elements",
|
||||
});
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
join.finish()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1862,9 +1913,13 @@ const LITERAL_POLICY: TruncationPolicy = TruncationPolicy {
|
|||
max_when_elided: 5,
|
||||
};
|
||||
|
||||
impl Display for DisplayLiteralGroup<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("Literal[")?;
|
||||
impl<'db> FmtDetailed<'db> for DisplayLiteralGroup<'db> {
|
||||
fn fmt_detailed(&self, f: &mut TypeWriter<'_, '_, 'db>) -> fmt::Result {
|
||||
f.with_detail(TypeDetail::Type(Type::SpecialForm(
|
||||
SpecialFormType::Literal,
|
||||
)))
|
||||
.write_str("Literal")?;
|
||||
f.write_char('[')?;
|
||||
|
||||
let total_entries = self.literals.len();
|
||||
|
||||
|
|
@ -1894,6 +1949,12 @@ impl Display for DisplayLiteralGroup<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Display for DisplayLiteralGroup<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
self.fmt_detailed(&mut TypeWriter::Formatter(f))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> IntersectionType<'db> {
|
||||
fn display_with<'a>(
|
||||
&'a self,
|
||||
|
|
|
|||
Loading…
Reference in New Issue