Skip to content

Commit 9fd7051

Browse files
committed
Auto merge of #18010 - Veykril:inlay-hints-lt, r=Veykril
feat: Support fn-ptr and fn-path types for lifetime elision hints All still syntax based unfortunately but that won't change for quite a while
2 parents 64c538f + 1607797 commit 9fd7051

File tree

3 files changed

+597
-358
lines changed

3 files changed

+597
-358
lines changed

crates/ide/src/inlay_hints.rs

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ use smallvec::{smallvec, SmallVec};
1414
use span::{Edition, EditionedFileId};
1515
use stdx::never;
1616
use syntax::{
17-
ast::{self, AstNode},
18-
match_ast, NodeOrToken, SyntaxNode, TextRange, TextSize, WalkEvent,
17+
ast::{self, AstNode, HasGenericParams},
18+
format_smolstr, match_ast, NodeOrToken, SmolStr, SyntaxNode, TextRange, TextSize, WalkEvent,
1919
};
2020
use text_edit::TextEdit;
2121

@@ -29,10 +29,10 @@ mod closing_brace;
2929
mod closure_captures;
3030
mod closure_ret;
3131
mod discriminant;
32-
mod fn_lifetime_fn;
3332
mod generic_param;
3433
mod implicit_drop;
3534
mod implicit_static;
35+
mod lifetime;
3636
mod param_name;
3737
mod range_exclusive;
3838

@@ -94,8 +94,8 @@ pub(crate) fn inlay_hints(
9494
};
9595
let famous_defs = FamousDefs(&sema, scope.krate());
9696

97-
let parent_impl = &mut None;
98-
let hints = |node| hints(&mut acc, parent_impl, &famous_defs, config, file_id, node);
97+
let ctx = &mut InlayHintCtx::default();
98+
let hints = |node| hints(&mut acc, ctx, &famous_defs, config, file_id, node);
9999
match range_limit {
100100
// FIXME: This can miss some hints that require the parent of the range to calculate
101101
Some(range) => match file.covering_element(range) {
@@ -111,6 +111,12 @@ pub(crate) fn inlay_hints(
111111
acc
112112
}
113113

114+
#[derive(Default)]
115+
struct InlayHintCtx {
116+
lifetime_stacks: Vec<Vec<SmolStr>>,
117+
is_param_list: bool,
118+
}
119+
114120
pub(crate) fn inlay_hints_resolve(
115121
db: &RootDatabase,
116122
file_id: FileId,
@@ -131,8 +137,8 @@ pub(crate) fn inlay_hints_resolve(
131137
let famous_defs = FamousDefs(&sema, scope.krate());
132138
let mut acc = Vec::new();
133139

134-
let parent_impl = &mut None;
135-
let hints = |node| hints(&mut acc, parent_impl, &famous_defs, config, file_id, node);
140+
let ctx = &mut InlayHintCtx::default();
141+
let hints = |node| hints(&mut acc, ctx, &famous_defs, config, file_id, node);
136142

137143
let mut res = file.clone();
138144
let res = loop {
@@ -146,9 +152,11 @@ pub(crate) fn inlay_hints_resolve(
146152
acc.into_iter().find(|hint| hasher(hint) == hash)
147153
}
148154

155+
// FIXME: At some point when our hir infra is fleshed out enough we should flip this and traverse the
156+
// HIR instead of the syntax tree.
149157
fn hints(
150158
hints: &mut Vec<InlayHint>,
151-
parent_impl: &mut Option<ast::Impl>,
159+
ctx: &mut InlayHintCtx,
152160
famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
153161
config: &InlayHintsConfig,
154162
file_id: EditionedFileId,
@@ -157,12 +165,30 @@ fn hints(
157165
let node = match node {
158166
WalkEvent::Enter(node) => node,
159167
WalkEvent::Leave(n) => {
160-
if ast::Impl::can_cast(n.kind()) {
161-
parent_impl.take();
168+
if ast::AnyHasGenericParams::can_cast(n.kind()) {
169+
ctx.lifetime_stacks.pop();
170+
// pop
171+
}
172+
if ast::ParamList::can_cast(n.kind()) {
173+
ctx.is_param_list = false;
174+
// pop
162175
}
163176
return;
164177
}
165178
};
179+
180+
if let Some(node) = ast::AnyHasGenericParams::cast(node.clone()) {
181+
let params = node
182+
.generic_param_list()
183+
.map(|it| {
184+
it.lifetime_params()
185+
.filter_map(|it| it.lifetime().map(|it| format_smolstr!("{}", &it.text()[1..])))
186+
.collect()
187+
})
188+
.unwrap_or_default();
189+
ctx.lifetime_stacks.push(params);
190+
}
191+
166192
closing_brace::hints(hints, sema, config, file_id, node.clone());
167193
if let Some(any_has_generic_args) = ast::AnyHasGenericArgs::cast(node.clone()) {
168194
generic_param::hints(hints, sema, config, any_has_generic_args);
@@ -183,7 +209,7 @@ fn hints(
183209
closure_ret::hints(hints, famous_defs, config, file_id, it)
184210
},
185211
ast::Expr::RangeExpr(it) => range_exclusive::hints(hints, famous_defs, config, file_id, it),
186-
_ => None,
212+
_ => Some(()),
187213
}
188214
},
189215
ast::Pat(it) => {
@@ -200,24 +226,27 @@ fn hints(
200226
Some(())
201227
},
202228
ast::Item(it) => match it {
203-
// FIXME: record impl lifetimes so they aren't being reused in assoc item lifetime inlay hints
204-
ast::Item::Impl(impl_) => {
205-
*parent_impl = Some(impl_);
206-
None
207-
},
208229
ast::Item::Fn(it) => {
209230
implicit_drop::hints(hints, famous_defs, config, file_id, &it);
210-
fn_lifetime_fn::hints(hints, famous_defs, config, file_id, it)
231+
lifetime::fn_hints(hints, ctx, famous_defs, config, file_id, it)
211232
},
212233
// static type elisions
213234
ast::Item::Static(it) => implicit_static::hints(hints, famous_defs, config, file_id, Either::Left(it)),
214235
ast::Item::Const(it) => implicit_static::hints(hints, famous_defs, config, file_id, Either::Right(it)),
215236
ast::Item::Enum(it) => discriminant::enum_hints(hints, famous_defs, config, file_id, it),
216237
_ => None,
217238
},
218-
// FIXME: fn-ptr type, dyn fn type, and trait object type elisions
219-
ast::Type(_) => None,
220-
_ => None,
239+
// FIXME: trait object type elisions
240+
ast::Type(ty) => match ty {
241+
ast::Type::FnPtrType(ptr) => lifetime::fn_ptr_hints(hints, ctx, famous_defs, config, file_id, ptr),
242+
ast::Type::PathType(path) => lifetime::fn_path_hints(hints, ctx, famous_defs, config, file_id, path),
243+
_ => Some(()),
244+
},
245+
ast::ParamList(_) => {
246+
ctx.is_param_list = true;
247+
Some(())
248+
},
249+
_ => Some(()),
221250
}
222251
};
223252
}

0 commit comments

Comments
 (0)