1 //! FIXME: write short doc here
5 use chalk_ir::Mutability;
9 generics::TypeParamProvenance,
11 path::{Path, PathKind},
12 type_ref::{TypeBound, TypeRef},
13 visibility::Visibility,
14 AssocContainerId, Lookup, ModuleId, TraitId,
16 use hir_expand::name::Name;
19 db::HirDatabase, from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, primitive,
20 to_assoc_type_id, traits::chalk::from_chalk, utils::generics, AdtId, AliasEq, AliasTy,
21 CallableDefId, CallableSig, DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime, OpaqueTy,
22 ProjectionTy, QuantifiedWhereClause, Scalar, TraitRef, Ty, TyExt, TyKind, WhereClause,
25 pub struct HirFormatter<'a> {
26 pub db: &'a dyn HirDatabase,
27 fmt: &'a mut dyn fmt::Write,
30 pub(crate) max_size: Option<usize>,
31 omit_verbose_types: bool,
32 display_target: DisplayTarget,
35 pub trait HirDisplay {
36 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError>;
38 /// Returns a `Display`able type that is human-readable.
39 fn into_displayable<'a>(
41 db: &'a dyn HirDatabase,
42 max_size: Option<usize>,
43 omit_verbose_types: bool,
44 display_target: DisplayTarget,
45 ) -> HirDisplayWrapper<'a, Self>
49 HirDisplayWrapper { db, t: self, max_size, omit_verbose_types, display_target }
52 /// Returns a `Display`able type that is human-readable.
53 /// Use this for showing types to the user (e.g. diagnostics)
54 fn display<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self>
62 omit_verbose_types: false,
63 display_target: DisplayTarget::Diagnostics,
67 /// Returns a `Display`able type that is human-readable and tries to be succinct.
68 /// Use this for showing types to the user where space is constrained (e.g. doc popups)
69 fn display_truncated<'a>(
71 db: &'a dyn HirDatabase,
72 max_size: Option<usize>,
73 ) -> HirDisplayWrapper<'a, Self>
81 omit_verbose_types: true,
82 display_target: DisplayTarget::Diagnostics,
86 /// Returns a String representation of `self` that can be inserted into the given module.
87 /// Use this when generating code (e.g. assists)
88 fn display_source_code<'a>(
90 db: &'a dyn HirDatabase,
92 ) -> Result<String, DisplaySourceCodeError> {
93 let mut result = String::new();
94 match self.hir_fmt(&mut HirFormatter {
97 buf: String::with_capacity(20),
100 omit_verbose_types: false,
101 display_target: DisplayTarget::SourceCode { module_id },
104 Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"),
105 Err(HirDisplayError::DisplaySourceCodeError(e)) => return Err(e),
110 /// Returns a String representation of `self` for test purposes
111 fn display_test<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self>
119 omit_verbose_types: false,
120 display_target: DisplayTarget::Test,
125 impl<'a> HirFormatter<'a> {
126 pub fn write_joined<T: HirDisplay>(
128 iter: impl IntoIterator<Item = T>,
130 ) -> Result<(), HirDisplayError> {
131 let mut first = true;
134 write!(self, "{}", sep)?;
142 /// This allows using the `write!` macro directly with a `HirFormatter`.
143 pub fn write_fmt(&mut self, args: fmt::Arguments) -> Result<(), HirDisplayError> {
144 // We write to a buffer first to track output size
146 fmt::write(&mut self.buf, args)?;
147 self.curr_size += self.buf.len();
149 // Then we write to the internal formatter from the buffer
150 self.fmt.write_str(&self.buf).map_err(HirDisplayError::from)
153 pub fn should_truncate(&self) -> bool {
154 if let Some(max_size) = self.max_size {
155 self.curr_size >= max_size
161 pub fn omit_verbose_types(&self) -> bool {
162 self.omit_verbose_types
166 #[derive(Clone, Copy)]
167 pub enum DisplayTarget {
168 /// Display types for inlays, doc popups, autocompletion, etc...
169 /// Showing `{unknown}` or not qualifying paths is fine here.
170 /// There's no reason for this to fail.
172 /// Display types for inserting them in source files.
173 /// The generated code should compile, so paths need to be qualified.
174 SourceCode { module_id: ModuleId },
175 /// Only for test purpose to keep real types
180 fn is_source_code(&self) -> bool {
181 matches!(self, Self::SourceCode { .. })
183 fn is_test(&self) -> bool {
184 matches!(self, Self::Test)
189 pub enum DisplaySourceCodeError {
195 pub enum HirDisplayError {
196 /// Errors that can occur when generating source code
197 DisplaySourceCodeError(DisplaySourceCodeError),
198 /// `FmtError` is required to be compatible with std::fmt::Display
201 impl From<fmt::Error> for HirDisplayError {
202 fn from(_: fmt::Error) -> Self {
207 pub struct HirDisplayWrapper<'a, T> {
208 db: &'a dyn HirDatabase,
210 max_size: Option<usize>,
211 omit_verbose_types: bool,
212 display_target: DisplayTarget,
215 impl<'a, T> fmt::Display for HirDisplayWrapper<'a, T>
219 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
220 match self.t.hir_fmt(&mut HirFormatter {
223 buf: String::with_capacity(20),
225 max_size: self.max_size,
226 omit_verbose_types: self.omit_verbose_types,
227 display_target: self.display_target,
230 Err(HirDisplayError::FmtError) => Err(fmt::Error),
231 Err(HirDisplayError::DisplaySourceCodeError(_)) => {
232 // This should never happen
233 panic!("HirDisplay failed when calling Display::fmt!")
239 const TYPE_HINT_TRUNCATION: &str = "…";
241 impl<T: HirDisplay> HirDisplay for &'_ T {
242 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
243 HirDisplay::hir_fmt(*self, f)
247 impl HirDisplay for ProjectionTy {
248 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
249 if f.should_truncate() {
250 return write!(f, "{}", TYPE_HINT_TRUNCATION);
253 let trait_ = f.db.trait_data(self.trait_(f.db));
254 let first_parameter = self.self_type_parameter().into_displayable(
257 f.omit_verbose_types,
260 write!(f, "<{} as {}", first_parameter, trait_.name)?;
261 if self.substitution.len(&Interner) > 1 {
263 f.write_joined(&self.substitution.interned(&Interner)[1..], ", ")?;
266 write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
271 impl HirDisplay for OpaqueTy {
272 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
273 if f.should_truncate() {
274 return write!(f, "{}", TYPE_HINT_TRUNCATION);
277 self.substitution.at(&Interner, 0).hir_fmt(f)
281 impl HirDisplay for GenericArg {
282 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
283 match self.interned() {
284 crate::GenericArgData::Ty(ty) => ty.hir_fmt(f),
289 impl HirDisplay for Ty {
290 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
291 if f.should_truncate() {
292 return write!(f, "{}", TYPE_HINT_TRUNCATION);
295 match self.kind(&Interner) {
296 TyKind::Never => write!(f, "!")?,
297 TyKind::Str => write!(f, "str")?,
298 TyKind::Scalar(Scalar::Bool) => write!(f, "bool")?,
299 TyKind::Scalar(Scalar::Char) => write!(f, "char")?,
300 &TyKind::Scalar(Scalar::Float(t)) => write!(f, "{}", primitive::float_ty_to_string(t))?,
301 &TyKind::Scalar(Scalar::Int(t)) => write!(f, "{}", primitive::int_ty_to_string(t))?,
302 &TyKind::Scalar(Scalar::Uint(t)) => write!(f, "{}", primitive::uint_ty_to_string(t))?,
303 TyKind::Slice(t) => {
308 TyKind::Array(t) => {
313 TyKind::Raw(m, t) | TyKind::Ref(m, t) => {
315 t.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target);
317 if matches!(self.kind(&Interner), TyKind::Raw(..)) {
322 Mutability::Not => "const ",
323 Mutability::Mut => "mut ",
331 Mutability::Not => "",
332 Mutability::Mut => "mut ",
337 // FIXME: all this just to decide whether to use parentheses...
339 let predicates: Vec<_> = match t.kind(&Interner) {
340 TyKind::Dyn(dyn_ty) if dyn_ty.bounds.skip_binders().interned().len() > 1 => {
341 dyn_ty.bounds.skip_binders().interned().iter().cloned().collect()
343 &TyKind::Alias(AliasTy::Opaque(OpaqueTy {
345 substitution: ref parameters,
347 let impl_trait_id = f.db.lookup_intern_impl_trait_id(opaque_ty_id.into());
348 if let ImplTraitId::ReturnTypeImplTrait(func, idx) = impl_trait_id {
350 f.db.return_type_impl_traits(func)
351 .expect("impl trait id without data");
354 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
355 let bounds = data.subst(parameters);
364 if let Some(WhereClause::Implemented(trait_ref)) =
365 predicates.get(0).map(|b| b.skip_binders())
367 let trait_ = trait_ref.hir_trait_id();
368 if fn_traits(f.db.upcast(), trait_).any(|it| it == trait_)
369 && predicates.len() <= 2
371 return write!(f, "{}", ty_display);
375 if predicates.len() > 1 {
377 write!(f, "{}", ty_display)?;
380 write!(f, "{}", ty_display)?;
383 TyKind::Tuple(_, substs) => {
384 if substs.len(&Interner) == 1 {
386 substs.at(&Interner, 0).hir_fmt(f)?;
390 f.write_joined(&*substs.0, ", ")?;
394 TyKind::Function(fn_ptr) => {
395 let sig = CallableSig::from_fn_ptr(fn_ptr);
398 TyKind::FnDef(def, parameters) => {
399 let def = from_chalk(f.db, *def);
400 let sig = f.db.callable_item_signature(def).subst(parameters);
402 CallableDefId::FunctionId(ff) => {
403 write!(f, "fn {}", f.db.function_data(ff).name)?
405 CallableDefId::StructId(s) => write!(f, "{}", f.db.struct_data(s).name)?,
406 CallableDefId::EnumVariantId(e) => {
407 write!(f, "{}", f.db.enum_data(e.parent).variants[e.local_id].name)?
410 if parameters.len(&Interner) > 0 {
411 let generics = generics(f.db.upcast(), def.into());
412 let (parent_params, self_param, type_params, _impl_trait_params) =
413 generics.provenance_split();
414 let total_len = parent_params + self_param + type_params;
415 // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
418 f.write_joined(¶meters.0[..total_len], ", ")?;
423 f.write_joined(sig.params(), ", ")?;
427 let ret_display = ret.into_displayable(
430 f.omit_verbose_types,
434 write!(f, " -> {}", ret_display)?;
437 TyKind::Adt(AdtId(def_id), parameters) => {
438 match f.display_target {
439 DisplayTarget::Diagnostics | DisplayTarget::Test => {
440 let name = match *def_id {
441 hir_def::AdtId::StructId(it) => f.db.struct_data(it).name.clone(),
442 hir_def::AdtId::UnionId(it) => f.db.union_data(it).name.clone(),
443 hir_def::AdtId::EnumId(it) => f.db.enum_data(it).name.clone(),
445 write!(f, "{}", name)?;
447 DisplayTarget::SourceCode { module_id } => {
448 if let Some(path) = find_path::find_path(
450 ItemInNs::Types((*def_id).into()),
453 write!(f, "{}", path)?;
455 return Err(HirDisplayError::DisplaySourceCodeError(
456 DisplaySourceCodeError::PathNotFound,
462 if parameters.len(&Interner) > 0 {
463 let parameters_to_write = if f.display_target.is_source_code()
464 || f.omit_verbose_types()
467 .as_generic_def(f.db)
468 .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
469 .filter(|defaults| !defaults.is_empty())
471 None => parameters.0.as_ref(),
472 Some(default_parameters) => {
473 let mut default_from = 0;
474 for (i, parameter) in parameters.iter(&Interner).enumerate() {
476 parameter.assert_ty_ref(&Interner).kind(&Interner),
477 default_parameters.get(i),
479 (&TyKind::Unknown, _) | (_, None) => {
480 default_from = i + 1;
482 (_, Some(default_parameter)) => {
483 let actual_default = default_parameter
485 .subst(¶meters.prefix(i));
486 if parameter.assert_ty_ref(&Interner) != &actual_default
488 default_from = i + 1;
493 ¶meters.0[0..default_from]
497 parameters.0.as_ref()
499 if !parameters_to_write.is_empty() {
501 f.write_joined(parameters_to_write, ", ")?;
506 TyKind::AssociatedType(assoc_type_id, parameters) => {
507 let type_alias = from_assoc_type_id(*assoc_type_id);
508 let trait_ = match type_alias.lookup(f.db.upcast()).container {
509 AssocContainerId::TraitId(it) => it,
510 _ => panic!("not an associated type"),
512 let trait_ = f.db.trait_data(trait_);
513 let type_alias_data = f.db.type_alias_data(type_alias);
515 // Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
516 if f.display_target.is_test() {
517 write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
518 if parameters.len(&Interner) > 0 {
520 f.write_joined(&*parameters.0, ", ")?;
524 let projection_ty = ProjectionTy {
525 associated_ty_id: to_assoc_type_id(type_alias),
526 substitution: parameters.clone(),
529 projection_ty.hir_fmt(f)?;
532 TyKind::ForeignType(type_alias) => {
533 let type_alias = f.db.type_alias_data(from_foreign_def_id(*type_alias));
534 write!(f, "{}", type_alias.name)?;
536 TyKind::OpaqueType(opaque_ty_id, parameters) => {
537 let impl_trait_id = f.db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
538 match impl_trait_id {
539 ImplTraitId::ReturnTypeImplTrait(func, idx) => {
541 f.db.return_type_impl_traits(func).expect("impl trait id without data");
544 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
545 let bounds = data.subst(¶meters);
546 write_bounds_like_dyn_trait_with_prefix("impl", &bounds.value, f)?;
547 // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
549 ImplTraitId::AsyncBlockTypeImplTrait(..) => {
550 write!(f, "impl Future<Output = ")?;
551 parameters.at(&Interner, 0).hir_fmt(f)?;
556 TyKind::Closure(.., substs) => {
557 if f.display_target.is_source_code() {
558 return Err(HirDisplayError::DisplaySourceCodeError(
559 DisplaySourceCodeError::Closure,
562 let sig = substs.at(&Interner, 0).assert_ty_ref(&Interner).callable_sig(f.db);
563 if let Some(sig) = sig {
564 if sig.params().is_empty() {
566 } else if f.omit_verbose_types() {
567 write!(f, "|{}|", TYPE_HINT_TRUNCATION)?;
570 f.write_joined(sig.params(), ", ")?;
574 let ret_display = sig.ret().into_displayable(
577 f.omit_verbose_types,
580 write!(f, " -> {}", ret_display)?;
582 write!(f, "{{closure}}")?;
585 TyKind::Placeholder(idx) => {
586 let id = from_placeholder_idx(f.db, *idx);
587 let generics = generics(f.db.upcast(), id.parent);
588 let param_data = &generics.params.types[id.local_id];
589 match param_data.provenance {
590 TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
591 write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))?
593 TypeParamProvenance::ArgumentImplTrait => {
594 let substs = generics.type_params_subst(f.db);
597 .generic_predicates(id.parent)
599 .map(|pred| pred.clone().subst(&substs))
600 .filter(|wc| match &wc.skip_binders() {
601 WhereClause::Implemented(tr) => tr.self_type_parameter() == self,
602 WhereClause::AliasEq(AliasEq {
603 alias: AliasTy::Projection(proj),
605 }) => proj.self_type_parameter() == self,
608 .collect::<Vec<_>>();
609 write_bounds_like_dyn_trait_with_prefix("impl", &bounds, f)?;
613 TyKind::BoundVar(idx) => write!(f, "?{}.{}", idx.debruijn.depth(), idx.index)?,
614 TyKind::Dyn(dyn_ty) => {
615 write_bounds_like_dyn_trait_with_prefix(
617 dyn_ty.bounds.skip_binders().interned(),
621 TyKind::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?,
622 TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
623 let impl_trait_id = f.db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into());
624 match impl_trait_id {
625 ImplTraitId::ReturnTypeImplTrait(func, idx) => {
627 f.db.return_type_impl_traits(func).expect("impl trait id without data");
630 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
631 let bounds = data.subst(&opaque_ty.substitution);
632 write_bounds_like_dyn_trait_with_prefix("impl", &bounds.value, f)?;
634 ImplTraitId::AsyncBlockTypeImplTrait(..) => {
635 write!(f, "{{async block}}")?;
640 if f.display_target.is_source_code() {
641 return Err(HirDisplayError::DisplaySourceCodeError(
642 DisplaySourceCodeError::UnknownType,
645 write!(f, "{{unknown}}")?;
647 TyKind::InferenceVar(..) => write!(f, "_")?,
653 impl HirDisplay for CallableSig {
654 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
656 f.write_joined(self.params(), ", ")?;
658 if self.params().is_empty() {
665 let ret = self.ret();
668 ret.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target);
669 write!(f, " -> {}", ret_display)?;
675 fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> {
676 let krate = trait_.lookup(db).container.krate();
678 db.lang_item(krate, "fn".into()),
679 db.lang_item(krate, "fn_mut".into()),
680 db.lang_item(krate, "fn_once".into()),
682 array::IntoIter::new(fn_traits).into_iter().flatten().flat_map(|it| it.as_trait())
685 pub fn write_bounds_like_dyn_trait_with_prefix(
687 predicates: &[QuantifiedWhereClause],
688 f: &mut HirFormatter,
689 ) -> Result<(), HirDisplayError> {
690 write!(f, "{}", prefix)?;
691 if !predicates.is_empty() {
693 write_bounds_like_dyn_trait(predicates, f)
699 fn write_bounds_like_dyn_trait(
700 predicates: &[QuantifiedWhereClause],
701 f: &mut HirFormatter,
702 ) -> Result<(), HirDisplayError> {
703 // Note: This code is written to produce nice results (i.e.
704 // corresponding to surface Rust) for types that can occur in
705 // actual Rust. It will have weird results if the predicates
706 // aren't as expected (i.e. self types = $0, projection
707 // predicates for a certain trait come after the Implemented
708 // predicate for that trait).
709 let mut first = true;
710 let mut angle_open = false;
711 let mut is_fn_trait = false;
712 for p in predicates.iter() {
713 match p.skip_binders() {
714 WhereClause::Implemented(trait_ref) => {
715 let trait_ = trait_ref.hir_trait_id();
717 is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == trait_);
719 if !is_fn_trait && angle_open {
726 // We assume that the self type is $0 (i.e. the
727 // existential) here, which is the only thing that's
728 // possible in actual Rust, and hence don't print it
729 write!(f, "{}", f.db.trait_data(trait_).name)?;
730 if let [_, params @ ..] = &*trait_ref.substitution.0 {
733 params.first().and_then(|it| it.assert_ty_ref(&Interner).as_tuple())
736 f.write_joined(&*args.0, ", ")?;
739 } else if !params.is_empty() {
741 f.write_joined(params, ", ")?;
742 // there might be assoc type bindings, so we leave the angle brackets open
747 WhereClause::AliasEq(alias_eq) if is_fn_trait => {
750 alias_eq.ty.hir_fmt(f)?;
752 WhereClause::AliasEq(AliasEq { ty, alias }) => {
753 // in types in actual Rust, these will always come
754 // after the corresponding Implemented predicate
761 if let AliasTy::Projection(proj) = alias {
763 f.db.type_alias_data(from_assoc_type_id(proj.associated_ty_id));
764 write!(f, "{} = ", type_alias.name)?;
778 fn hir_fmt_ext(&self, f: &mut HirFormatter, use_as: bool) -> Result<(), HirDisplayError> {
779 if f.should_truncate() {
780 return write!(f, "{}", TYPE_HINT_TRUNCATION);
783 self.self_type_parameter().hir_fmt(f)?;
789 write!(f, "{}", f.db.trait_data(self.hir_trait_id()).name)?;
790 if self.substitution.len(&Interner) > 1 {
792 f.write_joined(&self.substitution.interned(&Interner)[1..], ", ")?;
799 impl HirDisplay for TraitRef {
800 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
801 self.hir_fmt_ext(f, false)
805 impl HirDisplay for WhereClause {
806 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
807 if f.should_truncate() {
808 return write!(f, "{}", TYPE_HINT_TRUNCATION);
812 WhereClause::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
813 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
815 projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?;
819 f.db.type_alias_data(from_assoc_type_id(projection_ty.associated_ty_id)).name,
823 WhereClause::AliasEq(_) => write!(f, "{{error}}")?,
829 impl HirDisplay for Lifetime {
830 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
832 Lifetime::Parameter(id) => {
833 let generics = generics(f.db.upcast(), id.parent);
834 let param_data = &generics.params.lifetimes[id.local_id];
835 write!(f, "{}", ¶m_data.name)
837 Lifetime::Static => write!(f, "'static"),
842 impl HirDisplay for DomainGoal {
843 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
845 DomainGoal::Holds(wc) => {
846 write!(f, "Holds(")?;
854 pub fn write_visibility(
857 f: &mut HirFormatter,
858 ) -> Result<(), HirDisplayError> {
860 Visibility::Public => write!(f, "pub "),
861 Visibility::Module(vis_id) => {
862 let def_map = module_id.def_map(f.db.upcast());
863 let root_module_id = def_map.module_id(def_map.root());
864 if vis_id == module_id {
865 // pub(self) or omitted
867 } else if root_module_id == vis_id {
868 write!(f, "pub(crate) ")
869 } else if module_id.containing_module(f.db.upcast()) == Some(vis_id) {
870 write!(f, "pub(super) ")
872 write!(f, "pub(in ...) ")
878 impl HirDisplay for TypeRef {
879 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
881 TypeRef::Never => write!(f, "!")?,
882 TypeRef::Placeholder => write!(f, "_")?,
883 TypeRef::Tuple(elems) => {
885 f.write_joined(elems, ", ")?;
886 if elems.len() == 1 {
891 TypeRef::Path(path) => path.hir_fmt(f)?,
892 TypeRef::RawPtr(inner, mutability) => {
893 let mutability = match mutability {
894 hir_def::type_ref::Mutability::Shared => "*const ",
895 hir_def::type_ref::Mutability::Mut => "*mut ",
897 write!(f, "{}", mutability)?;
900 TypeRef::Reference(inner, lifetime, mutability) => {
901 let mutability = match mutability {
902 hir_def::type_ref::Mutability::Shared => "",
903 hir_def::type_ref::Mutability::Mut => "mut ",
906 if let Some(lifetime) = lifetime {
907 write!(f, "{} ", lifetime.name)?;
909 write!(f, "{}", mutability)?;
912 TypeRef::Array(inner) => {
915 // FIXME: Array length?
918 TypeRef::Slice(inner) => {
923 TypeRef::Fn(tys, is_varargs) => {
924 // FIXME: Function pointer qualifiers.
926 f.write_joined(&tys[..tys.len() - 1], ", ")?;
928 write!(f, "{}...", if tys.len() == 1 { "" } else { ", " })?;
931 let ret_ty = tys.last().unwrap();
933 TypeRef::Tuple(tup) if tup.is_empty() => {}
940 TypeRef::ImplTrait(bounds) => {
942 f.write_joined(bounds, " + ")?;
944 TypeRef::DynTrait(bounds) => {
946 f.write_joined(bounds, " + ")?;
948 TypeRef::Error => write!(f, "{{error}}")?,
954 impl HirDisplay for TypeBound {
955 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
957 TypeBound::Path(path) => path.hir_fmt(f),
958 TypeBound::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
959 TypeBound::Error => write!(f, "{{error}}"),
964 impl HirDisplay for Path {
965 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
966 match (self.type_anchor(), self.kind()) {
967 (Some(anchor), _) => {
972 (_, PathKind::Plain) => {}
973 (_, PathKind::Abs) => write!(f, "::")?,
974 (_, PathKind::Crate) => write!(f, "crate")?,
975 (_, PathKind::Super(0)) => write!(f, "self")?,
976 (_, PathKind::Super(n)) => {
979 write!(f, "::super")?;
982 (_, PathKind::DollarCrate(_)) => write!(f, "{{extern_crate}}")?,
985 for (seg_idx, segment) in self.segments().iter().enumerate() {
989 write!(f, "{}", segment.name)?;
990 if let Some(generic_args) = segment.args_and_bindings {
991 // We should be in type context, so format as `Foo<Bar>` instead of `Foo::<Bar>`.
992 // Do we actually format expressions?
994 let mut first = true;
995 for arg in &generic_args.args {
998 if generic_args.has_self_type {
999 // FIXME: Convert to `<Ty as Trait>` form.
1000 write!(f, "Self = ")?;
1007 for binding in &generic_args.bindings {
1013 write!(f, "{}", binding.name)?;
1014 match &binding.type_ref {
1021 f.write_joined(&binding.bounds, " + ")?;
1032 impl HirDisplay for hir_def::path::GenericArg {
1033 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
1035 hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f),
1036 hir_def::path::GenericArg::Lifetime(lifetime) => write!(f, "{}", lifetime.name),