From 80a2ac568108dbe1af674a7ac6f48adf74b0619e Mon Sep 17 00:00:00 2001 From: roife Date: Sat, 8 Jun 2024 03:10:27 +0800 Subject: [PATCH 1/6] internal: simplify and refactor write_where_clause --- src/tools/rust-analyzer/Cargo.lock | 1 + src/tools/rust-analyzer/crates/hir/Cargo.toml | 1 + .../rust-analyzer/crates/hir/src/display.rs | 209 +++++++++--------- 3 files changed, 110 insertions(+), 101 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index efb313cd3c80..57d43dad3fd8 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -512,6 +512,7 @@ dependencies = [ "hir-def", "hir-expand", "hir-ty", + "intern", "itertools", "once_cell", "rustc-hash", diff --git a/src/tools/rust-analyzer/crates/hir/Cargo.toml b/src/tools/rust-analyzer/crates/hir/Cargo.toml index 6d7ecd1e50b6..edf26a07a744 100644 --- a/src/tools/rust-analyzer/crates/hir/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir/Cargo.toml @@ -27,6 +27,7 @@ cfg.workspace = true hir-def.workspace = true hir-expand.workspace = true hir-ty.workspace = true +intern.workspace = true stdx.workspace = true syntax.workspace = true tt.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index c276e87786dd..1d8bbf9de6da 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -3,7 +3,8 @@ use either::Either; use hir_def::{ data::adt::{StructKind, VariantData}, generics::{ - TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget, + GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate, + WherePredicateTypeTarget, }, lang_item::LangItem, type_ref::{TypeBound, TypeRef}, @@ -16,6 +17,8 @@ use hir_ty::{ }, AliasEq, AliasTy, Interner, ProjectionTyExt, TraitRefExt, TyKind, WhereClause, }; +use intern::Interned; +use itertools::Itertools; use crate::{ Adt, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Enum, ExternCrateDecl, @@ -30,9 +33,13 @@ impl HirDisplay for Function { let data = db.function_data(self.id); let container = self.as_assoc_item(db).map(|it| it.container(db)); let mut module = self.module(db); - if let Some(AssocItemContainer::Impl(_)) = container { - // Block-local impls are "hoisted" to the nearest (non-block) module. - module = module.nearest_non_block_module(db); + + match container { + Some(AssocItemContainer::Impl(_)) => { + // Block-local impls are "hoisted" to the nearest (non-block) module. + module = module.nearest_non_block_module(db); + } + _ => {} } let module_id = module.id; write_visibility(module_id, self.visibility(db), f)?; @@ -555,103 +562,98 @@ fn write_where_clause( ) -> Result { let params = f.db.generic_params(def); - // unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`. - let is_unnamed_type_target = |target: &WherePredicateTypeTarget| match target { - WherePredicateTypeTarget::TypeRef(_) => false, - WherePredicateTypeTarget::TypeOrConstParam(id) => { - params.type_or_consts[*id].name().is_none() - } + let no_displayable_pred = |params: &Interned| { + params.where_predicates.iter().all(|pred| { + matches!( + pred, + WherePredicate::TypeBound { target: WherePredicateTypeTarget::TypeOrConstParam(id), .. } + if params.type_or_consts[*id].name().is_none() + ) + }) }; - let has_displayable_predicate = params - .where_predicates - .iter() - .any(|pred| { - !matches!(pred, WherePredicate::TypeBound { target, .. } if is_unnamed_type_target(target)) - }); - - if !has_displayable_predicate { + if no_displayable_pred(¶ms) { return Ok(false); } - let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter<'_>| match target { - WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f), - WherePredicateTypeTarget::TypeOrConstParam(id) => { - match ¶ms.type_or_consts[*id].name() { - Some(name) => write!(f, "{}", name.display(f.db.upcast())), - None => f.write_str("{unnamed}"), - } - } - }; - f.write_str("\nwhere")?; - - for (pred_idx, pred) in params.where_predicates.iter().enumerate() { - let prev_pred = - if pred_idx == 0 { None } else { Some(¶ms.where_predicates[pred_idx - 1]) }; - - let new_predicate = |f: &mut HirFormatter<'_>| { - f.write_str(if pred_idx == 0 { "\n " } else { ",\n " }) - }; - - match pred { - WherePredicate::TypeBound { target, .. } if is_unnamed_type_target(target) => {} - WherePredicate::TypeBound { target, bound } => { - if matches!(prev_pred, Some(WherePredicate::TypeBound { target: target_, .. }) if target_ == target) - { - f.write_str(" + ")?; - } else { - new_predicate(f)?; - write_target(target, f)?; - f.write_str(": ")?; - } - bound.hir_fmt(f)?; - } - WherePredicate::Lifetime { target, bound } => { - if matches!(prev_pred, Some(WherePredicate::Lifetime { target: target_, .. }) if target_ == target) - { - write!(f, " + {}", bound.name.display(f.db.upcast()))?; - } else { - new_predicate(f)?; - write!( - f, - "{}: {}", - target.name.display(f.db.upcast()), - bound.name.display(f.db.upcast()) - )?; - } - } - WherePredicate::ForLifetime { lifetimes, target, bound } => { - if matches!( - prev_pred, - Some(WherePredicate::ForLifetime { lifetimes: lifetimes_, target: target_, .. }) - if lifetimes_ == lifetimes && target_ == target, - ) { - f.write_str(" + ")?; - } else { - new_predicate(f)?; - f.write_str("for<")?; - for (idx, lifetime) in lifetimes.iter().enumerate() { - if idx != 0 { - f.write_str(", ")?; - } - write!(f, "{}", lifetime.display(f.db.upcast()))?; - } - f.write_str("> ")?; - write_target(target, f)?; - f.write_str(": ")?; - } - bound.hir_fmt(f)?; - } - } - } - - // End of final predicate. There must be at least one predicate here. - f.write_char(',')?; + write_where_predicates(¶ms, f)?; Ok(true) } +fn write_where_predicates( + params: &Interned, + f: &mut HirFormatter<'_>, +) -> Result<(), HirDisplayError> { + use WherePredicate::*; + + // unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`. + let is_unnamed_type_target = + |params: &Interned, target: &WherePredicateTypeTarget| { + matches!(target, + WherePredicateTypeTarget::TypeOrConstParam(id) if params.type_or_consts[*id].name().is_none() + ) + }; + + let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter<'_>| match target { + WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f), + WherePredicateTypeTarget::TypeOrConstParam(id) => match params.type_or_consts[*id].name() { + Some(name) => write!(f, "{}", name.display(f.db.upcast())), + None => f.write_str("{unnamed}"), + }, + }; + + let check_same_target = |pred1: &WherePredicate, pred2: &WherePredicate| match (pred1, pred2) { + (TypeBound { target: t1, .. }, TypeBound { target: t2, .. }) => t1 == t2, + (Lifetime { target: t1, .. }, Lifetime { target: t2, .. }) => t1 == t2, + ( + ForLifetime { lifetimes: l1, target: t1, .. }, + ForLifetime { lifetimes: l2, target: t2, .. }, + ) => l1 == l2 && t1 == t2, + _ => false, + }; + + let mut iter = params.where_predicates.iter().peekable(); + while let Some(pred) = iter.next() { + if matches!(pred, TypeBound { target, .. } if is_unnamed_type_target(params, target)) { + continue; + } + + f.write_str("\n ")?; + match pred { + TypeBound { target, bound } => { + write_target(target, f)?; + f.write_str(": ")?; + bound.hir_fmt(f)?; + } + Lifetime { target, bound } => { + let target = target.name.display(f.db.upcast()); + let bound = bound.name.display(f.db.upcast()); + write!(f, "{target}: {bound}")?; + } + ForLifetime { lifetimes, target, bound } => { + let lifetimes = lifetimes.iter().map(|it| it.display(f.db.upcast())).join(", "); + write!(f, "for<{lifetimes}> ")?; + write_target(target, f)?; + f.write_str(": ")?; + bound.hir_fmt(f)?; + } + } + + while let Some(nxt) = iter.next_if(|nxt| check_same_target(pred, nxt)) { + f.write_str(" + ")?; + match nxt { + TypeBound { bound, .. } | ForLifetime { bound, .. } => bound.hir_fmt(f)?, + Lifetime { bound, .. } => write!(f, "{}", bound.name.display(f.db.upcast()))?, + } + } + f.write_str(",")?; + } + + Ok(()) +} + impl HirDisplay for Const { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { let db = f.db; @@ -689,17 +691,8 @@ impl HirDisplay for Static { impl HirDisplay for Trait { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; - let data = f.db.trait_data(self.id); - if data.is_unsafe { - f.write_str("unsafe ")?; - } - if data.is_auto { - f.write_str("auto ")?; - } - write!(f, "trait {}", data.name.display(f.db.upcast()))?; + write_trait_header(self, f)?; let def_id = GenericDefId::TraitId(self.id); - write_generic_params(def_id, f)?; let has_where_clause = write_where_clause(def_id, f)?; if let Some(limit) = f.entity_limit { @@ -735,6 +728,20 @@ impl HirDisplay for Trait { } } +fn write_trait_header(trait_: &Trait, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { + write_visibility(trait_.module(f.db).id, trait_.visibility(f.db), f)?; + let data = f.db.trait_data(trait_.id); + if data.is_unsafe { + f.write_str("unsafe ")?; + } + if data.is_auto { + f.write_str("auto ")?; + } + write!(f, "trait {}", data.name.display(f.db.upcast()))?; + write_generic_params(GenericDefId::TraitId(trait_.id), f)?; + Ok(()) +} + impl HirDisplay for TraitAlias { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; From e5f859868e18f78073330d5d05548c98f7ce192a Mon Sep 17 00:00:00 2001 From: roife Date: Sat, 8 Jun 2024 03:16:22 +0800 Subject: [PATCH 2/6] feat: show type bounds from containers for functions --- .../rust-analyzer/crates/hir/src/display.rs | 52 +++++++++++++++++-- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 1d8bbf9de6da..7e16fbf21e9e 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -8,7 +8,7 @@ use hir_def::{ }, lang_item::LangItem, type_ref::{TypeBound, TypeRef}, - AdtId, GenericDefId, + AdtId, GenericDefId, ItemContainerId, ItemTreeLoc, Lookup, }; use hir_ty::{ display::{ @@ -22,7 +22,7 @@ use itertools::Itertools; use crate::{ Adt, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Enum, ExternCrateDecl, - Field, Function, GenericParam, HasCrate, HasVisibility, LifetimeParam, Macro, Module, + Field, Function, GenericParam, HasCrate, HasVisibility, Impl, LifetimeParam, Macro, Module, SelfParam, Static, Struct, Trait, TraitAlias, TupleField, TyBuilder, Type, TypeAlias, TypeOrConstParam, TypeParam, Union, Variant, }; @@ -35,11 +35,18 @@ impl HirDisplay for Function { let mut module = self.module(db); match container { - Some(AssocItemContainer::Impl(_)) => { + Some(AssocItemContainer::Trait(trait_)) => { + write_trait_header(&trait_, f)?; + f.write_str("\n")?; + } + Some(AssocItemContainer::Impl(impl_)) => { + write_impl_header(&impl_, f)?; + f.write_str("\n")?; + // Block-local impls are "hoisted" to the nearest (non-block) module. module = module.nearest_non_block_module(db); } - _ => {} + None => {} } let module_id = module.id; write_visibility(module_id, self.visibility(db), f)?; @@ -129,6 +136,24 @@ impl HirDisplay for Function { } } +fn write_impl_header(impl_: &Impl, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { + let db = f.db; + + f.write_str("impl")?; + let def_id = GenericDefId::ImplId(impl_.id); + write_generic_params(def_id, f)?; + + if let Some(trait_) = impl_.trait_(db) { + let trait_data = db.trait_data(trait_.id); + write!(f, " {} for", trait_data.name.display(db.upcast()))?; + } + + f.write_char(' ')?; + impl_.self_ty(db).hir_fmt(f)?; + + Ok(()) +} + impl HirDisplay for SelfParam { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { let data = f.db.function_data(self.func); @@ -562,6 +587,16 @@ fn write_where_clause( ) -> Result { let params = f.db.generic_params(def); + let container = match def { + GenericDefId::FunctionId(id) => match id.lookup(f.db.upcast()).container() { + ItemContainerId::ImplId(it) => Some(("impl", it.into())), + ItemContainerId::TraitId(it) => Some(("trait", it.into())), + _ => None, + } + .map(|(name, def)| (name, f.db.generic_params(def))), + _ => None, + }; + let no_displayable_pred = |params: &Interned| { params.where_predicates.iter().all(|pred| { matches!( @@ -572,13 +607,20 @@ fn write_where_clause( }) }; - if no_displayable_pred(¶ms) { + if no_displayable_pred(¶ms) + && container.as_ref().map_or(true, |(_, p)| no_displayable_pred(p)) + { return Ok(false); } f.write_str("\nwhere")?; write_where_predicates(¶ms, f)?; + if let Some((name, container_params)) = container { + write!(f, "\n // Bounds from {}:", name)?; + write_where_predicates(&container_params, f)?; + } + Ok(true) } From 445e8866a3fa9a8614b82eebbdfdd04b433ebb9b Mon Sep 17 00:00:00 2001 From: roife Date: Tue, 11 Jun 2024 20:59:06 +0800 Subject: [PATCH 3/6] feat: add hover config for showing container bounds --- .../crates/hir-ty/src/display.rs | 37 +++++++++++++++++++ .../rust-analyzer/crates/hir/src/display.rs | 36 +++++++++++------- .../crates/ide/src/hover/render.rs | 1 + 3 files changed, 60 insertions(+), 14 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index f035dd11e1f5..5e3996f65ab0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -74,6 +74,8 @@ pub struct HirFormatter<'a> { /// When rendering something that has a concept of "children" (like fields in a struct), this limits /// how many should be rendered. pub entity_limit: Option, + /// When rendering functions, whether to show the constraint from the container + show_container_bounds: bool, omit_verbose_types: bool, closure_style: ClosureStyle, display_target: DisplayTarget, @@ -101,6 +103,7 @@ pub trait HirDisplay { omit_verbose_types: bool, display_target: DisplayTarget, closure_style: ClosureStyle, + show_container_bounds: bool, ) -> HirDisplayWrapper<'a, Self> where Self: Sized, @@ -117,6 +120,7 @@ pub trait HirDisplay { omit_verbose_types, display_target, closure_style, + show_container_bounds, } } @@ -134,6 +138,7 @@ pub trait HirDisplay { omit_verbose_types: false, closure_style: ClosureStyle::ImplFn, display_target: DisplayTarget::Diagnostics, + show_container_bounds: false, } } @@ -155,6 +160,7 @@ pub trait HirDisplay { omit_verbose_types: true, closure_style: ClosureStyle::ImplFn, display_target: DisplayTarget::Diagnostics, + show_container_bounds: false, } } @@ -176,6 +182,7 @@ pub trait HirDisplay { omit_verbose_types: true, closure_style: ClosureStyle::ImplFn, display_target: DisplayTarget::Diagnostics, + show_container_bounds: false, } } @@ -198,6 +205,7 @@ pub trait HirDisplay { omit_verbose_types: false, closure_style: ClosureStyle::ImplFn, display_target: DisplayTarget::SourceCode { module_id, allow_opaque }, + show_container_bounds: false, }) { Ok(()) => {} Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"), @@ -219,6 +227,29 @@ pub trait HirDisplay { omit_verbose_types: false, closure_style: ClosureStyle::ImplFn, display_target: DisplayTarget::Test, + show_container_bounds: false, + } + } + + /// Returns a String representation of `self` that shows the constraint from + /// the container for functions + fn display_with_container_bounds<'a>( + &'a self, + db: &'a dyn HirDatabase, + show_container_bounds: bool, + ) -> HirDisplayWrapper<'a, Self> + where + Self: Sized, + { + HirDisplayWrapper { + db, + t: self, + max_size: None, + limited_size: None, + omit_verbose_types: false, + closure_style: ClosureStyle::ImplFn, + display_target: DisplayTarget::Diagnostics, + show_container_bounds, } } } @@ -277,6 +308,10 @@ impl HirFormatter<'_> { pub fn omit_verbose_types(&self) -> bool { self.omit_verbose_types } + + pub fn show_container_bounds(&self) -> bool { + self.show_container_bounds + } } #[derive(Clone, Copy)] @@ -336,6 +371,7 @@ pub struct HirDisplayWrapper<'a, T> { omit_verbose_types: bool, closure_style: ClosureStyle, display_target: DisplayTarget, + show_container_bounds: bool, } #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -365,6 +401,7 @@ impl HirDisplayWrapper<'_, T> { omit_verbose_types: self.omit_verbose_types, display_target: self.display_target, closure_style: self.closure_style, + show_container_bounds: self.show_container_bounds, }) } diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 7e16fbf21e9e..90deee0b01e6 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -36,12 +36,16 @@ impl HirDisplay for Function { match container { Some(AssocItemContainer::Trait(trait_)) => { - write_trait_header(&trait_, f)?; - f.write_str("\n")?; + if f.show_container_bounds() { + write_trait_header(&trait_, f)?; + f.write_str("\n")?; + } } Some(AssocItemContainer::Impl(impl_)) => { - write_impl_header(&impl_, f)?; - f.write_str("\n")?; + if f.show_container_bounds() { + write_impl_header(&impl_, f)?; + f.write_str("\n")?; + } // Block-local impls are "hoisted" to the nearest (non-block) module. module = module.nearest_non_block_module(db); @@ -588,12 +592,14 @@ fn write_where_clause( let params = f.db.generic_params(def); let container = match def { - GenericDefId::FunctionId(id) => match id.lookup(f.db.upcast()).container() { - ItemContainerId::ImplId(it) => Some(("impl", it.into())), - ItemContainerId::TraitId(it) => Some(("trait", it.into())), - _ => None, + GenericDefId::FunctionId(id) if f.show_container_bounds() => { + match id.lookup(f.db.upcast()).container() { + ItemContainerId::ImplId(it) => Some(("impl", it.into())), + ItemContainerId::TraitId(it) => Some(("trait", it.into())), + _ => None, + } + .map(|(name, def)| (name, f.db.generic_params(def))) } - .map(|(name, def)| (name, f.db.generic_params(def))), _ => None, }; @@ -607,9 +613,9 @@ fn write_where_clause( }) }; - if no_displayable_pred(¶ms) - && container.as_ref().map_or(true, |(_, p)| no_displayable_pred(p)) - { + let container_bounds_no_displayable = + container.as_ref().map_or(true, |(_, p)| no_displayable_pred(p)); + if no_displayable_pred(¶ms) && container_bounds_no_displayable { return Ok(false); } @@ -617,8 +623,10 @@ fn write_where_clause( write_where_predicates(¶ms, f)?; if let Some((name, container_params)) = container { - write!(f, "\n // Bounds from {}:", name)?; - write_where_predicates(&container_params, f)?; + if !container_bounds_no_displayable { + write!(f, "\n // Bounds from {}:", name)?; + write_where_predicates(&container_params, f)?; + } } Ok(true) diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index 3bc17f95e70d..99568c9922b5 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -430,6 +430,7 @@ pub(super) fn definition( } label } + Definition::Function(fn_) => fn_.display_with_container_bounds(db, true).to_string(), _ => def.label(db), }; let docs = def.docs(db, famous_defs); From 687889c5c38e9b6d458870fa551640abb903be78 Mon Sep 17 00:00:00 2001 From: roife Date: Sat, 8 Jun 2024 02:47:33 +0800 Subject: [PATCH 4/6] internal: simplify and rename display_xxx to write_xxx for consistency --- .../rust-analyzer/crates/hir/src/display.rs | 51 +++++++------------ 1 file changed, 18 insertions(+), 33 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 90deee0b01e6..1ecbfadf977d 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -224,7 +224,7 @@ impl HirDisplay for Struct { StructKind::Record => { let has_where_clause = write_where_clause(def_id, f)?; if let Some(limit) = f.entity_limit { - display_fields(&self.fields(f.db), has_where_clause, limit, false, f)?; + write_fields(&self.fields(f.db), has_where_clause, limit, false, f)?; } } StructKind::Unit => _ = write_where_clause(def_id, f)?, @@ -244,7 +244,7 @@ impl HirDisplay for Enum { let has_where_clause = write_where_clause(def_id, f)?; if let Some(limit) = f.entity_limit { - display_variants(&self.variants(f.db), has_where_clause, limit, f)?; + write_variants(&self.variants(f.db), has_where_clause, limit, f)?; } Ok(()) @@ -261,13 +261,13 @@ impl HirDisplay for Union { let has_where_clause = write_where_clause(def_id, f)?; if let Some(limit) = f.entity_limit { - display_fields(&self.fields(f.db), has_where_clause, limit, false, f)?; + write_fields(&self.fields(f.db), has_where_clause, limit, false, f)?; } Ok(()) } } -fn display_fields( +fn write_fields( fields: &[Field], has_where_clause: bool, limit: usize, @@ -278,11 +278,7 @@ fn display_fields( let (indent, separator) = if in_line { ("", ' ') } else { (" ", '\n') }; f.write_char(if !has_where_clause { ' ' } else { separator })?; if count == 0 { - if fields.is_empty() { - f.write_str("{}")?; - } else { - f.write_str("{ /* … */ }")?; - } + f.write_str(if fields.is_empty() { "{}" } else { "{ /* … */ }" })?; } else { f.write_char('{')?; @@ -291,14 +287,11 @@ fn display_fields( for field in &fields[..count] { f.write_str(indent)?; field.hir_fmt(f)?; - f.write_char(',')?; - f.write_char(separator)?; + write!(f, ",{separator}")?; } if fields.len() > count { - f.write_str(indent)?; - f.write_str("/* … */")?; - f.write_char(separator)?; + write!(f, "{indent}/* … */{separator}")?; } } @@ -308,7 +301,7 @@ fn display_fields( Ok(()) } -fn display_variants( +fn write_variants( variants: &[Variant], has_where_clause: bool, limit: usize, @@ -317,30 +310,22 @@ fn display_variants( let count = variants.len().min(limit); f.write_char(if !has_where_clause { ' ' } else { '\n' })?; if count == 0 { - if variants.is_empty() { - f.write_str("{}")?; - } else { - f.write_str("{ /* … */ }")?; - } + let variants = if variants.is_empty() { "{}" } else { "{ /* … */ }" }; + f.write_str(variants)?; } else { f.write_str("{\n")?; for variant in &variants[..count] { - f.write_str(" ")?; - write!(f, "{}", variant.name(f.db).display(f.db.upcast()))?; + write!(f, " {}", variant.name(f.db).display(f.db.upcast()))?; match variant.kind(f.db) { StructKind::Tuple => { - if variant.fields(f.db).is_empty() { - f.write_str("()")?; - } else { - f.write_str("( /* … */ )")?; - } + let fields_str = + if variant.fields(f.db).is_empty() { "()" } else { "( /* … */ )" }; + f.write_str(fields_str)?; } StructKind::Record => { - if variant.fields(f.db).is_empty() { - f.write_str(" {}")?; - } else { - f.write_str(" { /* … */ }")?; - } + let fields_str = + if variant.fields(f.db).is_empty() { " {}" } else { " { /* … */ }" }; + f.write_str(fields_str)?; } StructKind::Unit => {} } @@ -393,7 +378,7 @@ impl HirDisplay for Variant { } VariantData::Record(_) => { if let Some(limit) = f.entity_limit { - display_fields(&self.fields(f.db), false, limit, true, f)?; + write_fields(&self.fields(f.db), false, limit, true, f)?; } } } From 6c122f699010d90b5542a20b0cf64f1396850bf0 Mon Sep 17 00:00:00 2001 From: roife Date: Sat, 8 Jun 2024 13:07:22 +0800 Subject: [PATCH 5/6] fix: skip container header if no generics params --- src/tools/rust-analyzer/crates/hir/src/display.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 1ecbfadf977d..36b50645eb11 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -36,13 +36,13 @@ impl HirDisplay for Function { match container { Some(AssocItemContainer::Trait(trait_)) => { - if f.show_container_bounds() { + if f.show_container_bounds() && !f.db.generic_params(trait_.id.into()).is_empty() { write_trait_header(&trait_, f)?; f.write_str("\n")?; } } Some(AssocItemContainer::Impl(impl_)) => { - if f.show_container_bounds() { + if f.show_container_bounds() && !f.db.generic_params(impl_.id.into()).is_empty() { write_impl_header(&impl_, f)?; f.write_str("\n")?; } From 668327a672161aa68f965293266fe6fff44bd396 Mon Sep 17 00:00:00 2001 From: roife Date: Tue, 11 Jun 2024 20:20:59 +0800 Subject: [PATCH 6/6] refactor: move the logic that displays container type bounds to function fmt --- .../rust-analyzer/crates/hir/src/display.rs | 94 ++++++++++--------- 1 file changed, 49 insertions(+), 45 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 36b50645eb11..79069ed66bf0 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -8,7 +8,7 @@ use hir_def::{ }, lang_item::LangItem, type_ref::{TypeBound, TypeRef}, - AdtId, GenericDefId, ItemContainerId, ItemTreeLoc, Lookup, + AdtId, GenericDefId, }; use hir_ty::{ display::{ @@ -34,26 +34,41 @@ impl HirDisplay for Function { let container = self.as_assoc_item(db).map(|it| it.container(db)); let mut module = self.module(db); - match container { + // Write container (trait or impl) + let container_params = match container { Some(AssocItemContainer::Trait(trait_)) => { - if f.show_container_bounds() && !f.db.generic_params(trait_.id.into()).is_empty() { + let params = f.db.generic_params(trait_.id.into()); + if f.show_container_bounds() && !params.is_empty() { write_trait_header(&trait_, f)?; - f.write_str("\n")?; + f.write_char('\n')?; + has_disaplayable_predicates(¶ms).then_some(params) + } else { + None } } Some(AssocItemContainer::Impl(impl_)) => { - if f.show_container_bounds() && !f.db.generic_params(impl_.id.into()).is_empty() { + let params = f.db.generic_params(impl_.id.into()); + if f.show_container_bounds() && !params.is_empty() { write_impl_header(&impl_, f)?; - f.write_str("\n")?; + f.write_char('\n')?; + has_disaplayable_predicates(¶ms).then_some(params) + } else { + None } - - // Block-local impls are "hoisted" to the nearest (non-block) module. - module = module.nearest_non_block_module(db); } - None => {} + None => None, + }; + + // Write signature of the function + + // Block-local impls are "hoisted" to the nearest (non-block) module. + if let Some(AssocItemContainer::Impl(_)) = container { + module = module.nearest_non_block_module(db); } let module_id = module.id; + write_visibility(module_id, self.visibility(db), f)?; + if data.has_default_kw() { f.write_str("default ")?; } @@ -134,8 +149,19 @@ impl HirDisplay for Function { } } - write_where_clause(GenericDefId::FunctionId(self.id), f)?; - + // Write where clauses + let has_written_where = write_where_clause(GenericDefId::FunctionId(self.id), f)?; + if let Some(container_params) = container_params { + if !has_written_where { + f.write_str("\nwhere")?; + } + let container_name = match container.unwrap() { + AssocItemContainer::Trait(_) => "trait", + AssocItemContainer::Impl(_) => "impl", + }; + write!(f, "\n // Bounds from {container_name}:",)?; + write_where_predicates(&container_params, f)?; + } Ok(()) } } @@ -575,48 +601,26 @@ fn write_where_clause( f: &mut HirFormatter<'_>, ) -> Result { let params = f.db.generic_params(def); - - let container = match def { - GenericDefId::FunctionId(id) if f.show_container_bounds() => { - match id.lookup(f.db.upcast()).container() { - ItemContainerId::ImplId(it) => Some(("impl", it.into())), - ItemContainerId::TraitId(it) => Some(("trait", it.into())), - _ => None, - } - .map(|(name, def)| (name, f.db.generic_params(def))) - } - _ => None, - }; - - let no_displayable_pred = |params: &Interned| { - params.where_predicates.iter().all(|pred| { - matches!( - pred, - WherePredicate::TypeBound { target: WherePredicateTypeTarget::TypeOrConstParam(id), .. } - if params.type_or_consts[*id].name().is_none() - ) - }) - }; - - let container_bounds_no_displayable = - container.as_ref().map_or(true, |(_, p)| no_displayable_pred(p)); - if no_displayable_pred(¶ms) && container_bounds_no_displayable { + if !has_disaplayable_predicates(¶ms) { return Ok(false); } f.write_str("\nwhere")?; write_where_predicates(¶ms, f)?; - if let Some((name, container_params)) = container { - if !container_bounds_no_displayable { - write!(f, "\n // Bounds from {}:", name)?; - write_where_predicates(&container_params, f)?; - } - } - Ok(true) } +fn has_disaplayable_predicates(params: &Interned) -> bool { + params.where_predicates.iter().any(|pred| { + !matches!( + pred, + WherePredicate::TypeBound { target: WherePredicateTypeTarget::TypeOrConstParam(id), .. } + if params.type_or_consts[*id].name().is_none() + ) + }) +} + fn write_where_predicates( params: &Interned, f: &mut HirFormatter<'_>,