Auto merge of #17394 - Veykril:recurse-fix, r=Veykril

fix: Fix `HirDisplay` stackoverflow for parameter Self defaults

Fixes https://github.com/rust-lang/rust-analyzer/issues/10932
This commit is contained in:
bors 2024-06-11 15:05:26 +00:00
commit c07076b35c
2 changed files with 48 additions and 16 deletions

View file

@ -4,7 +4,7 @@
use std::{
fmt::{self, Debug},
mem::size_of,
mem::{self, size_of},
};
use base_db::CrateId;
@ -460,7 +460,7 @@ impl HirDisplay for ProjectionTy {
let proj_params_count =
self.substitution.len(Interner) - trait_ref.substitution.len(Interner);
let proj_params = &self.substitution.as_slice(Interner)[..proj_params_count];
hir_fmt_generics(f, proj_params, None)
hir_fmt_generics(f, proj_params, None, None)
}
}
@ -505,6 +505,7 @@ impl HirDisplay for Const {
f,
parameters.as_slice(Interner),
c.generic_def(f.db.upcast()),
None,
)?;
Ok(())
}
@ -1004,11 +1005,11 @@ impl HirDisplay for Ty {
let fn_params = generic_args_sans_defaults(f, Some(def.into()), fn_params);
write!(f, "<")?;
hir_fmt_generic_arguments(f, parent_params)?;
hir_fmt_generic_arguments(f, parent_params, None)?;
if !parent_params.is_empty() && !fn_params.is_empty() {
write!(f, ", ")?;
}
hir_fmt_generic_arguments(f, fn_params)?;
hir_fmt_generic_arguments(f, fn_params, None)?;
write!(f, ">")?;
}
}
@ -1053,7 +1054,7 @@ impl HirDisplay for Ty {
let generic_def = self.as_generic_def(db);
hir_fmt_generics(f, parameters.as_slice(Interner), generic_def)?;
hir_fmt_generics(f, parameters.as_slice(Interner), generic_def, None)?;
}
TyKind::AssociatedType(assoc_type_id, parameters) => {
let type_alias = from_assoc_type_id(*assoc_type_id);
@ -1076,7 +1077,7 @@ impl HirDisplay for Ty {
f.end_location_link();
// Note that the generic args for the associated type come before those for the
// trait (including the self type).
hir_fmt_generics(f, parameters.as_slice(Interner), None)
hir_fmt_generics(f, parameters.as_slice(Interner), None, None)
} else {
let projection_ty = ProjectionTy {
associated_ty_id: to_assoc_type_id(type_alias),
@ -1178,7 +1179,7 @@ impl HirDisplay for Ty {
}
ClosureStyle::ClosureWithSubst => {
write!(f, "{{closure#{:?}}}", id.0.as_u32())?;
return hir_fmt_generics(f, substs.as_slice(Interner), None);
return hir_fmt_generics(f, substs.as_slice(Interner), None, None);
}
_ => (),
}
@ -1366,6 +1367,7 @@ fn hir_fmt_generics(
f: &mut HirFormatter<'_>,
parameters: &[GenericArg],
generic_def: Option<hir_def::GenericDefId>,
self_: Option<&Ty>,
) -> Result<(), HirDisplayError> {
if parameters.is_empty() {
return Ok(());
@ -1385,7 +1387,7 @@ fn hir_fmt_generics(
});
if !parameters_to_write.is_empty() && !only_err_lifetimes {
write!(f, "<")?;
hir_fmt_generic_arguments(f, parameters_to_write)?;
hir_fmt_generic_arguments(f, parameters_to_write, self_)?;
write!(f, ">")?;
}
@ -1447,6 +1449,7 @@ fn generic_args_sans_defaults<'ga>(
fn hir_fmt_generic_arguments(
f: &mut HirFormatter<'_>,
parameters: &[GenericArg],
self_: Option<&Ty>,
) -> Result<(), HirDisplayError> {
let mut first = true;
let lifetime_offset = parameters.iter().position(|arg| arg.lifetime(Interner).is_some());
@ -1468,11 +1471,13 @@ fn hir_fmt_generic_arguments(
continue;
}
if !first {
if !mem::take(&mut first) {
write!(f, ", ")?;
}
first = false;
generic_arg.hir_fmt(f)?;
match self_ {
self_ @ Some(_) if generic_arg.ty(Interner) == self_ => write!(f, "Self")?,
_ => generic_arg.hir_fmt(f)?,
}
}
Ok(())
}
@ -1595,12 +1600,16 @@ fn write_bounds_like_dyn_trait(
write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast()))?;
f.end_location_link();
if is_fn_trait {
if let [_self, params @ ..] = trait_ref.substitution.as_slice(Interner) {
if let [self_, params @ ..] = trait_ref.substitution.as_slice(Interner) {
if let Some(args) =
params.first().and_then(|it| it.assert_ty_ref(Interner).as_tuple())
{
write!(f, "(")?;
hir_fmt_generic_arguments(f, args.as_slice(Interner))?;
hir_fmt_generic_arguments(
f,
args.as_slice(Interner),
self_.ty(Interner),
)?;
write!(f, ")")?;
}
}
@ -1610,10 +1619,10 @@ fn write_bounds_like_dyn_trait(
Some(trait_.into()),
trait_ref.substitution.as_slice(Interner),
);
if let [_self, params @ ..] = params {
if let [self_, params @ ..] = params {
if !params.is_empty() {
write!(f, "<")?;
hir_fmt_generic_arguments(f, params)?;
hir_fmt_generic_arguments(f, params, self_.ty(Interner))?;
// there might be assoc type bindings, so we leave the angle brackets open
angle_open = true;
}
@ -1671,6 +1680,7 @@ fn write_bounds_like_dyn_trait(
hir_fmt_generic_arguments(
f,
&proj.substitution.as_slice(Interner)[..proj_arg_count],
None,
)?;
write!(f, ">")?;
}
@ -1727,7 +1737,8 @@ fn fmt_trait_ref(
f.start_location_link(trait_.into());
write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast()))?;
f.end_location_link();
hir_fmt_generics(f, &tr.substitution.as_slice(Interner)[1..], None)
let substs = tr.substitution.as_slice(Interner);
hir_fmt_generics(f, &substs[1..], None, substs[0].ty(Interner))
}
impl HirDisplay for TraitRef {

View file

@ -709,4 +709,25 @@ fn main() {
"#,
)
}
// regression test for a stackoverflow in hir display code
#[test]
fn adjustment_hints_method_call_on_impl_trait_self() {
check_with_config(
InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
r#"
//- minicore: slice, coerce_unsized
trait T<RHS = Self> {}
fn hello(it: &&[impl T]) {
it.len();
//^^(
//^^&
//^^*
//^^*
//^^)
}
"#,
);
}
}