Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/display.rs')
-rw-r--r--crates/hir/src/display.rs296
1 files changed, 171 insertions, 125 deletions
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index c276e87786..79069ed66b 100644
--- a/crates/hir/src/display.rs
+++ b/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,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(&params).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(&params).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,102 +601,96 @@ fn write_where_clause(
f: &mut HirFormatter<'_>,
) -> Result<bool, HirDisplayError> {
let params = f.db.generic_params(def);
+ if !has_disaplayable_predicates(&params) {
+ return Ok(false);
+ }
- // 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()
- }
- };
+ f.write_str("\nwhere")?;
+ write_where_predicates(&params, f)?;
- let has_displayable_predicate = params
- .where_predicates
- .iter()
- .any(|pred| {
- !matches!(pred, WherePredicate::TypeBound { target, .. } if is_unnamed_type_target(target))
- });
+ Ok(true)
+}
- if !has_displayable_predicate {
- return Ok(false);
- }
+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}"),
- }
- }
+ WherePredicateTypeTarget::TypeOrConstParam(id) => match params.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(&params.where_predicates[pred_idx - 1]) };
+ 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 new_predicate = |f: &mut HirFormatter<'_>| {
- f.write_str(if pred_idx == 0 { "\n " } else { ",\n " })
- };
+ 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 {
- 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(": ")?;
- }
+ TypeBound { target, bound } => {
+ 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())
- )?;
- }
+ Lifetime { target, bound } => {
+ let target = target.name.display(f.db.upcast());
+ let bound = bound.name.display(f.db.upcast());
+ write!(f, "{target}: {bound}")?;
}
- 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(": ")?;
- }
+ 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)?;
}
}
- }
- // End of final predicate. There must be at least one predicate here.
- f.write_char(',')?;
+ 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(true)
+ Ok(())
}
impl HirDisplay for Const {
@@ -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)?;