mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-03 07:04:49 +00:00
Compute closure captures
This commit is contained in:
parent
51d5862caf
commit
59b6f2d9f2
42 changed files with 2537 additions and 433 deletions
|
@ -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}}")?;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue