Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide/src/inlay_hints.rs')
-rw-r--r--crates/ide/src/inlay_hints.rs196
1 files changed, 121 insertions, 75 deletions
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 19e5509681..21550d5e66 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -8,9 +8,12 @@ use hir::{
ClosureStyle, DisplayTarget, EditionedFileId, HasVisibility, HirDisplay, HirDisplayError,
HirWrite, InRealFile, ModuleDef, ModuleDefId, Semantics, sym,
};
-use ide_db::{FileRange, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder};
+use ide_db::{
+ FileRange, MiniCore, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder,
+};
use ide_db::{FxHashSet, text_edit::TextEdit};
use itertools::Itertools;
+use macros::UpmapFromRaFixture;
use smallvec::{SmallVec, smallvec};
use stdx::never;
use syntax::{
@@ -37,6 +40,7 @@ mod implicit_static;
mod implied_dyn_trait;
mod lifetime;
mod param_name;
+mod ra_fixture;
mod range_exclusive;
// Feature: Inlay Hints
@@ -80,7 +84,7 @@ pub(crate) fn inlay_hints(
db: &RootDatabase,
file_id: FileId,
range_limit: Option<TextRange>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
) -> Vec<InlayHint> {
let _p = tracing::info_span!("inlay_hints").entered();
let sema = Semantics::new(db);
@@ -105,14 +109,16 @@ pub(crate) fn inlay_hints(
}
};
let mut preorder = file.preorder();
- while let Some(event) = preorder.next() {
- if matches!((&event, range_limit), (WalkEvent::Enter(node), Some(range)) if range.intersect(node.text_range()).is_none())
- {
- preorder.skip_subtree();
- continue;
+ hir::attach_db(sema.db, || {
+ while let Some(event) = preorder.next() {
+ if matches!((&event, range_limit), (WalkEvent::Enter(node), Some(range)) if range.intersect(node.text_range()).is_none())
+ {
+ preorder.skip_subtree();
+ continue;
+ }
+ hints(event);
}
- hints(event);
- }
+ });
if let Some(range_limit) = range_limit {
acc.retain(|hint| range_limit.contains_range(hint.range));
}
@@ -130,7 +136,7 @@ pub(crate) fn inlay_hints_resolve(
file_id: FileId,
resolve_range: TextRange,
hash: u64,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
hasher: impl Fn(&InlayHint) -> u64,
) -> Option<InlayHint> {
let _p = tracing::info_span!("inlay_hints_resolve").entered();
@@ -206,7 +212,7 @@ fn hints(
hints: &mut Vec<InlayHint>,
ctx: &mut InlayHintCtx,
famous_defs @ FamousDefs(sema, _krate): &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
file_id: EditionedFileId,
display_target: DisplayTarget,
node: SyntaxNode,
@@ -228,15 +234,16 @@ fn hints(
chaining::hints(hints, famous_defs, config, display_target, &expr);
adjustment::hints(hints, famous_defs, config, display_target, &expr);
match expr {
- ast::Expr::CallExpr(it) => param_name::hints(hints, famous_defs, config, ast::Expr::from(it)),
+ ast::Expr::CallExpr(it) => param_name::hints(hints, famous_defs, config, file_id, ast::Expr::from(it)),
ast::Expr::MethodCallExpr(it) => {
- param_name::hints(hints, famous_defs, config, ast::Expr::from(it))
+ param_name::hints(hints, famous_defs, config, file_id, ast::Expr::from(it))
}
ast::Expr::ClosureExpr(it) => {
closure_captures::hints(hints, famous_defs, config, it.clone());
closure_ret::hints(hints, famous_defs, config, display_target, it)
},
ast::Expr::RangeExpr(it) => range_exclusive::hints(hints, famous_defs, config, it),
+ ast::Expr::Literal(it) => ra_fixture::hints(hints, famous_defs.0, file_id, config, it),
_ => Some(()),
}
},
@@ -292,8 +299,8 @@ fn hints(
};
}
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct InlayHintsConfig {
+#[derive(Clone, Debug)]
+pub struct InlayHintsConfig<'a> {
pub render_colons: bool,
pub type_hints: bool,
pub sized_bound: bool,
@@ -302,6 +309,7 @@ pub struct InlayHintsConfig {
pub generic_parameter_hints: GenericParameterHints,
pub chaining_hints: bool,
pub adjustment_hints: AdjustmentHints,
+ pub adjustment_hints_disable_reborrows: bool,
pub adjustment_hints_mode: AdjustmentHintsMode,
pub adjustment_hints_hide_outside_unsafe: bool,
pub closure_return_type_hints: ClosureReturnTypeHints,
@@ -318,9 +326,10 @@ pub struct InlayHintsConfig {
pub max_length: Option<usize>,
pub closing_brace_hints_min_lines: Option<usize>,
pub fields_to_resolve: InlayFieldsToResolve,
+ pub minicore: MiniCore<'a>,
}
-impl InlayHintsConfig {
+impl InlayHintsConfig<'_> {
fn lazy_text_edit(&self, finish: impl FnOnce() -> TextEdit) -> LazyProperty<TextEdit> {
if self.fields_to_resolve.resolve_text_edits {
LazyProperty::Lazy
@@ -426,7 +435,7 @@ pub enum LifetimeElisionHints {
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum AdjustmentHints {
Always,
- ReborrowOnly,
+ BorrowsOnly,
Never,
}
@@ -463,7 +472,7 @@ pub enum InlayHintPosition {
After,
}
-#[derive(Debug)]
+#[derive(Debug, UpmapFromRaFixture)]
pub struct InlayHint {
/// The text range this inlay hint applies to.
pub range: TextRange,
@@ -482,9 +491,10 @@ pub struct InlayHint {
}
/// A type signaling that a value is either computed, or is available for computation.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Default, UpmapFromRaFixture)]
pub enum LazyProperty<T> {
Computed(T),
+ #[default]
Lazy,
}
@@ -534,7 +544,7 @@ pub enum InlayTooltip {
Markdown(String),
}
-#[derive(Default, Hash)]
+#[derive(Default, Hash, UpmapFromRaFixture)]
pub struct InlayHintLabel {
pub parts: SmallVec<[InlayHintLabelPart; 1]>,
}
@@ -576,13 +586,13 @@ impl InlayHintLabel {
}
pub fn append_part(&mut self, part: InlayHintLabelPart) {
- if part.linked_location.is_none() && part.tooltip.is_none() {
- if let Some(InlayHintLabelPart { text, linked_location: None, tooltip: None }) =
+ if part.linked_location.is_none()
+ && part.tooltip.is_none()
+ && let Some(InlayHintLabelPart { text, linked_location: None, tooltip: None }) =
self.parts.last_mut()
- {
- text.push_str(&part.text);
- return;
- }
+ {
+ text.push_str(&part.text);
+ return;
}
self.parts.push(part);
}
@@ -620,6 +630,7 @@ impl fmt::Debug for InlayHintLabel {
}
}
+#[derive(UpmapFromRaFixture)]
pub struct InlayHintLabelPart {
pub text: String,
/// Source location represented by this label part. The client will use this to fetch the part's
@@ -667,7 +678,7 @@ impl fmt::Debug for InlayHintLabelPart {
#[derive(Debug)]
struct InlayHintLabelBuilder<'a> {
- db: &'a RootDatabase,
+ sema: &'a Semantics<'a, RootDatabase>,
result: InlayHintLabel,
last_part: String,
resolve: bool,
@@ -689,7 +700,7 @@ impl HirWrite for InlayHintLabelBuilder<'_> {
LazyProperty::Lazy
} else {
LazyProperty::Computed({
- let Some(location) = ModuleDef::from(def).try_to_nav(self.db) else { return };
+ let Some(location) = ModuleDef::from(def).try_to_nav(self.sema) else { return };
let location = location.call_site();
FileRange { file_id: location.file_id, range: location.focus_or_full_range() }
})
@@ -721,7 +732,7 @@ impl InlayHintLabelBuilder<'_> {
fn label_of_ty(
famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
ty: &hir::Type<'_>,
display_target: DisplayTarget,
) -> Option<InlayHintLabel> {
@@ -731,51 +742,53 @@ fn label_of_ty(
mut max_length: Option<usize>,
ty: &hir::Type<'_>,
label_builder: &mut InlayHintLabelBuilder<'_>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
display_target: DisplayTarget,
) -> Result<(), HirDisplayError> {
- let iter_item_type = hint_iterator(sema, famous_defs, ty);
- match iter_item_type {
- Some((iter_trait, item, ty)) => {
- const LABEL_START: &str = "impl ";
- const LABEL_ITERATOR: &str = "Iterator";
- const LABEL_MIDDLE: &str = "<";
- const LABEL_ITEM: &str = "Item";
- const LABEL_MIDDLE2: &str = " = ";
- const LABEL_END: &str = ">";
-
- max_length = max_length.map(|len| {
- len.saturating_sub(
- LABEL_START.len()
- + LABEL_ITERATOR.len()
- + LABEL_MIDDLE.len()
- + LABEL_MIDDLE2.len()
- + LABEL_END.len(),
- )
- });
-
- label_builder.write_str(LABEL_START)?;
- label_builder.start_location_link(ModuleDef::from(iter_trait).into());
- label_builder.write_str(LABEL_ITERATOR)?;
- label_builder.end_location_link();
- label_builder.write_str(LABEL_MIDDLE)?;
- label_builder.start_location_link(ModuleDef::from(item).into());
- label_builder.write_str(LABEL_ITEM)?;
- label_builder.end_location_link();
- label_builder.write_str(LABEL_MIDDLE2)?;
- rec(sema, famous_defs, max_length, &ty, label_builder, config, display_target)?;
- label_builder.write_str(LABEL_END)?;
- Ok(())
+ hir::attach_db(sema.db, || {
+ let iter_item_type = hint_iterator(sema, famous_defs, ty);
+ match iter_item_type {
+ Some((iter_trait, item, ty)) => {
+ const LABEL_START: &str = "impl ";
+ const LABEL_ITERATOR: &str = "Iterator";
+ const LABEL_MIDDLE: &str = "<";
+ const LABEL_ITEM: &str = "Item";
+ const LABEL_MIDDLE2: &str = " = ";
+ const LABEL_END: &str = ">";
+
+ max_length = max_length.map(|len| {
+ len.saturating_sub(
+ LABEL_START.len()
+ + LABEL_ITERATOR.len()
+ + LABEL_MIDDLE.len()
+ + LABEL_MIDDLE2.len()
+ + LABEL_END.len(),
+ )
+ });
+
+ label_builder.write_str(LABEL_START)?;
+ label_builder.start_location_link(ModuleDef::from(iter_trait).into());
+ label_builder.write_str(LABEL_ITERATOR)?;
+ label_builder.end_location_link();
+ label_builder.write_str(LABEL_MIDDLE)?;
+ label_builder.start_location_link(ModuleDef::from(item).into());
+ label_builder.write_str(LABEL_ITEM)?;
+ label_builder.end_location_link();
+ label_builder.write_str(LABEL_MIDDLE2)?;
+ rec(sema, famous_defs, max_length, &ty, label_builder, config, display_target)?;
+ label_builder.write_str(LABEL_END)?;
+ Ok(())
+ }
+ None => ty
+ .display_truncated(sema.db, max_length, display_target)
+ .with_closure_style(config.closure_style)
+ .write_to(label_builder),
}
- None => ty
- .display_truncated(sema.db, max_length, display_target)
- .with_closure_style(config.closure_style)
- .write_to(label_builder),
- }
+ })
}
let mut label_builder = InlayHintLabelBuilder {
- db: sema.db,
+ sema,
last_part: String::new(),
location: None,
result: InlayHintLabel::default(),
@@ -824,7 +837,7 @@ fn hint_iterator<'db>(
fn ty_to_text_edit(
sema: &Semantics<'_, RootDatabase>,
- config: &InlayHintsConfig,
+ config: &InlayHintsConfig<'_>,
node_for_hint: &SyntaxNode,
ty: &hir::Type<'_>,
offset_to_insert_ty: TextSize,
@@ -855,6 +868,7 @@ mod tests {
use expect_test::Expect;
use hir::ClosureStyle;
+ use ide_db::MiniCore;
use itertools::Itertools;
use test_utils::extract_annotations;
@@ -864,7 +878,7 @@ mod tests {
use super::{ClosureReturnTypeHints, GenericParameterHints, InlayFieldsToResolve};
- pub(super) const DISABLED_CONFIG: InlayHintsConfig = InlayHintsConfig {
+ pub(super) const DISABLED_CONFIG: InlayHintsConfig<'_> = InlayHintsConfig {
discriminant_hints: DiscriminantHints::Never,
render_colons: false,
type_hints: false,
@@ -880,6 +894,7 @@ mod tests {
closure_return_type_hints: ClosureReturnTypeHints::Never,
closure_capture_hints: false,
adjustment_hints: AdjustmentHints::Never,
+ adjustment_hints_disable_reborrows: false,
adjustment_hints_mode: AdjustmentHintsMode::Prefix,
adjustment_hints_hide_outside_unsafe: false,
binding_mode_hints: false,
@@ -893,8 +908,9 @@ mod tests {
fields_to_resolve: InlayFieldsToResolve::empty(),
implicit_drop_hints: false,
range_exclusive_hints: false,
+ minicore: MiniCore::default(),
};
- pub(super) const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig {
+ pub(super) const TEST_CONFIG: InlayHintsConfig<'_> = InlayHintsConfig {
type_hints: true,
parameter_hints: true,
chaining_hints: true,
@@ -911,7 +927,7 @@ mod tests {
#[track_caller]
pub(super) fn check_with_config(
- config: InlayHintsConfig,
+ config: InlayHintsConfig<'_>,
#[rust_analyzer::rust_fixture] ra_fixture: &str,
) {
let (analysis, file_id) = fixture::file(ra_fixture);
@@ -930,7 +946,7 @@ mod tests {
#[track_caller]
pub(super) fn check_expect(
- config: InlayHintsConfig,
+ config: InlayHintsConfig<'_>,
#[rust_analyzer::rust_fixture] ra_fixture: &str,
expect: Expect,
) {
@@ -945,7 +961,7 @@ mod tests {
/// expect test.
#[track_caller]
pub(super) fn check_edit(
- config: InlayHintsConfig,
+ config: InlayHintsConfig<'_>,
#[rust_analyzer::rust_fixture] ra_fixture: &str,
expect: Expect,
) {
@@ -968,7 +984,7 @@ mod tests {
#[track_caller]
pub(super) fn check_no_edit(
- config: InlayHintsConfig,
+ config: InlayHintsConfig<'_>,
#[rust_analyzer::rust_fixture] ra_fixture: &str,
) {
let (analysis, file_id) = fixture::file(ra_fixture);
@@ -1065,4 +1081,34 @@ fn bar() {
"#,
);
}
+
+ #[test]
+ fn regression_20239() {
+ check_with_config(
+ InlayHintsConfig { parameter_hints: true, type_hints: true, ..DISABLED_CONFIG },
+ r#"
+//- minicore: fn
+trait Iterator {
+ type Item;
+ fn map<B, F: FnMut(Self::Item) -> B>(self, f: F);
+}
+trait ToString {
+ fn to_string(&self);
+}
+
+fn check_tostr_eq<L, R>(left: L, right: R)
+where
+ L: Iterator,
+ L::Item: ToString,
+ R: Iterator,
+ R::Item: ToString,
+{
+ left.map(|s| s.to_string());
+ // ^ impl ToString
+ right.map(|s| s.to_string());
+ // ^ impl ToString
+}
+ "#,
+ );
+ }
}