Skip to content

Commit a62e2f5

Browse files
authored
Merge pull request #18991 from Veykril/push-rmqmnrymwmoz
Keep already computed inlay hint properties instead of late resolving them
2 parents 3a163fa + 41e6a87 commit a62e2f5

File tree

11 files changed

+433
-322
lines changed

11 files changed

+433
-322
lines changed

Diff for: crates/hir/src/lib.rs

+26-15
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ use hir_def::{
4545
body::BodyDiagnostic,
4646
data::{adt::VariantData, TraitFlags},
4747
generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance},
48-
hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, Pat},
48+
hir::{BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, LabelId, Pat},
4949
item_tree::{AttrOwner, FieldParent, ItemTreeFieldId, ItemTreeNode},
5050
lang_item::LangItemTarget,
5151
layout::{self, ReprOptions, TargetDataLayout},
@@ -2470,20 +2470,31 @@ impl Param {
24702470
}
24712471

24722472
pub fn as_local(&self, db: &dyn HirDatabase) -> Option<Local> {
2473-
let parent = match self.func {
2474-
Callee::Def(CallableDefId::FunctionId(it)) => DefWithBodyId::FunctionId(it),
2475-
Callee::Closure(closure, _) => db.lookup_intern_closure(closure.into()).0,
2476-
_ => return None,
2477-
};
2478-
let body = db.body(parent);
2479-
if let Some(self_param) = body.self_param.filter(|_| self.idx == 0) {
2480-
Some(Local { parent, binding_id: self_param })
2481-
} else if let Pat::Bind { id, .. } =
2482-
&body[body.params[self.idx - body.self_param.is_some() as usize]]
2483-
{
2484-
Some(Local { parent, binding_id: *id })
2485-
} else {
2486-
None
2473+
match self.func {
2474+
Callee::Def(CallableDefId::FunctionId(it)) => {
2475+
let parent = DefWithBodyId::FunctionId(it);
2476+
let body = db.body(parent);
2477+
if let Some(self_param) = body.self_param.filter(|_| self.idx == 0) {
2478+
Some(Local { parent, binding_id: self_param })
2479+
} else if let Pat::Bind { id, .. } =
2480+
&body[body.params[self.idx - body.self_param.is_some() as usize]]
2481+
{
2482+
Some(Local { parent, binding_id: *id })
2483+
} else {
2484+
None
2485+
}
2486+
}
2487+
Callee::Closure(closure, _) => {
2488+
let c = db.lookup_intern_closure(closure.into());
2489+
let body = db.body(c.0);
2490+
if let Expr::Closure { args, .. } = &body[c.1] {
2491+
if let Pat::Bind { id, .. } = &body[args[self.idx]] {
2492+
return Some(Local { parent: c.0, binding_id: *id });
2493+
}
2494+
}
2495+
None
2496+
}
2497+
_ => None,
24872498
}
24882499
}
24892500

Diff for: crates/ide/src/inlay_hints.rs

+51-26
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ fn hints(
209209
) {
210210
closing_brace::hints(hints, sema, config, file_id, node.clone());
211211
if let Some(any_has_generic_args) = ast::AnyHasGenericArgs::cast(node.clone()) {
212-
generic_param::hints(hints, sema, config, any_has_generic_args);
212+
generic_param::hints(hints, famous_defs, config, any_has_generic_args);
213213
}
214214

215215
match_ast! {
@@ -300,22 +300,23 @@ pub struct InlayHintsConfig {
300300
pub closing_brace_hints_min_lines: Option<usize>,
301301
pub fields_to_resolve: InlayFieldsToResolve,
302302
}
303+
303304
impl InlayHintsConfig {
304-
fn lazy_text_edit(&self, finish: impl FnOnce() -> TextEdit) -> Lazy<TextEdit> {
305+
fn lazy_text_edit(&self, finish: impl FnOnce() -> TextEdit) -> LazyProperty<TextEdit> {
305306
if self.fields_to_resolve.resolve_text_edits {
306-
Lazy::Lazy
307+
LazyProperty::Lazy
307308
} else {
308309
let edit = finish();
309310
never!(edit.is_empty(), "inlay hint produced an empty text edit");
310-
Lazy::Computed(edit)
311+
LazyProperty::Computed(edit)
311312
}
312313
}
313314

314-
fn lazy_tooltip(&self, finish: impl FnOnce() -> InlayTooltip) -> Lazy<InlayTooltip> {
315+
fn lazy_tooltip(&self, finish: impl FnOnce() -> InlayTooltip) -> LazyProperty<InlayTooltip> {
315316
if self.fields_to_resolve.resolve_hint_tooltip
316317
&& self.fields_to_resolve.resolve_label_tooltip
317318
{
318-
Lazy::Lazy
319+
LazyProperty::Lazy
319320
} else {
320321
let tooltip = finish();
321322
never!(
@@ -326,7 +327,20 @@ impl InlayHintsConfig {
326327
.is_empty(),
327328
"inlay hint produced an empty tooltip"
328329
);
329-
Lazy::Computed(tooltip)
330+
LazyProperty::Computed(tooltip)
331+
}
332+
}
333+
334+
/// This always reports a resolvable location, so only use this when it is very likely for a
335+
/// location link to actually resolve but where computing `finish` would be costly.
336+
fn lazy_location_opt(
337+
&self,
338+
finish: impl FnOnce() -> Option<FileRange>,
339+
) -> Option<LazyProperty<FileRange>> {
340+
if self.fields_to_resolve.resolve_label_location {
341+
Some(LazyProperty::Lazy)
342+
} else {
343+
finish().map(LazyProperty::Computed)
330344
}
331345
}
332346
}
@@ -441,23 +455,23 @@ pub struct InlayHint {
441455
/// The actual label to show in the inlay hint.
442456
pub label: InlayHintLabel,
443457
/// Text edit to apply when "accepting" this inlay hint.
444-
pub text_edit: Option<Lazy<TextEdit>>,
458+
pub text_edit: Option<LazyProperty<TextEdit>>,
445459
/// Range to recompute inlay hints when trying to resolve for this hint. If this is none, the
446460
/// hint does not support resolving.
447461
pub resolve_parent: Option<TextRange>,
448462
}
449463

450464
/// A type signaling that a value is either computed, or is available for computation.
451465
#[derive(Clone, Debug)]
452-
pub enum Lazy<T> {
466+
pub enum LazyProperty<T> {
453467
Computed(T),
454468
Lazy,
455469
}
456470

457-
impl<T> Lazy<T> {
471+
impl<T> LazyProperty<T> {
458472
pub fn computed(self) -> Option<T> {
459473
match self {
460-
Lazy::Computed(it) => Some(it),
474+
LazyProperty::Computed(it) => Some(it),
461475
_ => None,
462476
}
463477
}
@@ -508,8 +522,8 @@ pub struct InlayHintLabel {
508522
impl InlayHintLabel {
509523
pub fn simple(
510524
s: impl Into<String>,
511-
tooltip: Option<Lazy<InlayTooltip>>,
512-
linked_location: Option<FileRange>,
525+
tooltip: Option<LazyProperty<InlayTooltip>>,
526+
linked_location: Option<LazyProperty<FileRange>>,
513527
) -> InlayHintLabel {
514528
InlayHintLabel {
515529
parts: smallvec![InlayHintLabelPart { text: s.into(), linked_location, tooltip }],
@@ -593,33 +607,37 @@ pub struct InlayHintLabelPart {
593607
/// refers to (not necessarily the location itself).
594608
/// When setting this, no tooltip must be set on the containing hint, or VS Code will display
595609
/// them both.
596-
pub linked_location: Option<FileRange>,
610+
pub linked_location: Option<LazyProperty<FileRange>>,
597611
/// The tooltip to show when hovering over the inlay hint, this may invoke other actions like
598612
/// hover requests to show.
599-
pub tooltip: Option<Lazy<InlayTooltip>>,
613+
pub tooltip: Option<LazyProperty<InlayTooltip>>,
600614
}
601615

602616
impl std::hash::Hash for InlayHintLabelPart {
603617
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
604618
self.text.hash(state);
605-
self.linked_location.hash(state);
619+
self.linked_location.is_some().hash(state);
606620
self.tooltip.is_some().hash(state);
607621
}
608622
}
609623

610624
impl fmt::Debug for InlayHintLabelPart {
611625
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
612626
match self {
613-
Self { text, linked_location: None, tooltip: None | Some(Lazy::Lazy) } => text.fmt(f),
627+
Self { text, linked_location: None, tooltip: None | Some(LazyProperty::Lazy) } => {
628+
text.fmt(f)
629+
}
614630
Self { text, linked_location, tooltip } => f
615631
.debug_struct("InlayHintLabelPart")
616632
.field("text", text)
617633
.field("linked_location", linked_location)
618634
.field(
619635
"tooltip",
620636
&tooltip.as_ref().map_or("", |it| match it {
621-
Lazy::Computed(InlayTooltip::String(it) | InlayTooltip::Markdown(it)) => it,
622-
Lazy::Lazy => "",
637+
LazyProperty::Computed(
638+
InlayTooltip::String(it) | InlayTooltip::Markdown(it),
639+
) => it,
640+
LazyProperty::Lazy => "",
623641
}),
624642
)
625643
.finish(),
@@ -632,7 +650,8 @@ struct InlayHintLabelBuilder<'a> {
632650
db: &'a RootDatabase,
633651
result: InlayHintLabel,
634652
last_part: String,
635-
location: Option<FileRange>,
653+
resolve: bool,
654+
location: Option<LazyProperty<FileRange>>,
636655
}
637656

638657
impl fmt::Write for InlayHintLabelBuilder<'_> {
@@ -645,11 +664,16 @@ impl HirWrite for InlayHintLabelBuilder<'_> {
645664
fn start_location_link(&mut self, def: ModuleDefId) {
646665
never!(self.location.is_some(), "location link is already started");
647666
self.make_new_part();
648-
let Some(location) = ModuleDef::from(def).try_to_nav(self.db) else { return };
649-
let location = location.call_site();
650-
let location =
651-
FileRange { file_id: location.file_id, range: location.focus_or_full_range() };
652-
self.location = Some(location);
667+
668+
self.location = Some(if self.resolve {
669+
LazyProperty::Lazy
670+
} else {
671+
LazyProperty::Computed({
672+
let Some(location) = ModuleDef::from(def).try_to_nav(self.db) else { return };
673+
let location = location.call_site();
674+
FileRange { file_id: location.file_id, range: location.focus_or_full_range() }
675+
})
676+
});
653677
}
654678

655679
fn end_location_link(&mut self) {
@@ -735,6 +759,7 @@ fn label_of_ty(
735759
last_part: String::new(),
736760
location: None,
737761
result: InlayHintLabel::default(),
762+
resolve: config.fields_to_resolve.resolve_label_location,
738763
};
739764
let _ = rec(sema, famous_defs, config.max_length, ty, &mut label_builder, config, edition);
740765
let r = label_builder.finish();
@@ -783,7 +808,7 @@ fn ty_to_text_edit(
783808
ty: &hir::Type,
784809
offset_to_insert: TextSize,
785810
prefix: impl Into<String>,
786-
) -> Option<Lazy<TextEdit>> {
811+
) -> Option<LazyProperty<TextEdit>> {
787812
// FIXME: Limit the length and bail out on excess somehow?
788813
let rendered = sema
789814
.scope(node_for_hint)

Diff for: crates/ide/src/inlay_hints/bounds.rs

+20-12
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,7 @@ pub(super) fn hints(
2222
return None;
2323
}
2424

25-
let linked_location =
26-
famous_defs.core_marker_Sized().and_then(|it| it.try_to_nav(sema.db)).map(|it| {
27-
let n = it.call_site();
28-
FileRange { file_id: n.file_id, range: n.focus_or_full_range() }
29-
});
25+
let sized_trait = famous_defs.core_marker_Sized();
3026

3127
for param in params.type_or_const_params() {
3228
match param {
@@ -48,7 +44,17 @@ pub(super) fn hints(
4844
}
4945
hint.parts.push(InlayHintLabelPart {
5046
text: "Sized".to_owned(),
51-
linked_location,
47+
linked_location: sized_trait.and_then(|it| {
48+
config.lazy_location_opt(|| {
49+
it.try_to_nav(sema.db).map(|it| {
50+
let n = it.call_site();
51+
FileRange {
52+
file_id: n.file_id,
53+
range: n.focus_or_full_range(),
54+
}
55+
})
56+
})
57+
}),
5258
tooltip: None,
5359
});
5460
if has_bounds {
@@ -134,12 +140,14 @@ fn foo<T>() {}
134140
InlayHintLabelPart {
135141
text: "Sized",
136142
linked_location: Some(
137-
FileRangeWrapper {
138-
file_id: FileId(
139-
1,
140-
),
141-
range: 135..140,
142-
},
143+
Computed(
144+
FileRangeWrapper {
145+
file_id: FileId(
146+
1,
147+
),
148+
range: 135..140,
149+
},
150+
),
143151
),
144152
tooltip: "",
145153
},

0 commit comments

Comments
 (0)