Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/display.rs')
-rw-r--r--crates/hir-ty/src/display.rs79
1 files changed, 64 insertions, 15 deletions
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index bd3eccfe43..f892a81519 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -7,8 +7,8 @@ use std::fmt::{self, Debug};
use base_db::CrateId;
use chalk_ir::{BoundVar, TyKind};
use hir_def::{
- adt::VariantData,
body,
+ data::adt::VariantData,
db::DefDatabase,
find_path,
generics::{TypeOrConstParamData, TypeParamProvenance},
@@ -23,6 +23,7 @@ use hir_expand::{hygiene::Hygiene, name::Name};
use intern::{Internable, Interned};
use itertools::Itertools;
use smallvec::SmallVec;
+use stdx::never;
use crate::{
db::HirDatabase,
@@ -64,6 +65,7 @@ pub struct HirFormatter<'a> {
curr_size: usize,
pub(crate) max_size: Option<usize>,
omit_verbose_types: bool,
+ closure_style: ClosureStyle,
display_target: DisplayTarget,
}
@@ -87,6 +89,7 @@ pub trait HirDisplay {
max_size: Option<usize>,
omit_verbose_types: bool,
display_target: DisplayTarget,
+ closure_style: ClosureStyle,
) -> HirDisplayWrapper<'a, Self>
where
Self: Sized,
@@ -95,7 +98,14 @@ pub trait HirDisplay {
!matches!(display_target, DisplayTarget::SourceCode { .. }),
"HirDisplayWrapper cannot fail with DisplaySourceCodeError, use HirDisplay::hir_fmt directly instead"
);
- HirDisplayWrapper { db, t: self, max_size, omit_verbose_types, display_target }
+ HirDisplayWrapper {
+ db,
+ t: self,
+ max_size,
+ omit_verbose_types,
+ display_target,
+ closure_style,
+ }
}
/// Returns a `Display`able type that is human-readable.
@@ -109,6 +119,7 @@ pub trait HirDisplay {
t: self,
max_size: None,
omit_verbose_types: false,
+ closure_style: ClosureStyle::ImplFn,
display_target: DisplayTarget::Diagnostics,
}
}
@@ -128,6 +139,7 @@ pub trait HirDisplay {
t: self,
max_size,
omit_verbose_types: true,
+ closure_style: ClosureStyle::ImplFn,
display_target: DisplayTarget::Diagnostics,
}
}
@@ -147,6 +159,7 @@ pub trait HirDisplay {
curr_size: 0,
max_size: None,
omit_verbose_types: false,
+ closure_style: ClosureStyle::ImplFn,
display_target: DisplayTarget::SourceCode { module_id },
}) {
Ok(()) => {}
@@ -166,6 +179,7 @@ pub trait HirDisplay {
t: self,
max_size: None,
omit_verbose_types: false,
+ closure_style: ClosureStyle::ImplFn,
display_target: DisplayTarget::Test,
}
}
@@ -253,7 +267,6 @@ impl DisplayTarget {
pub enum DisplaySourceCodeError {
PathNotFound,
UnknownType,
- Closure,
Generator,
}
@@ -274,9 +287,23 @@ pub struct HirDisplayWrapper<'a, T> {
t: &'a T,
max_size: Option<usize>,
omit_verbose_types: bool,
+ closure_style: ClosureStyle,
display_target: DisplayTarget,
}
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub enum ClosureStyle {
+ /// `impl FnX(i32, i32) -> i32`, where `FnX` is the most special trait between `Fn`, `FnMut`, `FnOnce` that the
+ /// closure implements. This is the default.
+ ImplFn,
+ /// `|i32, i32| -> i32`
+ RANotation,
+ /// `{closure#14825}`, useful for some diagnostics (like type mismatch) and internal usage.
+ ClosureWithId,
+ /// `…`, which is the `TYPE_HINT_TRUNCATION`
+ Hide,
+}
+
impl<T: HirDisplay> HirDisplayWrapper<'_, T> {
pub fn write_to<F: HirWrite>(&self, f: &mut F) -> Result<(), HirDisplayError> {
self.t.hir_fmt(&mut HirFormatter {
@@ -287,8 +314,14 @@ impl<T: HirDisplay> HirDisplayWrapper<'_, T> {
max_size: self.max_size,
omit_verbose_types: self.omit_verbose_types,
display_target: self.display_target,
+ closure_style: self.closure_style,
})
}
+
+ pub fn with_closure_style(mut self, c: ClosureStyle) -> Self {
+ self.closure_style = c;
+ self
+ }
}
impl<'a, T> fmt::Display for HirDisplayWrapper<'a, T>
@@ -919,26 +952,42 @@ impl HirDisplay for Ty {
}
}
}
- TyKind::Closure(.., substs) => {
- if f.display_target.is_source_code() {
- return Err(HirDisplayError::DisplaySourceCodeError(
- DisplaySourceCodeError::Closure,
- ));
+ TyKind::Closure(id, substs) => {
+ if f.display_target.is_source_code() && f.closure_style != ClosureStyle::ImplFn {
+ never!("Only `impl Fn` is valid for displaying closures in source code");
+ }
+ match f.closure_style {
+ ClosureStyle::Hide => return write!(f, "{TYPE_HINT_TRUNCATION}"),
+ ClosureStyle::ClosureWithId => {
+ return write!(f, "{{closure#{:?}}}", id.0.as_u32())
+ }
+ _ => (),
}
let sig = substs.at(Interner, 0).assert_ty_ref(Interner).callable_sig(db);
if let Some(sig) = sig {
+ let (def, _) = db.lookup_intern_closure((*id).into());
+ let infer = db.infer(def);
+ let (_, kind) = infer.closure_info(id);
+ match f.closure_style {
+ ClosureStyle::ImplFn => write!(f, "impl {kind:?}(")?,
+ ClosureStyle::RANotation => write!(f, "|")?,
+ _ => unreachable!(),
+ }
if sig.params().is_empty() {
- write!(f, "||")?;
} else if f.should_truncate() {
- write!(f, "|{TYPE_HINT_TRUNCATION}|")?;
+ write!(f, "{TYPE_HINT_TRUNCATION}")?;
} else {
- write!(f, "|")?;
f.write_joined(sig.params(), ", ")?;
- write!(f, "|")?;
};
-
- write!(f, " -> ")?;
- sig.ret().hir_fmt(f)?;
+ match f.closure_style {
+ ClosureStyle::ImplFn => write!(f, ")")?,
+ ClosureStyle::RANotation => write!(f, "|")?,
+ _ => unreachable!(),
+ }
+ if f.closure_style == ClosureStyle::RANotation || !sig.ret().is_unit() {
+ write!(f, " -> ")?;
+ sig.ret().hir_fmt(f)?;
+ }
} else {
write!(f, "{{closure}}")?;
}