Compute closure captures

This commit is contained in:
hkalbasi 2023-04-06 16:14:38 +03:30
parent 51d5862caf
commit 59b6f2d9f2
42 changed files with 2537 additions and 433 deletions

View file

@ -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}}")?;
}