Skip to content

Commit a1efdaf

Browse files
committed
fix: Add recursion limit when hovering on const values
This fixes #21503
1 parent eb05888 commit a1efdaf

File tree

2 files changed

+78
-7
lines changed

2 files changed

+78
-7
lines changed

crates/hir-ty/src/display.rs

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,7 @@ impl<'db> HirDisplay<'db> for Const<'db> {
702702
&const_bytes.value.inner().memory,
703703
&const_bytes.value.inner().memory_map,
704704
const_bytes.ty,
705+
CONST_SCALAR_RENDER_DEPTH_LIMIT,
705706
),
706707
ConstKind::Unevaluated(unev) => {
707708
let c = unev.def.0;
@@ -715,16 +716,24 @@ impl<'db> HirDisplay<'db> for Const<'db> {
715716
}
716717
}
717718

719+
/// Maximum recursion depth for rendering const scalars.
720+
/// This prevents stack overflow with self-referential data structures.
721+
const CONST_SCALAR_RENDER_DEPTH_LIMIT: usize = 20;
722+
718723
fn render_const_scalar<'db>(
719724
f: &mut HirFormatter<'_, 'db>,
720725
b: &[u8],
721726
memory_map: &MemoryMap<'db>,
722727
ty: Ty<'db>,
728+
depth: usize,
723729
) -> Result {
730+
if depth == 0 {
731+
return f.write_str("<recursion-limit>");
732+
}
724733
let param_env = ParamEnv::empty();
725734
let infcx = f.interner.infer_ctxt().build(TypingMode::PostAnalysis);
726735
let ty = infcx.at(&ObligationCause::new(), param_env).deeply_normalize(ty).unwrap_or(ty);
727-
render_const_scalar_inner(f, b, memory_map, ty, param_env)
736+
render_const_scalar_inner(f, b, memory_map, ty, param_env, depth)
728737
}
729738

730739
fn render_const_scalar_inner<'db>(
@@ -733,6 +742,7 @@ fn render_const_scalar_inner<'db>(
733742
memory_map: &MemoryMap<'db>,
734743
ty: Ty<'db>,
735744
param_env: ParamEnv<'db>,
745+
depth: usize,
736746
) -> Result {
737747
use TyKind;
738748
let param_env = ParamEnvAndCrate { param_env, krate: f.krate() };
@@ -822,7 +832,13 @@ fn render_const_scalar_inner<'db>(
822832
f.write_str(", ")?;
823833
}
824834
let offset = size_one * i;
825-
render_const_scalar(f, &bytes[offset..offset + size_one], memory_map, ty)?;
835+
render_const_scalar(
836+
f,
837+
&bytes[offset..offset + size_one],
838+
memory_map,
839+
ty,
840+
depth - 1,
841+
)?;
826842
}
827843
f.write_str("]")
828844
}
@@ -840,7 +856,7 @@ fn render_const_scalar_inner<'db>(
840856
return f.write_str("<ref-data-not-available>");
841857
};
842858
f.write_str("&")?;
843-
render_const_scalar(f, bytes, memory_map, t)
859+
render_const_scalar(f, bytes, memory_map, t, depth - 1)
844860
}
845861
TyKind::Adt(adt, _) if b.len() == 2 * size_of::<usize>() => match adt.def_id().0 {
846862
hir_def::AdtId::StructId(s) => {
@@ -870,7 +886,7 @@ fn render_const_scalar_inner<'db>(
870886
return f.write_str("<ref-data-not-available>");
871887
};
872888
f.write_str("&")?;
873-
render_const_scalar(f, bytes, memory_map, t)
889+
render_const_scalar(f, bytes, memory_map, t, depth - 1)
874890
}
875891
},
876892
TyKind::Tuple(tys) => {
@@ -891,7 +907,7 @@ fn render_const_scalar_inner<'db>(
891907
continue;
892908
};
893909
let size = layout.size.bytes_usize();
894-
render_const_scalar(f, &b[offset..offset + size], memory_map, ty)?;
910+
render_const_scalar(f, &b[offset..offset + size], memory_map, ty, depth - 1)?;
895911
}
896912
f.write_str(")")
897913
}
@@ -914,6 +930,7 @@ fn render_const_scalar_inner<'db>(
914930
args,
915931
b,
916932
memory_map,
933+
depth,
917934
)
918935
}
919936
hir_def::AdtId::UnionId(u) => {
@@ -946,6 +963,7 @@ fn render_const_scalar_inner<'db>(
946963
args,
947964
b,
948965
memory_map,
966+
depth,
949967
)
950968
}
951969
}
@@ -973,7 +991,7 @@ fn render_const_scalar_inner<'db>(
973991
f.write_str(", ")?;
974992
}
975993
let offset = size_one * i;
976-
render_const_scalar(f, &b[offset..offset + size_one], memory_map, ty)?;
994+
render_const_scalar(f, &b[offset..offset + size_one], memory_map, ty, depth - 1)?;
977995
}
978996
f.write_str("]")
979997
}
@@ -1006,6 +1024,7 @@ fn render_variant_after_name<'db>(
10061024
args: GenericArgs<'db>,
10071025
b: &[u8],
10081026
memory_map: &MemoryMap<'db>,
1027+
depth: usize,
10091028
) -> Result {
10101029
let param_env = ParamEnvAndCrate { param_env, krate: f.krate() };
10111030
match data.shape {
@@ -1017,7 +1036,7 @@ fn render_variant_after_name<'db>(
10171036
return f.write_str("<layout-error>");
10181037
};
10191038
let size = layout.size.bytes_usize();
1020-
render_const_scalar(f, &b[offset..offset + size], memory_map, ty)
1039+
render_const_scalar(f, &b[offset..offset + size], memory_map, ty, depth - 1)
10211040
};
10221041
let mut it = data.fields().iter();
10231042
if matches!(data.shape, FieldsShape::Record) {

crates/ide/src/hover/tests.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11311,3 +11311,55 @@ pub trait MyTrait {
1131111311
"#]],
1131211312
);
1131311313
}
11314+
11315+
#[test]
11316+
fn hover_recursive_const_fn() {
11317+
check(
11318+
r#"
11319+
//- minicore: option
11320+
enum Child {
11321+
Static { child: &'static MyEnum },
11322+
}
11323+
11324+
enum MyEnum {
11325+
Unit,
11326+
Array(Child),
11327+
}
11328+
11329+
impl MyEnum {
11330+
pub const fn static_array(child: &'static MyEnum) -> Self {
11331+
MyEnum::Array(Child::Static { child })
11332+
}
11333+
}
11334+
11335+
pub trait MyTrait {
11336+
const MY_CONST: &'static MyEnum;
11337+
}
11338+
11339+
impl<T> MyTrait for Option<T> where T: MyTrait {
11340+
const MY_CONST: &'static MyEnum = &MyEnum::static_array(T::MY_CONST);
11341+
}
11342+
11343+
impl MyTrait for () {
11344+
const MY_CONST: &'static MyEnum = &MyEnum::Unit;
11345+
}
11346+
11347+
pub struct Address;
11348+
11349+
impl MyTrait for Address {
11350+
const MY_CONST$0: &'static MyEnum = (<Option<()> as MyTrait>::MY_CONST);
11351+
}
11352+
"#,
11353+
expect![[r#"
11354+
*MY_CONST*
11355+
11356+
```rust
11357+
ra_test_fixture::Address
11358+
```
11359+
11360+
```rust
11361+
const MY_CONST: &'static MyEnum = &Array(Static { child: &Array(Static { child: &Array(Static { child: &Array(Static { child: &Array(Static { child: &Array(Static { child: &Array(<recursion-limit>) }) }) }) }) }) })
11362+
```
11363+
"#]],
11364+
);
11365+
}

0 commit comments

Comments
 (0)