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.
| -rw-r--r-- | crates/hir-ty/src/display.rs | 27 | ||||
| -rw-r--r-- | crates/ide/src/hover/tests.rs | 21 |
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#" |