Skip to content

feat: Closure capture inlay hints #14742

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 4 additions & 16 deletions crates/hir-ty/src/infer/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ impl HirPlace {
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) enum CaptureKind {
pub enum CaptureKind {
ByRef(BorrowKind),
ByValue,
}
Expand All @@ -166,23 +166,11 @@ impl CapturedItem {
self.place.local
}

pub fn display_kind(&self) -> &'static str {
match self.kind {
CaptureKind::ByRef(k) => match k {
BorrowKind::Shared => "immutable borrow",
BorrowKind::Shallow => {
never!("shallow borrow should not happen in closure captures");
"shallow borrow"
},
BorrowKind::Unique => "unique immutable borrow ([read more](https://doc.rust-lang.org/stable/reference/types/closure.html#unique-immutable-borrows-in-captures))",
BorrowKind::Mut { .. } => "mutable borrow",
},
CaptureKind::ByValue => "move",
}
pub fn kind(&self) -> CaptureKind {
self.kind
}

pub fn display_place(&self, owner: ClosureId, db: &dyn HirDatabase) -> String {
let owner = db.lookup_intern_closure(owner.into()).0;
pub fn display_place(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String {
let body = db.body(owner);
let mut result = body[self.place.local].name.to_string();
let mut field_need_paren = false;
Expand Down
5 changes: 3 additions & 2 deletions crates/hir-ty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ pub use autoderef::autoderef;
pub use builder::{ParamKind, TyBuilder};
pub use chalk_ext::*;
pub use infer::{
closure::CapturedItem, could_coerce, could_unify, Adjust, Adjustment, AutoBorrow, BindingMode,
InferenceDiagnostic, InferenceResult, OverloadedDeref, PointerCast,
closure::{CaptureKind, CapturedItem},
could_coerce, could_unify, Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic,
InferenceResult, OverloadedDeref, PointerCast,
};
pub use interner::Interner;
pub use lower::{
Expand Down
37 changes: 32 additions & 5 deletions crates/hir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2611,6 +2611,10 @@ impl LocalSource {
self.source.file_id.original_file(db.upcast())
}

pub fn file(&self) -> HirFileId {
self.source.file_id
}

pub fn name(&self) -> Option<ast::Name> {
self.source.value.name()
}
Expand Down Expand Up @@ -3210,7 +3214,11 @@ impl Closure {
let owner = db.lookup_intern_closure((self.id).into()).0;
let infer = &db.infer(owner);
let info = infer.closure_info(&self.id);
info.0.iter().cloned().map(|capture| ClosureCapture { owner, capture }).collect()
info.0
.iter()
.cloned()
.map(|capture| ClosureCapture { owner, closure: self.id, capture })
.collect()
}

pub fn fn_trait(&self, db: &dyn HirDatabase) -> FnTrait {
Expand All @@ -3224,6 +3232,7 @@ impl Closure {
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ClosureCapture {
owner: DefWithBodyId,
closure: ClosureId,
capture: hir_ty::CapturedItem,
}

Expand All @@ -3232,15 +3241,33 @@ impl ClosureCapture {
Local { parent: self.owner, binding_id: self.capture.local() }
}

pub fn display_kind(&self) -> &'static str {
self.capture.display_kind()
pub fn kind(&self) -> CaptureKind {
match self.capture.kind() {
hir_ty::CaptureKind::ByRef(
hir_ty::mir::BorrowKind::Shallow | hir_ty::mir::BorrowKind::Shared,
) => CaptureKind::SharedRef,
hir_ty::CaptureKind::ByRef(hir_ty::mir::BorrowKind::Unique) => {
CaptureKind::UniqueSharedRef
}
hir_ty::CaptureKind::ByRef(hir_ty::mir::BorrowKind::Mut { .. }) => {
CaptureKind::MutableRef
}
hir_ty::CaptureKind::ByValue => CaptureKind::Move,
}
}

pub fn display_place(&self, owner: ClosureId, db: &dyn HirDatabase) -> String {
self.capture.display_place(owner, db)
pub fn display_place(&self, db: &dyn HirDatabase) -> String {
self.capture.display_place(self.owner, db)
}
}

pub enum CaptureKind {
SharedRef,
UniqueSharedRef,
MutableRef,
Move,
}

#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Type {
env: Arc<TraitEnvironment>,
Expand Down
13 changes: 10 additions & 3 deletions crates/ide/src/hover/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ use std::fmt::Display;

use either::Either;
use hir::{
Adt, AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay, Semantics, TypeInfo,
Adt, AsAssocItem, AttributeTemplate, CaptureKind, HasAttrs, HasSource, HirDisplay, Semantics,
TypeInfo,
};
use ide_db::{
base_db::SourceDatabase,
Expand Down Expand Up @@ -54,8 +55,14 @@ pub(super) fn closure_expr(
let mut captures = c
.captured_items(sema.db)
.into_iter()
.map(|x| {
format!("* `{}` by {}", x.display_place(c.clone().into(), sema.db), x.display_kind())
.map(|it| {
let borrow_kind= match it.kind() {
CaptureKind::SharedRef => "immutable borrow",
CaptureKind::UniqueSharedRef => "unique immutable borrow ([read more](https://doc.rust-lang.org/stable/reference/types/closure.html#unique-immutable-borrows-in-captures))",
CaptureKind::MutableRef => "mutable borrow",
CaptureKind::Move => "move",
};
format!("* `{}` by {}", it.display_place(sema.db), borrow_kind)
})
.join("\n");
if captures.trim().is_empty() {
Expand Down
28 changes: 17 additions & 11 deletions crates/ide/src/inlay_hints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,17 @@ use text_edit::TextEdit;

use crate::{navigation_target::TryToNav, FileId};

mod closing_brace;
mod implicit_static;
mod fn_lifetime_fn;
mod closure_ret;
mod adjustment;
mod chaining;
mod param_name;
mod binding_mode;
mod bind_pat;
mod binding_mode;
mod chaining;
mod closing_brace;
mod closure_ret;
mod closure_captures;
mod discriminant;
mod fn_lifetime_fn;
mod implicit_static;
mod param_name;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct InlayHintsConfig {
Expand All @@ -42,6 +43,7 @@ pub struct InlayHintsConfig {
pub adjustment_hints_mode: AdjustmentHintsMode,
pub adjustment_hints_hide_outside_unsafe: bool,
pub closure_return_type_hints: ClosureReturnTypeHints,
pub closure_capture_hints: bool,
pub binding_mode_hints: bool,
pub lifetime_elision_hints: LifetimeElisionHints,
pub param_names_for_lifetime_elision_hints: bool,
Expand Down Expand Up @@ -88,6 +90,8 @@ pub enum AdjustmentHintsMode {
PreferPostfix,
}

// FIXME: Clean up this mess, the kinds are mainly used for setting different rendering properties in the lsp layer
// We should probably turns this into such a property holding struct. Or clean this up in some other form.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum InlayKind {
BindingMode,
Expand All @@ -98,6 +102,7 @@ pub enum InlayKind {
Adjustment,
AdjustmentPostfix,
Lifetime,
ClosureCapture,
Parameter,
Type,
Discriminant,
Expand Down Expand Up @@ -444,10 +449,10 @@ fn hints(
ast::Expr::MethodCallExpr(it) => {
param_name::hints(hints, sema, config, ast::Expr::from(it))
}
ast::Expr::ClosureExpr(it) => closure_ret::hints(hints, famous_defs, config, file_id, it),
// We could show reborrows for all expressions, but usually that is just noise to the user
// and the main point here is to show why "moving" a mutable reference doesn't necessarily move it
// ast::Expr::PathExpr(_) => reborrow_hints(hints, sema, config, &expr),
ast::Expr::ClosureExpr(it) => {
closure_captures::hints(hints, famous_defs, config, file_id, it.clone());
closure_ret::hints(hints, famous_defs, config, file_id, it)
},
_ => None,
}
},
Expand Down Expand Up @@ -535,6 +540,7 @@ mod tests {
chaining_hints: false,
lifetime_elision_hints: LifetimeElisionHints::Never,
closure_return_type_hints: ClosureReturnTypeHints::Never,
closure_capture_hints: false,
adjustment_hints: AdjustmentHints::Never,
adjustment_hints_mode: AdjustmentHintsMode::Prefix,
adjustment_hints_hide_outside_unsafe: false,
Expand Down
Loading