]> git.lizzy.rs Git - rust.git/blob - crates/hir_ty/src/display.rs
Use chalk_ir::AssocTypeId
[rust.git] / crates / hir_ty / src / display.rs
1 //! FIXME: write short doc here
2
3 use std::{borrow::Cow, fmt};
4
5 use arrayvec::ArrayVec;
6 use chalk_ir::Mutability;
7 use hir_def::{
8     db::DefDatabase, find_path, generics::TypeParamProvenance, item_scope::ItemInNs,
9     AssocContainerId, Lookup, ModuleId, TraitId,
10 };
11 use hir_expand::name::Name;
12
13 use crate::{
14     db::HirDatabase, from_assoc_type_id, from_foreign_def_id, primitive, to_assoc_type_id,
15     utils::generics, AdtId, AliasTy, CallableDefId, CallableSig, GenericPredicate, Interner,
16     Lifetime, Obligation, OpaqueTy, OpaqueTyId, ProjectionTy, Scalar, Substs, TraitRef, Ty, TyKind,
17 };
18
19 pub struct HirFormatter<'a> {
20     pub db: &'a dyn HirDatabase,
21     fmt: &'a mut dyn fmt::Write,
22     buf: String,
23     curr_size: usize,
24     pub(crate) max_size: Option<usize>,
25     omit_verbose_types: bool,
26     display_target: DisplayTarget,
27 }
28
29 pub trait HirDisplay {
30     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError>;
31
32     /// Returns a `Display`able type that is human-readable.
33     fn into_displayable<'a>(
34         &'a self,
35         db: &'a dyn HirDatabase,
36         max_size: Option<usize>,
37         omit_verbose_types: bool,
38         display_target: DisplayTarget,
39     ) -> HirDisplayWrapper<'a, Self>
40     where
41         Self: Sized,
42     {
43         HirDisplayWrapper { db, t: self, max_size, omit_verbose_types, display_target }
44     }
45
46     /// Returns a `Display`able type that is human-readable.
47     /// Use this for showing types to the user (e.g. diagnostics)
48     fn display<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self>
49     where
50         Self: Sized,
51     {
52         HirDisplayWrapper {
53             db,
54             t: self,
55             max_size: None,
56             omit_verbose_types: false,
57             display_target: DisplayTarget::Diagnostics,
58         }
59     }
60
61     /// Returns a `Display`able type that is human-readable and tries to be succinct.
62     /// Use this for showing types to the user where space is constrained (e.g. doc popups)
63     fn display_truncated<'a>(
64         &'a self,
65         db: &'a dyn HirDatabase,
66         max_size: Option<usize>,
67     ) -> HirDisplayWrapper<'a, Self>
68     where
69         Self: Sized,
70     {
71         HirDisplayWrapper {
72             db,
73             t: self,
74             max_size,
75             omit_verbose_types: true,
76             display_target: DisplayTarget::Diagnostics,
77         }
78     }
79
80     /// Returns a String representation of `self` that can be inserted into the given module.
81     /// Use this when generating code (e.g. assists)
82     fn display_source_code<'a>(
83         &'a self,
84         db: &'a dyn HirDatabase,
85         module_id: ModuleId,
86     ) -> Result<String, DisplaySourceCodeError> {
87         let mut result = String::new();
88         match self.hir_fmt(&mut HirFormatter {
89             db,
90             fmt: &mut result,
91             buf: String::with_capacity(20),
92             curr_size: 0,
93             max_size: None,
94             omit_verbose_types: false,
95             display_target: DisplayTarget::SourceCode { module_id },
96         }) {
97             Ok(()) => {}
98             Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"),
99             Err(HirDisplayError::DisplaySourceCodeError(e)) => return Err(e),
100         };
101         Ok(result)
102     }
103
104     /// Returns a String representation of `self` for test purposes
105     fn display_test<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self>
106     where
107         Self: Sized,
108     {
109         HirDisplayWrapper {
110             db,
111             t: self,
112             max_size: None,
113             omit_verbose_types: false,
114             display_target: DisplayTarget::Test,
115         }
116     }
117 }
118
119 impl<'a> HirFormatter<'a> {
120     pub fn write_joined<T: HirDisplay>(
121         &mut self,
122         iter: impl IntoIterator<Item = T>,
123         sep: &str,
124     ) -> Result<(), HirDisplayError> {
125         let mut first = true;
126         for e in iter {
127             if !first {
128                 write!(self, "{}", sep)?;
129             }
130             first = false;
131             e.hir_fmt(self)?;
132         }
133         Ok(())
134     }
135
136     /// This allows using the `write!` macro directly with a `HirFormatter`.
137     pub fn write_fmt(&mut self, args: fmt::Arguments) -> Result<(), HirDisplayError> {
138         // We write to a buffer first to track output size
139         self.buf.clear();
140         fmt::write(&mut self.buf, args)?;
141         self.curr_size += self.buf.len();
142
143         // Then we write to the internal formatter from the buffer
144         self.fmt.write_str(&self.buf).map_err(HirDisplayError::from)
145     }
146
147     pub fn should_truncate(&self) -> bool {
148         if let Some(max_size) = self.max_size {
149             self.curr_size >= max_size
150         } else {
151             false
152         }
153     }
154
155     pub fn omit_verbose_types(&self) -> bool {
156         self.omit_verbose_types
157     }
158 }
159
160 #[derive(Clone, Copy)]
161 pub enum DisplayTarget {
162     /// Display types for inlays, doc popups, autocompletion, etc...
163     /// Showing `{unknown}` or not qualifying paths is fine here.
164     /// There's no reason for this to fail.
165     Diagnostics,
166     /// Display types for inserting them in source files.
167     /// The generated code should compile, so paths need to be qualified.
168     SourceCode { module_id: ModuleId },
169     /// Only for test purpose to keep real types
170     Test,
171 }
172
173 impl DisplayTarget {
174     fn is_source_code(&self) -> bool {
175         matches!(self, Self::SourceCode { .. })
176     }
177     fn is_test(&self) -> bool {
178         matches!(self, Self::Test)
179     }
180 }
181
182 #[derive(Debug)]
183 pub enum DisplaySourceCodeError {
184     PathNotFound,
185     UnknownType,
186 }
187
188 pub enum HirDisplayError {
189     /// Errors that can occur when generating source code
190     DisplaySourceCodeError(DisplaySourceCodeError),
191     /// `FmtError` is required to be compatible with std::fmt::Display
192     FmtError,
193 }
194 impl From<fmt::Error> for HirDisplayError {
195     fn from(_: fmt::Error) -> Self {
196         Self::FmtError
197     }
198 }
199
200 pub struct HirDisplayWrapper<'a, T> {
201     db: &'a dyn HirDatabase,
202     t: &'a T,
203     max_size: Option<usize>,
204     omit_verbose_types: bool,
205     display_target: DisplayTarget,
206 }
207
208 impl<'a, T> fmt::Display for HirDisplayWrapper<'a, T>
209 where
210     T: HirDisplay,
211 {
212     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
213         match self.t.hir_fmt(&mut HirFormatter {
214             db: self.db,
215             fmt: f,
216             buf: String::with_capacity(20),
217             curr_size: 0,
218             max_size: self.max_size,
219             omit_verbose_types: self.omit_verbose_types,
220             display_target: self.display_target,
221         }) {
222             Ok(()) => Ok(()),
223             Err(HirDisplayError::FmtError) => Err(fmt::Error),
224             Err(HirDisplayError::DisplaySourceCodeError(_)) => {
225                 // This should never happen
226                 panic!("HirDisplay failed when calling Display::fmt!")
227             }
228         }
229     }
230 }
231
232 const TYPE_HINT_TRUNCATION: &str = "…";
233
234 impl HirDisplay for &Ty {
235     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
236         HirDisplay::hir_fmt(*self, f)
237     }
238 }
239
240 impl HirDisplay for ProjectionTy {
241     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
242         if f.should_truncate() {
243             return write!(f, "{}", TYPE_HINT_TRUNCATION);
244         }
245
246         let trait_ = f.db.trait_data(self.trait_(f.db));
247         let first_parameter = self.parameters[0].into_displayable(
248             f.db,
249             f.max_size,
250             f.omit_verbose_types,
251             f.display_target,
252         );
253         write!(f, "<{} as {}", first_parameter, trait_.name)?;
254         if self.parameters.len() > 1 {
255             write!(f, "<")?;
256             f.write_joined(&self.parameters[1..], ", ")?;
257             write!(f, ">")?;
258         }
259         write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty)).name)?;
260         Ok(())
261     }
262 }
263
264 impl HirDisplay for Ty {
265     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
266         if f.should_truncate() {
267             return write!(f, "{}", TYPE_HINT_TRUNCATION);
268         }
269
270         match self.interned(&Interner) {
271             TyKind::Never => write!(f, "!")?,
272             TyKind::Str => write!(f, "str")?,
273             TyKind::Scalar(Scalar::Bool) => write!(f, "bool")?,
274             TyKind::Scalar(Scalar::Char) => write!(f, "char")?,
275             &TyKind::Scalar(Scalar::Float(t)) => write!(f, "{}", primitive::float_ty_to_string(t))?,
276             &TyKind::Scalar(Scalar::Int(t)) => write!(f, "{}", primitive::int_ty_to_string(t))?,
277             &TyKind::Scalar(Scalar::Uint(t)) => write!(f, "{}", primitive::uint_ty_to_string(t))?,
278             TyKind::Slice(parameters) => {
279                 let t = parameters.as_single();
280                 write!(f, "[")?;
281                 t.hir_fmt(f)?;
282                 write!(f, "]")?;
283             }
284             TyKind::Array(parameters) => {
285                 let t = parameters.as_single();
286                 write!(f, "[")?;
287                 t.hir_fmt(f)?;
288                 write!(f, "; _]")?;
289             }
290             TyKind::Raw(m, parameters) | TyKind::Ref(m, parameters) => {
291                 let t = parameters.as_single();
292                 let ty_display =
293                     t.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target);
294
295                 if matches!(self.interned(&Interner), TyKind::Raw(..)) {
296                     write!(
297                         f,
298                         "*{}",
299                         match m {
300                             Mutability::Not => "const ",
301                             Mutability::Mut => "mut ",
302                         }
303                     )?;
304                 } else {
305                     write!(
306                         f,
307                         "&{}",
308                         match m {
309                             Mutability::Not => "",
310                             Mutability::Mut => "mut ",
311                         }
312                     )?;
313                 }
314
315                 let datas;
316                 let predicates = match t.interned(&Interner) {
317                     TyKind::Dyn(predicates) if predicates.len() > 1 => {
318                         Cow::Borrowed(predicates.as_ref())
319                     }
320                     &TyKind::Alias(AliasTy::Opaque(OpaqueTy {
321                         opaque_ty_id: OpaqueTyId::ReturnTypeImplTrait(func, idx),
322                         ref parameters,
323                     })) => {
324                         datas =
325                             f.db.return_type_impl_traits(func).expect("impl trait id without data");
326                         let data = (*datas)
327                             .as_ref()
328                             .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
329                         let bounds = data.subst(parameters);
330                         Cow::Owned(bounds.value)
331                     }
332                     _ => Cow::Borrowed(&[][..]),
333                 };
334
335                 if let [GenericPredicate::Implemented(trait_ref), _] = predicates.as_ref() {
336                     let trait_ = trait_ref.trait_;
337                     if fn_traits(f.db.upcast(), trait_).any(|it| it == trait_) {
338                         return write!(f, "{}", ty_display);
339                     }
340                 }
341
342                 if predicates.len() > 1 {
343                     write!(f, "(")?;
344                     write!(f, "{}", ty_display)?;
345                     write!(f, ")")?;
346                 } else {
347                     write!(f, "{}", ty_display)?;
348                 }
349             }
350             TyKind::Tuple(_, substs) => {
351                 if substs.len() == 1 {
352                     write!(f, "(")?;
353                     substs[0].hir_fmt(f)?;
354                     write!(f, ",)")?;
355                 } else {
356                     write!(f, "(")?;
357                     f.write_joined(&*substs.0, ", ")?;
358                     write!(f, ")")?;
359                 }
360             }
361             TyKind::Function(fn_ptr) => {
362                 let sig = CallableSig::from_fn_ptr(fn_ptr);
363                 sig.hir_fmt(f)?;
364             }
365             TyKind::FnDef(def, parameters) => {
366                 let def = *def;
367                 let sig = f.db.callable_item_signature(def).subst(parameters);
368                 match def {
369                     CallableDefId::FunctionId(ff) => {
370                         write!(f, "fn {}", f.db.function_data(ff).name)?
371                     }
372                     CallableDefId::StructId(s) => write!(f, "{}", f.db.struct_data(s).name)?,
373                     CallableDefId::EnumVariantId(e) => {
374                         write!(f, "{}", f.db.enum_data(e.parent).variants[e.local_id].name)?
375                     }
376                 };
377                 if parameters.len() > 0 {
378                     let generics = generics(f.db.upcast(), def.into());
379                     let (parent_params, self_param, type_params, _impl_trait_params) =
380                         generics.provenance_split();
381                     let total_len = parent_params + self_param + type_params;
382                     // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
383                     if total_len > 0 {
384                         write!(f, "<")?;
385                         f.write_joined(&parameters.0[..total_len], ", ")?;
386                         write!(f, ">")?;
387                     }
388                 }
389                 write!(f, "(")?;
390                 f.write_joined(sig.params(), ", ")?;
391                 write!(f, ")")?;
392                 let ret = sig.ret();
393                 if *ret != Ty::unit() {
394                     let ret_display = ret.into_displayable(
395                         f.db,
396                         f.max_size,
397                         f.omit_verbose_types,
398                         f.display_target,
399                     );
400
401                     write!(f, " -> {}", ret_display)?;
402                 }
403             }
404             TyKind::Adt(AdtId(def_id), parameters) => {
405                 match f.display_target {
406                     DisplayTarget::Diagnostics | DisplayTarget::Test => {
407                         let name = match *def_id {
408                             hir_def::AdtId::StructId(it) => f.db.struct_data(it).name.clone(),
409                             hir_def::AdtId::UnionId(it) => f.db.union_data(it).name.clone(),
410                             hir_def::AdtId::EnumId(it) => f.db.enum_data(it).name.clone(),
411                         };
412                         write!(f, "{}", name)?;
413                     }
414                     DisplayTarget::SourceCode { module_id } => {
415                         if let Some(path) = find_path::find_path(
416                             f.db.upcast(),
417                             ItemInNs::Types((*def_id).into()),
418                             module_id,
419                         ) {
420                             write!(f, "{}", path)?;
421                         } else {
422                             return Err(HirDisplayError::DisplaySourceCodeError(
423                                 DisplaySourceCodeError::PathNotFound,
424                             ));
425                         }
426                     }
427                 }
428
429                 if parameters.len() > 0 {
430                     let parameters_to_write = if f.display_target.is_source_code()
431                         || f.omit_verbose_types()
432                     {
433                         match self
434                             .as_generic_def()
435                             .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
436                             .filter(|defaults| !defaults.is_empty())
437                         {
438                             None => parameters.0.as_ref(),
439                             Some(default_parameters) => {
440                                 let mut default_from = 0;
441                                 for (i, parameter) in parameters.iter().enumerate() {
442                                     match (parameter.interned(&Interner), default_parameters.get(i))
443                                     {
444                                         (&TyKind::Unknown, _) | (_, None) => {
445                                             default_from = i + 1;
446                                         }
447                                         (_, Some(default_parameter)) => {
448                                             let actual_default = default_parameter
449                                                 .clone()
450                                                 .subst(&parameters.prefix(i));
451                                             if parameter != &actual_default {
452                                                 default_from = i + 1;
453                                             }
454                                         }
455                                     }
456                                 }
457                                 &parameters.0[0..default_from]
458                             }
459                         }
460                     } else {
461                         parameters.0.as_ref()
462                     };
463                     if !parameters_to_write.is_empty() {
464                         write!(f, "<")?;
465                         f.write_joined(parameters_to_write, ", ")?;
466                         write!(f, ">")?;
467                     }
468                 }
469             }
470             TyKind::AssociatedType(assoc_type_id, parameters) => {
471                 let type_alias = from_assoc_type_id(*assoc_type_id);
472                 let trait_ = match type_alias.lookup(f.db.upcast()).container {
473                     AssocContainerId::TraitId(it) => it,
474                     _ => panic!("not an associated type"),
475                 };
476                 let trait_ = f.db.trait_data(trait_);
477                 let type_alias_data = f.db.type_alias_data(type_alias);
478
479                 // Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
480                 if f.display_target.is_test() {
481                     write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
482                     if parameters.len() > 0 {
483                         write!(f, "<")?;
484                         f.write_joined(&*parameters.0, ", ")?;
485                         write!(f, ">")?;
486                     }
487                 } else {
488                     let projection_ty = ProjectionTy {
489                         associated_ty: to_assoc_type_id(type_alias),
490                         parameters: parameters.clone(),
491                     };
492
493                     projection_ty.hir_fmt(f)?;
494                 }
495             }
496             TyKind::ForeignType(type_alias) => {
497                 let type_alias = f.db.type_alias_data(from_foreign_def_id(*type_alias));
498                 write!(f, "{}", type_alias.name)?;
499             }
500             TyKind::OpaqueType(opaque_ty_id, parameters) => {
501                 match opaque_ty_id {
502                     &OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
503                         let datas =
504                             f.db.return_type_impl_traits(func).expect("impl trait id without data");
505                         let data = (*datas)
506                             .as_ref()
507                             .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
508                         let bounds = data.subst(&parameters);
509                         write_bounds_like_dyn_trait_with_prefix("impl", &bounds.value, f)?;
510                         // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
511                     }
512                     OpaqueTyId::AsyncBlockTypeImplTrait(..) => {
513                         write!(f, "impl Future<Output = ")?;
514                         parameters[0].hir_fmt(f)?;
515                         write!(f, ">")?;
516                     }
517                 }
518             }
519             TyKind::Closure(.., substs) => {
520                 let sig = substs[0].callable_sig(f.db);
521                 if let Some(sig) = sig {
522                     if sig.params().is_empty() {
523                         write!(f, "||")?;
524                     } else if f.omit_verbose_types() {
525                         write!(f, "|{}|", TYPE_HINT_TRUNCATION)?;
526                     } else {
527                         write!(f, "|")?;
528                         f.write_joined(sig.params(), ", ")?;
529                         write!(f, "|")?;
530                     };
531
532                     let ret_display = sig.ret().into_displayable(
533                         f.db,
534                         f.max_size,
535                         f.omit_verbose_types,
536                         f.display_target,
537                     );
538                     write!(f, " -> {}", ret_display)?;
539                 } else {
540                     write!(f, "{{closure}}")?;
541                 }
542             }
543             TyKind::Placeholder(id) => {
544                 let generics = generics(f.db.upcast(), id.parent);
545                 let param_data = &generics.params.types[id.local_id];
546                 match param_data.provenance {
547                     TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
548                         write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))?
549                     }
550                     TypeParamProvenance::ArgumentImplTrait => {
551                         let bounds = f.db.generic_predicates_for_param(*id);
552                         let substs = Substs::type_params_for_generics(&generics);
553                         write_bounds_like_dyn_trait_with_prefix(
554                             "impl",
555                             &bounds.iter().map(|b| b.clone().subst(&substs)).collect::<Vec<_>>(),
556                             f,
557                         )?;
558                     }
559                 }
560             }
561             TyKind::BoundVar(idx) => write!(f, "?{}.{}", idx.debruijn.depth(), idx.index)?,
562             TyKind::Dyn(predicates) => {
563                 write_bounds_like_dyn_trait_with_prefix("dyn", predicates, f)?;
564             }
565             TyKind::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?,
566             TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
567                 match opaque_ty.opaque_ty_id {
568                     OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
569                         let datas =
570                             f.db.return_type_impl_traits(func).expect("impl trait id without data");
571                         let data = (*datas)
572                             .as_ref()
573                             .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
574                         let bounds = data.subst(&opaque_ty.parameters);
575                         write_bounds_like_dyn_trait_with_prefix("impl", &bounds.value, f)?;
576                     }
577                     OpaqueTyId::AsyncBlockTypeImplTrait(..) => {
578                         write!(f, "{{async block}}")?;
579                     }
580                 };
581             }
582             TyKind::Unknown => {
583                 if f.display_target.is_source_code() {
584                     return Err(HirDisplayError::DisplaySourceCodeError(
585                         DisplaySourceCodeError::UnknownType,
586                     ));
587                 }
588                 write!(f, "{{unknown}}")?;
589             }
590             TyKind::InferenceVar(..) => write!(f, "_")?,
591         }
592         Ok(())
593     }
594 }
595
596 impl HirDisplay for CallableSig {
597     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
598         write!(f, "fn(")?;
599         f.write_joined(self.params(), ", ")?;
600         if self.is_varargs {
601             if self.params().is_empty() {
602                 write!(f, "...")?;
603             } else {
604                 write!(f, ", ...")?;
605             }
606         }
607         write!(f, ")")?;
608         let ret = self.ret();
609         if *ret != Ty::unit() {
610             let ret_display =
611                 ret.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target);
612             write!(f, " -> {}", ret_display)?;
613         }
614         Ok(())
615     }
616 }
617
618 fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> {
619     let krate = trait_.lookup(db).container.krate();
620     let fn_traits = [
621         db.lang_item(krate, "fn".into()),
622         db.lang_item(krate, "fn_mut".into()),
623         db.lang_item(krate, "fn_once".into()),
624     ];
625     // FIXME: Replace ArrayVec when into_iter is a thing on arrays
626     ArrayVec::from(fn_traits).into_iter().flatten().flat_map(|it| it.as_trait())
627 }
628
629 pub fn write_bounds_like_dyn_trait_with_prefix(
630     prefix: &str,
631     predicates: &[GenericPredicate],
632     f: &mut HirFormatter,
633 ) -> Result<(), HirDisplayError> {
634     write!(f, "{}", prefix)?;
635     if !predicates.is_empty() {
636         write!(f, " ")?;
637         write_bounds_like_dyn_trait(predicates, f)
638     } else {
639         Ok(())
640     }
641 }
642
643 fn write_bounds_like_dyn_trait(
644     predicates: &[GenericPredicate],
645     f: &mut HirFormatter,
646 ) -> Result<(), HirDisplayError> {
647     // Note: This code is written to produce nice results (i.e.
648     // corresponding to surface Rust) for types that can occur in
649     // actual Rust. It will have weird results if the predicates
650     // aren't as expected (i.e. self types = $0, projection
651     // predicates for a certain trait come after the Implemented
652     // predicate for that trait).
653     let mut first = true;
654     let mut angle_open = false;
655     let mut is_fn_trait = false;
656     for p in predicates.iter() {
657         match p {
658             GenericPredicate::Implemented(trait_ref) => {
659                 let trait_ = trait_ref.trait_;
660                 if !is_fn_trait {
661                     is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == trait_);
662                 }
663                 if !is_fn_trait && angle_open {
664                     write!(f, ">")?;
665                     angle_open = false;
666                 }
667                 if !first {
668                     write!(f, " + ")?;
669                 }
670                 // We assume that the self type is $0 (i.e. the
671                 // existential) here, which is the only thing that's
672                 // possible in actual Rust, and hence don't print it
673                 write!(f, "{}", f.db.trait_data(trait_).name)?;
674                 if let [_, params @ ..] = &*trait_ref.substs.0 {
675                     if is_fn_trait {
676                         if let Some(args) = params.first().and_then(|it| it.as_tuple()) {
677                             write!(f, "(")?;
678                             f.write_joined(&*args.0, ", ")?;
679                             write!(f, ")")?;
680                         }
681                     } else if !params.is_empty() {
682                         write!(f, "<")?;
683                         f.write_joined(params, ", ")?;
684                         // there might be assoc type bindings, so we leave the angle brackets open
685                         angle_open = true;
686                     }
687                 }
688             }
689             GenericPredicate::Projection(projection_pred) if is_fn_trait => {
690                 is_fn_trait = false;
691                 write!(f, " -> ")?;
692                 projection_pred.ty.hir_fmt(f)?;
693             }
694             GenericPredicate::Projection(projection_pred) => {
695                 // in types in actual Rust, these will always come
696                 // after the corresponding Implemented predicate
697                 if angle_open {
698                     write!(f, ", ")?;
699                 } else {
700                     write!(f, "<")?;
701                     angle_open = true;
702                 }
703                 let type_alias = f.db.type_alias_data(from_assoc_type_id(
704                     projection_pred.projection_ty.associated_ty,
705                 ));
706                 write!(f, "{} = ", type_alias.name)?;
707                 projection_pred.ty.hir_fmt(f)?;
708             }
709             GenericPredicate::Error => {
710                 if angle_open {
711                     // impl Trait<X, {error}>
712                     write!(f, ", ")?;
713                 } else if !first {
714                     // impl Trait + {error}
715                     write!(f, " + ")?;
716                 }
717                 p.hir_fmt(f)?;
718             }
719         }
720         first = false;
721     }
722     if angle_open {
723         write!(f, ">")?;
724     }
725     Ok(())
726 }
727
728 impl TraitRef {
729     fn hir_fmt_ext(&self, f: &mut HirFormatter, use_as: bool) -> Result<(), HirDisplayError> {
730         if f.should_truncate() {
731             return write!(f, "{}", TYPE_HINT_TRUNCATION);
732         }
733
734         self.substs[0].hir_fmt(f)?;
735         if use_as {
736             write!(f, " as ")?;
737         } else {
738             write!(f, ": ")?;
739         }
740         write!(f, "{}", f.db.trait_data(self.trait_).name)?;
741         if self.substs.len() > 1 {
742             write!(f, "<")?;
743             f.write_joined(&self.substs[1..], ", ")?;
744             write!(f, ">")?;
745         }
746         Ok(())
747     }
748 }
749
750 impl HirDisplay for TraitRef {
751     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
752         self.hir_fmt_ext(f, false)
753     }
754 }
755
756 impl HirDisplay for &GenericPredicate {
757     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
758         HirDisplay::hir_fmt(*self, f)
759     }
760 }
761
762 impl HirDisplay for GenericPredicate {
763     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
764         if f.should_truncate() {
765             return write!(f, "{}", TYPE_HINT_TRUNCATION);
766         }
767
768         match self {
769             GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
770             GenericPredicate::Projection(projection_pred) => {
771                 write!(f, "<")?;
772                 projection_pred.projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?;
773                 write!(
774                     f,
775                     ">::{} = ",
776                     f.db.type_alias_data(from_assoc_type_id(
777                         projection_pred.projection_ty.associated_ty
778                     ))
779                     .name,
780                 )?;
781                 projection_pred.ty.hir_fmt(f)?;
782             }
783             GenericPredicate::Error => write!(f, "{{error}}")?,
784         }
785         Ok(())
786     }
787 }
788
789 impl HirDisplay for Lifetime {
790     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
791         match self {
792             Lifetime::Parameter(id) => {
793                 let generics = generics(f.db.upcast(), id.parent);
794                 let param_data = &generics.params.lifetimes[id.local_id];
795                 write!(f, "{}", &param_data.name)
796             }
797             Lifetime::Static => write!(f, "'static"),
798         }
799     }
800 }
801
802 impl HirDisplay for Obligation {
803     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
804         match self {
805             Obligation::Trait(tr) => {
806                 write!(f, "Implements(")?;
807                 tr.hir_fmt(f)?;
808                 write!(f, ")")
809             }
810             Obligation::Projection(proj) => {
811                 write!(f, "Normalize(")?;
812                 proj.projection_ty.hir_fmt(f)?;
813                 write!(f, " => ")?;
814                 proj.ty.hir_fmt(f)?;
815                 write!(f, ")")
816             }
817         }
818     }
819 }