//! FIXME: write short doc here
-use std::{borrow::Cow, fmt};
+use std::{array, fmt};
-use arrayvec::ArrayVec;
use chalk_ir::Mutability;
use hir_def::{
- db::DefDatabase, find_path, generics::TypeParamProvenance, item_scope::ItemInNs,
+ db::DefDatabase,
+ find_path,
+ generics::TypeParamProvenance,
+ item_scope::ItemInNs,
+ path::{Path, PathKind},
+ type_ref::{TypeBound, TypeRef},
+ visibility::Visibility,
AssocContainerId, Lookup, ModuleId, TraitId,
};
use hir_expand::name::Name;
use crate::{
db::HirDatabase, from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, primitive,
- to_assoc_type_id, traits::chalk::from_chalk, utils::generics, AdtId, AliasTy, CallableDefId,
- CallableSig, GenericPredicate, ImplTraitId, Interner, Lifetime, Obligation, OpaqueTy,
- ProjectionTy, Scalar, Substs, TraitRef, Ty, TyKind,
+ to_assoc_type_id, traits::chalk::from_chalk, utils::generics, AdtId, AliasEq, AliasTy,
+ CallableDefId, CallableSig, DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime, OpaqueTy,
+ ProjectionTy, QuantifiedWhereClause, Scalar, TraitRef, Ty, TyExt, TyKind, WhereClause,
};
pub struct HirFormatter<'a> {
pub enum DisplaySourceCodeError {
PathNotFound,
UnknownType,
+ Closure,
}
pub enum HirDisplayError {
const TYPE_HINT_TRUNCATION: &str = "…";
-impl HirDisplay for &Ty {
+impl<T: HirDisplay> HirDisplay for &'_ T {
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
HirDisplay::hir_fmt(*self, f)
}
}
let trait_ = f.db.trait_data(self.trait_(f.db));
- let first_parameter = self.substitution[0].into_displayable(
+ let first_parameter = self.self_type_parameter().into_displayable(
f.db,
f.max_size,
f.omit_verbose_types,
f.display_target,
);
write!(f, "<{} as {}", first_parameter, trait_.name)?;
- if self.substitution.len() > 1 {
+ if self.substitution.len(&Interner) > 1 {
write!(f, "<")?;
- f.write_joined(&self.substitution[1..], ", ")?;
+ f.write_joined(&self.substitution.interned()[1..], ", ")?;
write!(f, ">")?;
}
write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
}
}
+impl HirDisplay for OpaqueTy {
+ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
+ if f.should_truncate() {
+ return write!(f, "{}", TYPE_HINT_TRUNCATION);
+ }
+
+ self.substitution.at(&Interner, 0).hir_fmt(f)
+ }
+}
+
+impl HirDisplay for GenericArg {
+ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
+ match self.interned() {
+ crate::GenericArgData::Ty(ty) => ty.hir_fmt(f),
+ }
+ }
+}
+
impl HirDisplay for Ty {
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
if f.should_truncate() {
return write!(f, "{}", TYPE_HINT_TRUNCATION);
}
- match self.interned(&Interner) {
+ match self.kind(&Interner) {
TyKind::Never => write!(f, "!")?,
TyKind::Str => write!(f, "str")?,
TyKind::Scalar(Scalar::Bool) => write!(f, "bool")?,
&TyKind::Scalar(Scalar::Float(t)) => write!(f, "{}", primitive::float_ty_to_string(t))?,
&TyKind::Scalar(Scalar::Int(t)) => write!(f, "{}", primitive::int_ty_to_string(t))?,
&TyKind::Scalar(Scalar::Uint(t)) => write!(f, "{}", primitive::uint_ty_to_string(t))?,
- TyKind::Slice(parameters) => {
- let t = parameters.as_single();
+ TyKind::Slice(t) => {
write!(f, "[")?;
t.hir_fmt(f)?;
write!(f, "]")?;
}
- TyKind::Array(parameters) => {
- let t = parameters.as_single();
+ TyKind::Array(t) => {
write!(f, "[")?;
t.hir_fmt(f)?;
write!(f, "; _]")?;
}
- TyKind::Raw(m, parameters) | TyKind::Ref(m, parameters) => {
- let t = parameters.as_single();
+ TyKind::Raw(m, t) | TyKind::Ref(m, t) => {
let ty_display =
t.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target);
- if matches!(self.interned(&Interner), TyKind::Raw(..)) {
+ if matches!(self.kind(&Interner), TyKind::Raw(..)) {
write!(
f,
"*{}",
// FIXME: all this just to decide whether to use parentheses...
let datas;
- let predicates = match t.interned(&Interner) {
- TyKind::Dyn(predicates) if predicates.len() > 1 => {
- Cow::Borrowed(predicates.as_ref())
+ let predicates: Vec<_> = match t.kind(&Interner) {
+ TyKind::Dyn(dyn_ty) if dyn_ty.bounds.skip_binders().interned().len() > 1 => {
+ dyn_ty.bounds.skip_binders().interned().iter().cloned().collect()
}
&TyKind::Alias(AliasTy::Opaque(OpaqueTy {
opaque_ty_id,
.as_ref()
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
let bounds = data.subst(parameters);
- Cow::Owned(bounds.value)
+ bounds.value
} else {
- Cow::Borrowed(&[][..])
+ Vec::new()
}
}
- _ => Cow::Borrowed(&[][..]),
+ _ => Vec::new(),
};
- if let [GenericPredicate::Implemented(trait_ref), _] = predicates.as_ref() {
- let trait_ = trait_ref.trait_;
- if fn_traits(f.db.upcast(), trait_).any(|it| it == trait_) {
+ if let Some(WhereClause::Implemented(trait_ref)) =
+ predicates.get(0).map(|b| b.skip_binders())
+ {
+ let trait_ = trait_ref.hir_trait_id();
+ if fn_traits(f.db.upcast(), trait_).any(|it| it == trait_)
+ && predicates.len() <= 2
+ {
return write!(f, "{}", ty_display);
}
}
}
}
TyKind::Tuple(_, substs) => {
- if substs.len() == 1 {
+ if substs.len(&Interner) == 1 {
write!(f, "(")?;
- substs[0].hir_fmt(f)?;
+ substs.at(&Interner, 0).hir_fmt(f)?;
write!(f, ",)")?;
} else {
write!(f, "(")?;
- f.write_joined(&*substs.0, ", ")?;
+ f.write_joined(&*substs.interned(), ", ")?;
write!(f, ")")?;
}
}
write!(f, "{}", f.db.enum_data(e.parent).variants[e.local_id].name)?
}
};
- if parameters.len() > 0 {
+ if parameters.len(&Interner) > 0 {
let generics = generics(f.db.upcast(), def.into());
let (parent_params, self_param, type_params, _impl_trait_params) =
generics.provenance_split();
// We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
if total_len > 0 {
write!(f, "<")?;
- f.write_joined(¶meters.0[..total_len], ", ")?;
+ f.write_joined(¶meters.interned()[..total_len], ", ")?;
write!(f, ">")?;
}
}
f.write_joined(sig.params(), ", ")?;
write!(f, ")")?;
let ret = sig.ret();
- if *ret != Ty::unit() {
+ if !ret.is_unit() {
let ret_display = ret.into_displayable(
f.db,
f.max_size,
}
}
- if parameters.len() > 0 {
+ if parameters.len(&Interner) > 0 {
let parameters_to_write = if f.display_target.is_source_code()
|| f.omit_verbose_types()
{
.map(|generic_def_id| f.db.generic_defaults(generic_def_id))
.filter(|defaults| !defaults.is_empty())
{
- None => parameters.0.as_ref(),
+ None => parameters.interned().as_ref(),
Some(default_parameters) => {
let mut default_from = 0;
- for (i, parameter) in parameters.iter().enumerate() {
- match (parameter.interned(&Interner), default_parameters.get(i))
- {
- (&TyKind::Unknown, _) | (_, None) => {
+ for (i, parameter) in parameters.iter(&Interner).enumerate() {
+ match (
+ parameter.assert_ty_ref(&Interner).kind(&Interner),
+ default_parameters.get(i),
+ ) {
+ (&TyKind::Error, _) | (_, None) => {
default_from = i + 1;
}
(_, Some(default_parameter)) => {
let actual_default = default_parameter
.clone()
.subst(¶meters.prefix(i));
- if parameter != &actual_default {
+ if parameter.assert_ty_ref(&Interner) != &actual_default
+ {
default_from = i + 1;
}
}
}
}
- ¶meters.0[0..default_from]
+ ¶meters.interned()[0..default_from]
}
}
} else {
- parameters.0.as_ref()
+ parameters.interned().as_ref()
};
if !parameters_to_write.is_empty() {
write!(f, "<")?;
// Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
if f.display_target.is_test() {
write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
- if parameters.len() > 0 {
+ if parameters.len(&Interner) > 0 {
write!(f, "<")?;
- f.write_joined(&*parameters.0, ", ")?;
+ f.write_joined(&*parameters.interned(), ", ")?;
write!(f, ">")?;
}
} else {
projection_ty.hir_fmt(f)?;
}
}
- TyKind::ForeignType(type_alias) => {
+ TyKind::Foreign(type_alias) => {
let type_alias = f.db.type_alias_data(from_foreign_def_id(*type_alias));
write!(f, "{}", type_alias.name)?;
}
}
ImplTraitId::AsyncBlockTypeImplTrait(..) => {
write!(f, "impl Future<Output = ")?;
- parameters[0].hir_fmt(f)?;
+ parameters.at(&Interner, 0).hir_fmt(f)?;
write!(f, ">")?;
}
}
}
TyKind::Closure(.., substs) => {
- let sig = substs[0].callable_sig(f.db);
+ if f.display_target.is_source_code() {
+ return Err(HirDisplayError::DisplaySourceCodeError(
+ DisplaySourceCodeError::Closure,
+ ));
+ }
+ let sig = substs.at(&Interner, 0).assert_ty_ref(&Interner).callable_sig(f.db);
if let Some(sig) = sig {
if sig.params().is_empty() {
write!(f, "||")?;
write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))?
}
TypeParamProvenance::ArgumentImplTrait => {
- let bounds = f.db.generic_predicates_for_param(id);
- let substs = Substs::type_params_for_generics(f.db, &generics);
- write_bounds_like_dyn_trait_with_prefix(
- "impl",
- &bounds.iter().map(|b| b.clone().subst(&substs)).collect::<Vec<_>>(),
- f,
- )?;
+ let substs = generics.type_params_subst(f.db);
+ let bounds = f
+ .db
+ .generic_predicates(id.parent)
+ .into_iter()
+ .map(|pred| pred.clone().subst(&substs))
+ .filter(|wc| match &wc.skip_binders() {
+ WhereClause::Implemented(tr) => tr.self_type_parameter() == self,
+ WhereClause::AliasEq(AliasEq {
+ alias: AliasTy::Projection(proj),
+ ty: _,
+ }) => proj.self_type_parameter() == self,
+ _ => false,
+ })
+ .collect::<Vec<_>>();
+ write_bounds_like_dyn_trait_with_prefix("impl", &bounds, f)?;
}
}
}
TyKind::BoundVar(idx) => write!(f, "?{}.{}", idx.debruijn.depth(), idx.index)?,
- TyKind::Dyn(predicates) => {
- write_bounds_like_dyn_trait_with_prefix("dyn", predicates, f)?;
+ TyKind::Dyn(dyn_ty) => {
+ write_bounds_like_dyn_trait_with_prefix(
+ "dyn",
+ dyn_ty.bounds.skip_binders().interned(),
+ f,
+ )?;
}
TyKind::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?,
TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
}
};
}
- TyKind::Unknown => {
+ TyKind::Error => {
if f.display_target.is_source_code() {
return Err(HirDisplayError::DisplaySourceCodeError(
DisplaySourceCodeError::UnknownType,
}
write!(f, ")")?;
let ret = self.ret();
- if *ret != Ty::unit() {
+ if !ret.is_unit() {
let ret_display =
ret.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target);
write!(f, " -> {}", ret_display)?;
db.lang_item(krate, "fn_mut".into()),
db.lang_item(krate, "fn_once".into()),
];
- // FIXME: Replace ArrayVec when into_iter is a thing on arrays
- ArrayVec::from(fn_traits).into_iter().flatten().flat_map(|it| it.as_trait())
+ array::IntoIter::new(fn_traits).into_iter().flatten().flat_map(|it| it.as_trait())
}
pub fn write_bounds_like_dyn_trait_with_prefix(
prefix: &str,
- predicates: &[GenericPredicate],
+ predicates: &[QuantifiedWhereClause],
f: &mut HirFormatter,
) -> Result<(), HirDisplayError> {
write!(f, "{}", prefix)?;
}
fn write_bounds_like_dyn_trait(
- predicates: &[GenericPredicate],
+ predicates: &[QuantifiedWhereClause],
f: &mut HirFormatter,
) -> Result<(), HirDisplayError> {
// Note: This code is written to produce nice results (i.e.
let mut angle_open = false;
let mut is_fn_trait = false;
for p in predicates.iter() {
- match p {
- GenericPredicate::Implemented(trait_ref) => {
- let trait_ = trait_ref.trait_;
+ match p.skip_binders() {
+ WhereClause::Implemented(trait_ref) => {
+ let trait_ = trait_ref.hir_trait_id();
if !is_fn_trait {
is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == trait_);
}
// existential) here, which is the only thing that's
// possible in actual Rust, and hence don't print it
write!(f, "{}", f.db.trait_data(trait_).name)?;
- if let [_, params @ ..] = &*trait_ref.substs.0 {
+ if let [_, params @ ..] = &*trait_ref.substitution.interned() {
if is_fn_trait {
- if let Some(args) = params.first().and_then(|it| it.as_tuple()) {
+ if let Some(args) =
+ params.first().and_then(|it| it.assert_ty_ref(&Interner).as_tuple())
+ {
write!(f, "(")?;
- f.write_joined(&*args.0, ", ")?;
+ f.write_joined(&*args.interned(), ", ")?;
write!(f, ")")?;
}
} else if !params.is_empty() {
}
}
}
- GenericPredicate::Projection(projection_pred) if is_fn_trait => {
+ WhereClause::AliasEq(alias_eq) if is_fn_trait => {
is_fn_trait = false;
write!(f, " -> ")?;
- projection_pred.ty.hir_fmt(f)?;
+ alias_eq.ty.hir_fmt(f)?;
}
- GenericPredicate::Projection(projection_pred) => {
+ WhereClause::AliasEq(AliasEq { ty, alias }) => {
// in types in actual Rust, these will always come
// after the corresponding Implemented predicate
if angle_open {
write!(f, "<")?;
angle_open = true;
}
- let type_alias = f.db.type_alias_data(from_assoc_type_id(
- projection_pred.projection_ty.associated_ty_id,
- ));
- write!(f, "{} = ", type_alias.name)?;
- projection_pred.ty.hir_fmt(f)?;
- }
- GenericPredicate::Error => {
- if angle_open {
- // impl Trait<X, {error}>
- write!(f, ", ")?;
- } else if !first {
- // impl Trait + {error}
- write!(f, " + ")?;
+ if let AliasTy::Projection(proj) = alias {
+ let type_alias =
+ f.db.type_alias_data(from_assoc_type_id(proj.associated_ty_id));
+ write!(f, "{} = ", type_alias.name)?;
}
- p.hir_fmt(f)?;
+ ty.hir_fmt(f)?;
}
}
first = false;
return write!(f, "{}", TYPE_HINT_TRUNCATION);
}
- self.substs[0].hir_fmt(f)?;
+ self.self_type_parameter().hir_fmt(f)?;
if use_as {
write!(f, " as ")?;
} else {
write!(f, ": ")?;
}
- write!(f, "{}", f.db.trait_data(self.trait_).name)?;
- if self.substs.len() > 1 {
+ write!(f, "{}", f.db.trait_data(self.hir_trait_id()).name)?;
+ if self.substitution.len(&Interner) > 1 {
write!(f, "<")?;
- f.write_joined(&self.substs[1..], ", ")?;
+ f.write_joined(&self.substitution.interned()[1..], ", ")?;
write!(f, ">")?;
}
Ok(())
}
}
-impl HirDisplay for &GenericPredicate {
- fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
- HirDisplay::hir_fmt(*self, f)
- }
-}
-
-impl HirDisplay for GenericPredicate {
+impl HirDisplay for WhereClause {
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
if f.should_truncate() {
return write!(f, "{}", TYPE_HINT_TRUNCATION);
}
match self {
- GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
- GenericPredicate::Projection(projection_pred) => {
+ WhereClause::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
+ WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
write!(f, "<")?;
- projection_pred.projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?;
+ projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?;
write!(
f,
">::{} = ",
- f.db.type_alias_data(from_assoc_type_id(
- projection_pred.projection_ty.associated_ty_id
- ))
- .name,
+ f.db.type_alias_data(from_assoc_type_id(projection_ty.associated_ty_id)).name,
)?;
- projection_pred.ty.hir_fmt(f)?;
+ ty.hir_fmt(f)?;
}
- GenericPredicate::Error => write!(f, "{{error}}")?,
+ WhereClause::AliasEq(_) => write!(f, "{{error}}")?,
}
Ok(())
}
}
}
-impl HirDisplay for Obligation {
+impl HirDisplay for DomainGoal {
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
match self {
- Obligation::Trait(tr) => {
- write!(f, "Implements(")?;
- tr.hir_fmt(f)?;
+ DomainGoal::Holds(wc) => {
+ write!(f, "Holds(")?;
+ wc.hir_fmt(f)?;
write!(f, ")")
}
- Obligation::Projection(proj) => {
- write!(f, "Normalize(")?;
- proj.projection_ty.hir_fmt(f)?;
- write!(f, " => ")?;
- proj.ty.hir_fmt(f)?;
- write!(f, ")")
+ }
+ }
+}
+
+pub fn write_visibility(
+ module_id: ModuleId,
+ vis: Visibility,
+ f: &mut HirFormatter,
+) -> Result<(), HirDisplayError> {
+ match vis {
+ Visibility::Public => write!(f, "pub "),
+ Visibility::Module(vis_id) => {
+ let def_map = module_id.def_map(f.db.upcast());
+ let root_module_id = def_map.module_id(def_map.root());
+ if vis_id == module_id {
+ // pub(self) or omitted
+ Ok(())
+ } else if root_module_id == vis_id {
+ write!(f, "pub(crate) ")
+ } else if module_id.containing_module(f.db.upcast()) == Some(vis_id) {
+ write!(f, "pub(super) ")
+ } else {
+ write!(f, "pub(in ...) ")
+ }
+ }
+ }
+}
+
+impl HirDisplay for TypeRef {
+ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
+ match self {
+ TypeRef::Never => write!(f, "!")?,
+ TypeRef::Placeholder => write!(f, "_")?,
+ TypeRef::Tuple(elems) => {
+ write!(f, "(")?;
+ f.write_joined(elems, ", ")?;
+ if elems.len() == 1 {
+ write!(f, ",")?;
+ }
+ write!(f, ")")?;
+ }
+ TypeRef::Path(path) => path.hir_fmt(f)?,
+ TypeRef::RawPtr(inner, mutability) => {
+ let mutability = match mutability {
+ hir_def::type_ref::Mutability::Shared => "*const ",
+ hir_def::type_ref::Mutability::Mut => "*mut ",
+ };
+ write!(f, "{}", mutability)?;
+ inner.hir_fmt(f)?;
+ }
+ TypeRef::Reference(inner, lifetime, mutability) => {
+ let mutability = match mutability {
+ hir_def::type_ref::Mutability::Shared => "",
+ hir_def::type_ref::Mutability::Mut => "mut ",
+ };
+ write!(f, "&")?;
+ if let Some(lifetime) = lifetime {
+ write!(f, "{} ", lifetime.name)?;
+ }
+ write!(f, "{}", mutability)?;
+ inner.hir_fmt(f)?;
+ }
+ TypeRef::Array(inner) => {
+ write!(f, "[")?;
+ inner.hir_fmt(f)?;
+ // FIXME: Array length?
+ write!(f, "; _]")?;
+ }
+ TypeRef::Slice(inner) => {
+ write!(f, "[")?;
+ inner.hir_fmt(f)?;
+ write!(f, "]")?;
+ }
+ TypeRef::Fn(tys, is_varargs) => {
+ // FIXME: Function pointer qualifiers.
+ write!(f, "fn(")?;
+ f.write_joined(&tys[..tys.len() - 1], ", ")?;
+ if *is_varargs {
+ write!(f, "{}...", if tys.len() == 1 { "" } else { ", " })?;
+ }
+ write!(f, ")")?;
+ let ret_ty = tys.last().unwrap();
+ match ret_ty {
+ TypeRef::Tuple(tup) if tup.is_empty() => {}
+ _ => {
+ write!(f, " -> ")?;
+ ret_ty.hir_fmt(f)?;
+ }
+ }
+ }
+ TypeRef::ImplTrait(bounds) => {
+ write!(f, "impl ")?;
+ f.write_joined(bounds, " + ")?;
+ }
+ TypeRef::DynTrait(bounds) => {
+ write!(f, "dyn ")?;
+ f.write_joined(bounds, " + ")?;
+ }
+ TypeRef::Error => write!(f, "{{error}}")?,
+ }
+ Ok(())
+ }
+}
+
+impl HirDisplay for TypeBound {
+ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
+ match self {
+ TypeBound::Path(path) => path.hir_fmt(f),
+ TypeBound::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
+ TypeBound::Error => write!(f, "{{error}}"),
+ }
+ }
+}
+
+impl HirDisplay for Path {
+ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
+ match (self.type_anchor(), self.kind()) {
+ (Some(anchor), _) => {
+ write!(f, "<")?;
+ anchor.hir_fmt(f)?;
+ write!(f, ">")?;
+ }
+ (_, PathKind::Plain) => {}
+ (_, PathKind::Abs) => write!(f, "::")?,
+ (_, PathKind::Crate) => write!(f, "crate")?,
+ (_, PathKind::Super(0)) => write!(f, "self")?,
+ (_, PathKind::Super(n)) => {
+ write!(f, "super")?;
+ for _ in 0..*n {
+ write!(f, "::super")?;
+ }
+ }
+ (_, PathKind::DollarCrate(_)) => write!(f, "{{extern_crate}}")?,
+ }
+
+ for (seg_idx, segment) in self.segments().iter().enumerate() {
+ if seg_idx != 0 {
+ write!(f, "::")?;
+ }
+ write!(f, "{}", segment.name)?;
+ if let Some(generic_args) = segment.args_and_bindings {
+ // We should be in type context, so format as `Foo<Bar>` instead of `Foo::<Bar>`.
+ // Do we actually format expressions?
+ write!(f, "<")?;
+ let mut first = true;
+ for arg in &generic_args.args {
+ if first {
+ first = false;
+ if generic_args.has_self_type {
+ // FIXME: Convert to `<Ty as Trait>` form.
+ write!(f, "Self = ")?;
+ }
+ } else {
+ write!(f, ", ")?;
+ }
+ arg.hir_fmt(f)?;
+ }
+ for binding in &generic_args.bindings {
+ if first {
+ first = false;
+ } else {
+ write!(f, ", ")?;
+ }
+ write!(f, "{}", binding.name)?;
+ match &binding.type_ref {
+ Some(ty) => {
+ write!(f, " = ")?;
+ ty.hir_fmt(f)?
+ }
+ None => {
+ write!(f, ": ")?;
+ f.write_joined(&binding.bounds, " + ")?;
+ }
+ }
+ }
+ write!(f, ">")?;
}
}
+ Ok(())
+ }
+}
+
+impl HirDisplay for hir_def::path::GenericArg {
+ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
+ match self {
+ hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f),
+ hir_def::path::GenericArg::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
+ }
}
}