Skip to content
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

feat: Initial support for implicit drop inlay hint #16000

Merged
merged 1 commit into from
Dec 1, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 14 additions & 0 deletions crates/hir-ty/src/mir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,10 @@ impl ProjectionStore {
impl ProjectionId {
pub const EMPTY: ProjectionId = ProjectionId(0);

pub fn is_empty(self) -> bool {
self == ProjectionId::EMPTY
}

pub fn lookup(self, store: &ProjectionStore) -> &[PlaceElem] {
store.id_to_proj.get(&self).unwrap()
}
Expand Down Expand Up @@ -1069,6 +1073,10 @@ pub struct MirBody {
}

impl MirBody {
pub fn local_to_binding_map(&self) -> ArenaMap<LocalId, BindingId> {
self.binding_locals.iter().map(|(it, y)| (*y, it)).collect()
}

fn walk_places(&mut self, mut f: impl FnMut(&mut Place, &mut ProjectionStore)) {
fn for_operand(
op: &mut Operand,
Expand Down Expand Up @@ -1188,3 +1196,9 @@ pub enum MirSpan {
}

impl_from!(ExprId, PatId for MirSpan);

impl From<&ExprId> for MirSpan {
fn from(value: &ExprId) -> Self {
(*value).into()
}
}
54 changes: 34 additions & 20 deletions crates/hir-ty/src/mir/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,14 @@ pub enum MirLowerError {
/// A token to ensuring that each drop scope is popped at most once, thanks to the compiler that checks moves.
struct DropScopeToken;
impl DropScopeToken {
fn pop_and_drop(self, ctx: &mut MirLowerCtx<'_>, current: BasicBlockId) -> BasicBlockId {
fn pop_and_drop(
self,
ctx: &mut MirLowerCtx<'_>,
current: BasicBlockId,
span: MirSpan,
) -> BasicBlockId {
std::mem::forget(self);
ctx.pop_drop_scope_internal(current)
ctx.pop_drop_scope_internal(current, span)
}

/// It is useful when we want a drop scope is syntaxically closed, but we don't want to execute any drop
Expand Down Expand Up @@ -582,7 +587,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
self.lower_loop(current, place, *label, expr_id.into(), |this, begin| {
let scope = this.push_drop_scope();
if let Some((_, mut current)) = this.lower_expr_as_place(begin, *body, true)? {
current = scope.pop_and_drop(this, current);
current = scope.pop_and_drop(this, current, body.into());
this.set_goto(current, begin, expr_id.into());
} else {
scope.pop_assume_dropped(this);
Expand Down Expand Up @@ -720,7 +725,8 @@ impl<'ctx> MirLowerCtx<'ctx> {
.ok_or(MirLowerError::ContinueWithoutLoop)?,
};
let begin = loop_data.begin;
current = self.drop_until_scope(loop_data.drop_scope_index, current);
current =
self.drop_until_scope(loop_data.drop_scope_index, current, expr_id.into());
self.set_goto(current, begin, expr_id.into());
Ok(None)
}
Expand Down Expand Up @@ -759,7 +765,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
self.current_loop_blocks.as_ref().unwrap().drop_scope_index,
),
};
current = self.drop_until_scope(drop_scope, current);
current = self.drop_until_scope(drop_scope, current, expr_id.into());
self.set_goto(current, end, expr_id.into());
Ok(None)
}
Expand All @@ -773,7 +779,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
return Ok(None);
}
}
current = self.drop_until_scope(0, current);
current = self.drop_until_scope(0, current, expr_id.into());
self.set_terminator(current, TerminatorKind::Return, expr_id.into());
Ok(None)
}
Expand Down Expand Up @@ -1782,7 +1788,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
return Ok(None);
};
self.push_fake_read(c, p, expr.into());
current = scope2.pop_and_drop(self, c);
current = scope2.pop_and_drop(self, c, expr.into());
}
}
}
Expand All @@ -1793,7 +1799,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
};
current = c;
}
current = scope.pop_and_drop(self, current);
current = scope.pop_and_drop(self, current, span);
Ok(Some(current))
}

Expand Down Expand Up @@ -1873,9 +1879,14 @@ impl<'ctx> MirLowerCtx<'ctx> {
}
}

fn drop_until_scope(&mut self, scope_index: usize, mut current: BasicBlockId) -> BasicBlockId {
fn drop_until_scope(
&mut self,
scope_index: usize,
mut current: BasicBlockId,
span: MirSpan,
) -> BasicBlockId {
for scope in self.drop_scopes[scope_index..].to_vec().iter().rev() {
self.emit_drop_and_storage_dead_for_scope(scope, &mut current);
self.emit_drop_and_storage_dead_for_scope(scope, &mut current, span);
}
current
}
Expand All @@ -1891,17 +1902,22 @@ impl<'ctx> MirLowerCtx<'ctx> {
}

/// Don't call directly
fn pop_drop_scope_internal(&mut self, mut current: BasicBlockId) -> BasicBlockId {
fn pop_drop_scope_internal(
&mut self,
mut current: BasicBlockId,
span: MirSpan,
) -> BasicBlockId {
let scope = self.drop_scopes.pop().unwrap();
self.emit_drop_and_storage_dead_for_scope(&scope, &mut current);
self.emit_drop_and_storage_dead_for_scope(&scope, &mut current, span);
current
}

fn pop_drop_scope_assert_finished(
&mut self,
mut current: BasicBlockId,
span: MirSpan,
) -> Result<BasicBlockId> {
current = self.pop_drop_scope_internal(current);
current = self.pop_drop_scope_internal(current, span);
if !self.drop_scopes.is_empty() {
implementation_error!("Mismatched count between drop scope push and pops");
}
Expand All @@ -1912,20 +1928,18 @@ impl<'ctx> MirLowerCtx<'ctx> {
&mut self,
scope: &DropScope,
current: &mut Idx<BasicBlock>,
span: MirSpan,
) {
for &l in scope.locals.iter().rev() {
if !self.result.locals[l].ty.clone().is_copy(self.db, self.owner) {
let prev = std::mem::replace(current, self.new_basic_block());
self.set_terminator(
prev,
TerminatorKind::Drop { place: l.into(), target: *current, unwind: None },
MirSpan::Unknown,
span,
);
}
self.push_statement(
*current,
StatementKind::StorageDead(l).with_span(MirSpan::Unknown),
);
self.push_statement(*current, StatementKind::StorageDead(l).with_span(span));
}
}
}
Expand Down Expand Up @@ -2002,7 +2016,7 @@ pub fn mir_body_for_closure_query(
|_| true,
)?;
if let Some(current) = ctx.lower_expr_to_place(*root, return_slot().into(), current)? {
let current = ctx.pop_drop_scope_assert_finished(current)?;
let current = ctx.pop_drop_scope_assert_finished(current, root.into())?;
ctx.set_terminator(current, TerminatorKind::Return, (*root).into());
}
let mut upvar_map: FxHashMap<LocalId, Vec<(&CapturedItem, usize)>> = FxHashMap::default();
Expand Down Expand Up @@ -2146,7 +2160,7 @@ pub fn lower_to_mir(
ctx.lower_params_and_bindings([].into_iter(), binding_picker)?
};
if let Some(current) = ctx.lower_expr_to_place(root_expr, return_slot().into(), current)? {
let current = ctx.pop_drop_scope_assert_finished(current)?;
let current = ctx.pop_drop_scope_assert_finished(current, root_expr.into())?;
ctx.set_terminator(current, TerminatorKind::Return, root_expr.into());
}
Ok(ctx.result)
Expand Down
4 changes: 2 additions & 2 deletions crates/hir-ty/src/mir/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ impl<'a> MirPrettyCtx<'a> {
let indent = mem::take(&mut self.indent);
let mut ctx = MirPrettyCtx {
body: &body,
local_to_binding: body.binding_locals.iter().map(|(it, y)| (*y, it)).collect(),
local_to_binding: body.local_to_binding_map(),
result,
indent,
..*self
Expand All @@ -167,7 +167,7 @@ impl<'a> MirPrettyCtx<'a> {
}

fn new(body: &'a MirBody, hir_body: &'a Body, db: &'a dyn HirDatabase) -> Self {
let local_to_binding = body.binding_locals.iter().map(|(it, y)| (*y, it)).collect();
let local_to_binding = body.local_to_binding_map();
MirPrettyCtx {
body,
db,
Expand Down
5 changes: 3 additions & 2 deletions crates/hir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ use hir_ty::{
known_const_to_ast,
layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding},
method_resolution::{self, TyFingerprint},
mir::{self, interpret_mir},
mir::interpret_mir,
primitive::UintTy,
traits::FnTrait,
AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg,
Expand Down Expand Up @@ -129,9 +129,10 @@ pub use {
hir_ty::{
display::{ClosureStyle, HirDisplay, HirDisplayError, HirWrite},
layout::LayoutError,
mir::MirEvalError,
PointerCast, Safety,
},
// FIXME: Properly encapsulate mir
hir_ty::{mir, Interner as ChalkTyInterner},
};

// These are negative re-exports: pub using these names is forbidden, they
Expand Down
9 changes: 8 additions & 1 deletion crates/ide/src/inlay_hints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ mod discriminant;
mod fn_lifetime_fn;
mod implicit_static;
mod param_name;
mod implicit_drop;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct InlayHintsConfig {
Expand All @@ -45,6 +46,7 @@ pub struct InlayHintsConfig {
pub closure_return_type_hints: ClosureReturnTypeHints,
pub closure_capture_hints: bool,
pub binding_mode_hints: bool,
pub implicit_drop_hints: bool,
pub lifetime_elision_hints: LifetimeElisionHints,
pub param_names_for_lifetime_elision_hints: bool,
pub hide_named_constructor_hints: bool,
Expand Down Expand Up @@ -124,6 +126,7 @@ pub enum InlayKind {
Lifetime,
Parameter,
Type,
Drop,
}

#[derive(Debug)]
Expand Down Expand Up @@ -503,7 +506,10 @@ fn hints(
ast::Item(it) => match it {
// FIXME: record impl lifetimes so they aren't being reused in assoc item lifetime inlay hints
ast::Item::Impl(_) => None,
ast::Item::Fn(it) => fn_lifetime_fn::hints(hints, config, it),
ast::Item::Fn(it) => {
implicit_drop::hints(hints, sema, config, &it);
fn_lifetime_fn::hints(hints, config, it)
},
// static type elisions
ast::Item::Static(it) => implicit_static::hints(hints, config, Either::Left(it)),
ast::Item::Const(it) => implicit_static::hints(hints, config, Either::Right(it)),
Expand Down Expand Up @@ -591,6 +597,7 @@ mod tests {
max_length: None,
closing_brace_hints_min_lines: None,
fields_to_resolve: InlayFieldsToResolve::empty(),
implicit_drop_hints: false,
};
pub(super) const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig {
type_hints: true,
Expand Down