Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/display.rs')
-rw-r--r--crates/hir-ty/src/display.rs264
1 files changed, 134 insertions, 130 deletions
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index 43b428c3fa..d680588645 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -10,16 +10,18 @@ use std::{
use base_db::{Crate, FxIndexMap};
use either::Either;
use hir_def::{
- FindPathConfig, GenericDefId, GenericParamId, HasModule, LocalFieldId, Lookup, ModuleDefId,
- ModuleId, TraitId,
- db::DefDatabase,
+ ExpressionStoreOwnerId, FindPathConfig, GenericDefId, GenericParamId, HasModule, LocalFieldId,
+ Lookup, ModuleDefId, ModuleId, TraitId,
expr_store::{ExpressionStore, path::Path},
find_path::{self, PrefixKind},
- hir::generics::{TypeOrConstParamData, TypeParamProvenance, WherePredicate},
+ hir::generics::{GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate},
item_scope::ItemInNs,
item_tree::FieldsShape,
lang_item::LangItems,
- signatures::VariantFields,
+ signatures::{
+ EnumSignature, FunctionSignature, StructSignature, TraitSignature, TypeAliasSignature,
+ UnionSignature, VariantFields,
+ },
type_ref::{
ConstRef, LifetimeRef, LifetimeRefId, TraitBoundModifier, TypeBound, TypeRef, TypeRefId,
UseArgRef,
@@ -100,6 +102,9 @@ pub struct HirFormatter<'a, 'db> {
display_kind: DisplayKind,
display_target: DisplayTarget,
bounds_formatting_ctx: BoundsFormattingCtx<'db>,
+ /// Whether formatting `impl Trait1 + Trait2` or `dyn Trait1 + Trait2` needs parentheses around it,
+ /// for example when formatting `&(impl Trait1 + Trait2)`.
+ trait_bounds_need_parens: bool,
}
// FIXME: To consider, ref and dyn trait lifetimes can be omitted if they are `'_`, path args should
@@ -331,6 +336,7 @@ pub trait HirDisplay<'db> {
show_container_bounds: false,
display_lifetimes: DisplayLifetime::OnlyNamedOrStatic,
bounds_formatting_ctx: Default::default(),
+ trait_bounds_need_parens: false,
}) {
Ok(()) => {}
Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"),
@@ -566,6 +572,7 @@ impl<'db, T: HirDisplay<'db>> HirDisplayWrapper<'_, 'db, T> {
show_container_bounds: self.show_container_bounds,
display_lifetimes: self.display_lifetimes,
bounds_formatting_ctx: Default::default(),
+ trait_bounds_need_parens: false,
})
}
@@ -612,7 +619,11 @@ impl<'db, T: HirDisplay<'db> + Internable> HirDisplay<'db> for Interned<T> {
}
}
-fn write_projection<'db>(f: &mut HirFormatter<'_, 'db>, alias: &AliasTy<'db>) -> Result {
+fn write_projection<'db>(
+ f: &mut HirFormatter<'_, 'db>,
+ alias: &AliasTy<'db>,
+ needs_parens_if_multi: bool,
+) -> Result {
if f.should_truncate() {
return write!(f, "{TYPE_HINT_TRUNCATION}");
}
@@ -650,6 +661,7 @@ fn write_projection<'db>(f: &mut HirFormatter<'_, 'db>, alias: &AliasTy<'db>) ->
Either::Left(Ty::new_alias(f.interner, AliasTyKind::Projection, *alias)),
&bounds,
SizedByDefault::NotSized,
+ needs_parens_if_multi,
)
});
}
@@ -662,7 +674,9 @@ fn write_projection<'db>(f: &mut HirFormatter<'_, 'db>, alias: &AliasTy<'db>) ->
write!(
f,
">::{}",
- f.db.type_alias_signature(alias.def_id.expect_type_alias()).name.display(f.db, f.edition())
+ TypeAliasSignature::of(f.db, alias.def_id.expect_type_alias())
+ .name
+ .display(f.db, f.edition())
)?;
let proj_params = &alias.args.as_slice()[trait_ref.args.len()..];
hir_fmt_generics(f, proj_params, None, None)
@@ -844,7 +858,7 @@ fn render_const_scalar_inner<'db>(
}
TyKind::Adt(adt, _) if b.len() == 2 * size_of::<usize>() => match adt.def_id().0 {
hir_def::AdtId::StructId(s) => {
- let data = f.db.struct_signature(s);
+ let data = StructSignature::of(f.db, s);
write!(f, "&{}", data.name.display(f.db, f.edition()))?;
Ok(())
}
@@ -902,14 +916,16 @@ fn render_const_scalar_inner<'db>(
};
match def {
hir_def::AdtId::StructId(s) => {
- let data = f.db.struct_signature(s);
+ let data = StructSignature::of(f.db, s);
write!(f, "{}", data.name.display(f.db, f.edition()))?;
let field_types = f.db.field_types(s.into());
render_variant_after_name(
s.fields(f.db),
f,
field_types,
- f.db.trait_environment(def.into()),
+ f.db.trait_environment(ExpressionStoreOwnerId::from(GenericDefId::from(
+ def,
+ ))),
&layout,
args,
b,
@@ -917,7 +933,7 @@ fn render_const_scalar_inner<'db>(
)
}
hir_def::AdtId::UnionId(u) => {
- write!(f, "{}", f.db.union_signature(u).name.display(f.db, f.edition()))
+ write!(f, "{}", UnionSignature::of(f.db, u).name.display(f.db, f.edition()))
}
hir_def::AdtId::EnumId(e) => {
let Ok(target_data_layout) = f.db.target_data_layout(f.krate()) else {
@@ -941,7 +957,9 @@ fn render_const_scalar_inner<'db>(
var_id.fields(f.db),
f,
field_types,
- f.db.trait_environment(def.into()),
+ f.db.trait_environment(ExpressionStoreOwnerId::from(GenericDefId::from(
+ def,
+ ))),
var_layout,
args,
b,
@@ -1056,7 +1074,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
return write!(f, "{TYPE_HINT_TRUNCATION}");
}
- use TyKind;
+ let trait_bounds_need_parens = mem::replace(&mut f.trait_bounds_need_parens, false);
match self.kind() {
TyKind::Never => write!(f, "!")?,
TyKind::Str => write!(f, "str")?,
@@ -1077,103 +1095,34 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
c.hir_fmt(f)?;
write!(f, "]")?;
}
- kind @ (TyKind::RawPtr(t, m) | TyKind::Ref(_, t, m)) => {
- if let TyKind::Ref(l, _, _) = kind {
- f.write_char('&')?;
- if f.render_region(l) {
- l.hir_fmt(f)?;
- f.write_char(' ')?;
- }
- match m {
- rustc_ast_ir::Mutability::Not => (),
- rustc_ast_ir::Mutability::Mut => f.write_str("mut ")?,
- }
- } else {
- write!(
- f,
- "*{}",
- match m {
- rustc_ast_ir::Mutability::Not => "const ",
- rustc_ast_ir::Mutability::Mut => "mut ",
- }
- )?;
+ TyKind::Ref(l, t, m) => {
+ f.write_char('&')?;
+ if f.render_region(l) {
+ l.hir_fmt(f)?;
+ f.write_char(' ')?;
+ }
+ match m {
+ rustc_ast_ir::Mutability::Not => (),
+ rustc_ast_ir::Mutability::Mut => f.write_str("mut ")?,
}
- // FIXME: all this just to decide whether to use parentheses...
- let (preds_to_print, has_impl_fn_pred) = match t.kind() {
- TyKind::Dynamic(bounds, region) => {
- let contains_impl_fn =
- bounds.iter().any(|bound| match bound.skip_binder() {
- ExistentialPredicate::Trait(trait_ref) => {
- let trait_ = trait_ref.def_id.0;
- fn_traits(f.lang_items()).any(|it| it == trait_)
- }
- _ => false,
- });
- let render_lifetime = f.render_region(region);
- (bounds.len() + render_lifetime as usize, contains_impl_fn)
- }
- TyKind::Alias(AliasTyKind::Opaque, ty) => {
- let opaque_ty_id = match ty.def_id {
- SolverDefId::InternedOpaqueTyId(id) => id,
- _ => unreachable!(),
- };
- let impl_trait_id = db.lookup_intern_impl_trait_id(opaque_ty_id);
- if let ImplTraitId::ReturnTypeImplTrait(func, _) = impl_trait_id {
- let data = impl_trait_id.predicates(db);
- let bounds =
- || data.iter_instantiated_copied(f.interner, ty.args.as_slice());
- let mut len = bounds().count();
-
- // Don't count Sized but count when it absent
- // (i.e. when explicit ?Sized bound is set).
- let default_sized = SizedByDefault::Sized { anchor: func.krate(db) };
- let sized_bounds = bounds()
- .filter(|b| {
- matches!(
- b.kind().skip_binder(),
- ClauseKind::Trait(trait_ref)
- if default_sized.is_sized_trait(
- trait_ref.def_id().0,
- db,
- ),
- )
- })
- .count();
- match sized_bounds {
- 0 => len += 1,
- _ => {
- len = len.saturating_sub(sized_bounds);
- }
- }
-
- let contains_impl_fn = bounds().any(|bound| {
- if let ClauseKind::Trait(trait_ref) = bound.kind().skip_binder() {
- let trait_ = trait_ref.def_id().0;
- fn_traits(f.lang_items()).any(|it| it == trait_)
- } else {
- false
- }
- });
- (len, contains_impl_fn)
- } else {
- (0, false)
- }
+ f.trait_bounds_need_parens = true;
+ t.hir_fmt(f)?;
+ f.trait_bounds_need_parens = false;
+ }
+ TyKind::RawPtr(t, m) => {
+ write!(
+ f,
+ "*{}",
+ match m {
+ rustc_ast_ir::Mutability::Not => "const ",
+ rustc_ast_ir::Mutability::Mut => "mut ",
}
- _ => (0, false),
- };
-
- if has_impl_fn_pred && preds_to_print <= 2 {
- return t.hir_fmt(f);
- }
+ )?;
- if preds_to_print > 1 {
- write!(f, "(")?;
- t.hir_fmt(f)?;
- write!(f, ")")?;
- } else {
- t.hir_fmt(f)?;
- }
+ f.trait_bounds_need_parens = true;
+ t.hir_fmt(f)?;
+ f.trait_bounds_need_parens = false;
}
TyKind::Tuple(tys) => {
if tys.len() == 1 {
@@ -1212,11 +1161,13 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
write!(f, "fn ")?;
f.start_location_link(def.into());
match def {
- CallableDefId::FunctionId(ff) => {
- write!(f, "{}", db.function_signature(ff).name.display(f.db, f.edition()))?
- }
+ CallableDefId::FunctionId(ff) => write!(
+ f,
+ "{}",
+ FunctionSignature::of(db, ff).name.display(f.db, f.edition())
+ )?,
CallableDefId::StructId(s) => {
- write!(f, "{}", db.struct_signature(s).name.display(f.db, f.edition()))?
+ write!(f, "{}", StructSignature::of(db, s).name.display(f.db, f.edition()))?
}
CallableDefId::EnumVariantId(e) => {
let loc = e.lookup(db);
@@ -1295,9 +1246,11 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
match f.display_kind {
DisplayKind::Diagnostics | DisplayKind::Test => {
let name = match def_id {
- hir_def::AdtId::StructId(it) => db.struct_signature(it).name.clone(),
- hir_def::AdtId::UnionId(it) => db.union_signature(it).name.clone(),
- hir_def::AdtId::EnumId(it) => db.enum_signature(it).name.clone(),
+ hir_def::AdtId::StructId(it) => {
+ StructSignature::of(db, it).name.clone()
+ }
+ hir_def::AdtId::UnionId(it) => UnionSignature::of(db, it).name.clone(),
+ hir_def::AdtId::EnumId(it) => EnumSignature::of(db, it).name.clone(),
};
write!(f, "{}", name.display(f.db, f.edition()))?;
}
@@ -1328,9 +1281,11 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
hir_fmt_generics(f, parameters.as_slice(), Some(def.def_id().0.into()), None)?;
}
- TyKind::Alias(AliasTyKind::Projection, alias_ty) => write_projection(f, &alias_ty)?,
+ TyKind::Alias(AliasTyKind::Projection, alias_ty) => {
+ write_projection(f, &alias_ty, trait_bounds_need_parens)?
+ }
TyKind::Foreign(alias) => {
- let type_alias = db.type_alias_signature(alias.0);
+ let type_alias = TypeAliasSignature::of(db, alias.0);
f.start_location_link(alias.0.into());
write!(f, "{}", type_alias.name.display(f.db, f.edition()))?;
f.end_location_link();
@@ -1363,6 +1318,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
Either::Left(*self),
&bounds,
SizedByDefault::Sized { anchor: krate },
+ trait_bounds_need_parens,
)?;
}
TyKind::Closure(id, substs) => {
@@ -1393,8 +1349,8 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
}
let sig = interner.signature_unclosure(substs.as_closure().sig(), Safety::Safe);
let sig = sig.skip_binder();
- let InternedClosure(def, _) = db.lookup_intern_closure(id);
- let infer = InferenceResult::for_body(db, def);
+ let InternedClosure(owner, _) = db.lookup_intern_closure(id);
+ let infer = InferenceResult::of(db, owner);
let (_, kind) = infer.closure_info(id);
match f.closure_style {
ClosureStyle::ImplFn => write!(f, "impl {kind:?}(")?,
@@ -1525,6 +1481,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
Either::Left(*self),
&bounds,
SizedByDefault::Sized { anchor: krate },
+ trait_bounds_need_parens,
)?;
}
},
@@ -1567,6 +1524,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
Either::Left(*self),
&bounds_to_display,
SizedByDefault::NotSized,
+ trait_bounds_need_parens,
)?;
}
TyKind::Error(_) => {
@@ -1581,7 +1539,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
let InternedCoroutine(owner, expr_id) = coroutine_id.0.loc(db);
let CoroutineArgsParts { resume_ty, yield_ty, return_ty, .. } =
subst.split_coroutine_args();
- let body = db.body(owner);
+ let body = ExpressionStore::of(db, owner);
let expr = &body[expr_id];
match expr {
hir_def::hir::Expr::Closure {
@@ -1806,11 +1764,11 @@ pub enum SizedByDefault {
}
impl SizedByDefault {
- fn is_sized_trait(self, trait_: TraitId, db: &dyn DefDatabase) -> bool {
+ fn is_sized_trait(self, trait_: TraitId, interner: DbInterner<'_>) -> bool {
match self {
Self::NotSized => false,
- Self::Sized { anchor } => {
- let sized_trait = hir_def::lang_item::lang_items(db, anchor).Sized;
+ Self::Sized { .. } => {
+ let sized_trait = interner.lang_items().Sized;
Some(trait_) == sized_trait
}
}
@@ -1823,16 +1781,62 @@ pub fn write_bounds_like_dyn_trait_with_prefix<'db>(
this: Either<Ty<'db>, Region<'db>>,
predicates: &[Clause<'db>],
default_sized: SizedByDefault,
+ needs_parens_if_multi: bool,
) -> Result {
+ let needs_parens =
+ needs_parens_if_multi && trait_bounds_need_parens(f, this, predicates, default_sized);
+ if needs_parens {
+ write!(f, "(")?;
+ }
write!(f, "{prefix}")?;
if !predicates.is_empty()
|| predicates.is_empty() && matches!(default_sized, SizedByDefault::Sized { .. })
{
write!(f, " ")?;
- write_bounds_like_dyn_trait(f, this, predicates, default_sized)
- } else {
- Ok(())
+ write_bounds_like_dyn_trait(f, this, predicates, default_sized)?;
+ }
+ if needs_parens {
+ write!(f, ")")?;
+ }
+ Ok(())
+}
+
+fn trait_bounds_need_parens<'db>(
+ f: &mut HirFormatter<'_, 'db>,
+ this: Either<Ty<'db>, Region<'db>>,
+ predicates: &[Clause<'db>],
+ default_sized: SizedByDefault,
+) -> bool {
+ // This needs to be kept in sync with `write_bounds_like_dyn_trait()`.
+ let mut distinct_bounds = 0usize;
+ let mut is_sized = false;
+ for p in predicates {
+ match p.kind().skip_binder() {
+ ClauseKind::Trait(trait_ref) => {
+ let trait_ = trait_ref.def_id().0;
+ if default_sized.is_sized_trait(trait_, f.interner) {
+ is_sized = true;
+ if matches!(default_sized, SizedByDefault::Sized { .. }) {
+ // Don't print +Sized, but rather +?Sized if absent.
+ continue;
+ }
+ }
+
+ distinct_bounds += 1;
+ }
+ ClauseKind::TypeOutlives(to) if Either::Left(to.0) == this => distinct_bounds += 1,
+ ClauseKind::RegionOutlives(lo) if Either::Right(lo.0) == this => distinct_bounds += 1,
+ _ => {}
+ }
}
+
+ if let SizedByDefault::Sized { .. } = default_sized
+ && !is_sized
+ {
+ distinct_bounds += 1;
+ }
+
+ distinct_bounds > 1
}
fn write_bounds_like_dyn_trait<'db>(
@@ -1855,7 +1859,7 @@ fn write_bounds_like_dyn_trait<'db>(
match p.kind().skip_binder() {
ClauseKind::Trait(trait_ref) => {
let trait_ = trait_ref.def_id().0;
- if default_sized.is_sized_trait(trait_, f.db) {
+ if default_sized.is_sized_trait(trait_, f.interner) {
is_sized = true;
if matches!(default_sized, SizedByDefault::Sized { .. }) {
// Don't print +Sized, but rather +?Sized if absent.
@@ -1876,7 +1880,7 @@ fn write_bounds_like_dyn_trait<'db>(
// existential) here, which is the only thing that's
// possible in actual Rust, and hence don't print it
f.start_location_link(trait_.into());
- write!(f, "{}", f.db.trait_signature(trait_).name.display(f.db, f.edition()))?;
+ write!(f, "{}", TraitSignature::of(f.db, trait_).name.display(f.db, f.edition()))?;
f.end_location_link();
if is_fn_trait {
if let [_self, params @ ..] = trait_ref.trait_ref.args.as_slice()
@@ -1939,7 +1943,7 @@ fn write_bounds_like_dyn_trait<'db>(
angle_open = true;
}
let assoc_ty_id = projection.def_id().expect_type_alias();
- let type_alias = f.db.type_alias_signature(assoc_ty_id);
+ let type_alias = TypeAliasSignature::of(f.db, assoc_ty_id);
f.start_location_link(assoc_ty_id.into());
write!(f, "{}", type_alias.name.display(f.db, f.edition()))?;
f.end_location_link();
@@ -2030,7 +2034,7 @@ impl<'db> HirDisplay<'db> for TraitRef<'db> {
fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
let trait_ = self.def_id.0;
f.start_location_link(trait_.into());
- write!(f, "{}", f.db.trait_signature(trait_).name.display(f.db, f.edition()))?;
+ write!(f, "{}", TraitSignature::of(f.db, trait_).name.display(f.db, f.edition()))?;
f.end_location_link();
let substs = self.args.as_slice();
hir_fmt_generic_args(f, &substs[1..], None, Some(self.self_ty()))
@@ -2137,7 +2141,7 @@ impl<'db> HirDisplayWithExpressionStore<'db> for LifetimeRefId {
LifetimeRef::Placeholder => write!(f, "'_"),
LifetimeRef::Error => write!(f, "'{{error}}"),
&LifetimeRef::Param(lifetime_param_id) => {
- let generic_params = f.db.generic_params(lifetime_param_id.parent);
+ let generic_params = GenericParams::of(f.db, lifetime_param_id.parent);
write!(
f,
"{}",
@@ -2153,7 +2157,7 @@ impl<'db> HirDisplayWithExpressionStore<'db> for TypeRefId {
match &store[*self] {
TypeRef::Never => write!(f, "!")?,
TypeRef::TypeParam(param) => {
- let generic_params = f.db.generic_params(param.parent());
+ let generic_params = GenericParams::of(f.db, param.parent());
match generic_params[param.local_id()].name() {
Some(name) => write!(f, "{}", name.display(f.db, f.edition()))?,
None => {