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