diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index 5e3996f65a..ff78fe0d54 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -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, + 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 { diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs index 20128a286f..7932d8efbc 100644 --- a/crates/ide/src/inlay_hints/adjustment.rs +++ b/crates/ide/src/inlay_hints/adjustment.rs @@ -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 {} + +fn hello(it: &&[impl T]) { + it.len(); + //^^( + //^^& + //^^* + //^^* + //^^) +} +"#, + ); + } }