Auto merge of #17364 - roife:fix-issue-12917, r=Veykril
feat: show type bounds from containers when hovering on functions fix #12917. ### Changes 1. Added Support for displaying the container and type bounds from it when hovering on functions with generic types. 2. Added a user config to determine whether to display container bounds (enabled by default). 3. Added regression tests. 4. Simplified and refactored `hir/display.rs` to improve readability.
This commit is contained in:
commit
21e9022cda
5 changed files with 224 additions and 138 deletions
|
|
@ -512,6 +512,7 @@ dependencies = [
|
|||
"hir-def",
|
||||
"hir-expand",
|
||||
"hir-ty",
|
||||
"intern",
|
||||
"itertools",
|
||||
"once_cell",
|
||||
"rustc-hash",
|
||||
|
|
|
|||
|
|
@ -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<usize>,
|
||||
/// 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<T: HirDisplay> 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,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,10 +17,12 @@ 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,
|
||||
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,
|
||||
};
|
||||
|
|
@ -30,12 +33,42 @@ 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);
|
||||
|
||||
// Write container (trait or impl)
|
||||
let container_params = match container {
|
||||
Some(AssocItemContainer::Trait(trait_)) => {
|
||||
let params = f.db.generic_params(trait_.id.into());
|
||||
if f.show_container_bounds() && !params.is_empty() {
|
||||
write_trait_header(&trait_, f)?;
|
||||
f.write_char('\n')?;
|
||||
has_disaplayable_predicates(¶ms).then_some(params)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Some(AssocItemContainer::Impl(impl_)) => {
|
||||
let params = f.db.generic_params(impl_.id.into());
|
||||
if f.show_container_bounds() && !params.is_empty() {
|
||||
write_impl_header(&impl_, f)?;
|
||||
f.write_char('\n')?;
|
||||
has_disaplayable_predicates(¶ms).then_some(params)
|
||||
} else {
|
||||
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 {
|
||||
// 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)?;
|
||||
|
||||
if data.has_default_kw() {
|
||||
f.write_str("default ")?;
|
||||
}
|
||||
|
|
@ -116,12 +149,41 @@ 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(())
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
@ -188,7 +250,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)?,
|
||||
|
|
@ -208,7 +270,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(())
|
||||
|
|
@ -225,13 +287,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,
|
||||
|
|
@ -242,11 +304,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('{')?;
|
||||
|
||||
|
|
@ -255,14 +313,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}")?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -272,7 +327,7 @@ fn display_fields(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn display_variants(
|
||||
fn write_variants(
|
||||
variants: &[Variant],
|
||||
has_where_clause: bool,
|
||||
limit: usize,
|
||||
|
|
@ -281,30 +336,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 => {}
|
||||
}
|
||||
|
|
@ -357,7 +404,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)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -554,104 +601,98 @@ fn write_where_clause(
|
|||
f: &mut HirFormatter<'_>,
|
||||
) -> Result<bool, HirDisplayError> {
|
||||
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 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 !has_disaplayable_predicates(¶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 has_disaplayable_predicates(params: &Interned<GenericParams>) -> 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<GenericParams>,
|
||||
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<GenericParams>, 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 +730,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 +767,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)?;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue