Unnamed repository; edit this file 'description' to name the repository.
fix: Crash when hovering on anonymous consts
Previously, the following code would cause rust-analyzer to infinitely recurse when hovering on `x`. trait Tr<const N: usize> {} pub fn f(x: impl Tr<{ 0 }>) {} Attaching gdb and printing a stack trace shows that the problem is in HirDisplay for an anonymous const. frame 9 hir_ty::display::hir_fmt_generic_arguments () at crates/hir-ty/src/display.rs:1920 frame 10 0x00005555563b9f94 in hir_ty::display::hir_fmt_generics () at crates/hir-ty/src/display.rs:1843 frame 11 0x00005555563bd0ea in <hir_ty::next_solver::consts::Const as hir_ty::display::HirDisplay>::hir_fmt () at crates/hir-ty/src/display.rs:768 frame 12 0x00005555563ba964 in <hir_ty::next_solver::generic_arg::GenericArg as hir_ty::display::HirDisplay>::hir_fmt () at crates/hir-ty/src/display.rs:716 frame 13 hir_ty::display::hir_fmt_generic_arguments () at crates/hir-ty/src/display.rs:1920 Instead, just render anonymous consts as `{const}` rather than trying to render the synthetic type parameters too. (We could track cycles like we do for recursive bounds, but that just produces a hover of `x: impl Tr<{const}<impl …>> + ?Sized` which doesn't seem terribly useful.) AI disclosure: Initial implementation done with Codex and GPT-5.5.
Wilfred Hughes 2 weeks ago
parent cdab17b · commit 13539e1
-rw-r--r--crates/hir-ty/src/display.rs27
-rw-r--r--crates/ide/src/hover/tests.rs21
2 files changed, 38 insertions, 10 deletions
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index ab290aa57a..5d0a010a7f 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -746,26 +746,33 @@ impl<'db> HirDisplay<'db> for Const<'db> {
ConstKind::Value(value) => render_const_scalar_from_valtree(f, value.ty, value.value),
ConstKind::Unevaluated(unev) => {
let c = unev.def.0;
- match c {
- GeneralConstId::ConstId(id) => match &ConstSignature::of(f.db, id).name {
- Some(name) => {
- f.start_location_link(id.into());
- write!(f, "{}", name.display(f.db, f.edition()))?;
- f.end_location_link();
+ let generic_def = match c {
+ GeneralConstId::ConstId(id) => {
+ match &ConstSignature::of(f.db, id).name {
+ Some(name) => {
+ f.start_location_link(id.into());
+ write!(f, "{}", name.display(f.db, f.edition()))?;
+ f.end_location_link();
+ }
+ None => f.write_str("_")?,
}
- None => f.write_str("_")?,
- },
+ Some(id.into())
+ }
GeneralConstId::StaticId(id) => {
let name = &StaticSignature::of(f.db, id).name;
f.start_location_link(id.into());
write!(f, "{}", name.display(f.db, f.edition()))?;
f.end_location_link();
+ Some(id.into())
}
GeneralConstId::AnonConstId(_) => {
- f.write_str(if f.display_kind.is_source_code() { "_" } else { "{const}" })?
+ f.write_str(if f.display_kind.is_source_code() { "_" } else { "{const}" })?;
+ None
}
};
- hir_fmt_generics(f, unev.args.as_slice(), c.generic_def(f.db), None)?;
+ if let Some(generic_def) = generic_def {
+ hir_fmt_generics(f, unev.args.as_slice(), Some(generic_def), None)?;
+ }
Ok(())
}
ConstKind::Error(..) => f.write_char('_'),
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 30644fe2db..2bd79d79df 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -9422,6 +9422,27 @@ fn main(a$0: impl T) {}
}
#[test]
+fn hover_impl_trait_arg_with_anon_const_arg_does_not_recurse() {
+ check(
+ r#"
+trait Tr<const N: usize> {}
+pub fn f(x$0: impl Tr<{ 0 }>) {}
+"#,
+ expect![[r#"
+ *x*
+
+ ```rust
+ x: impl Tr<{const}> + ?Sized
+ ```
+
+ ---
+
+ type param may need Drop
+ "#]],
+ );
+}
+
+#[test]
fn hover_struct_default_arg_self() {
check(
r#"