]> git.lizzy.rs Git - rust.git/blob - crates/hir_ty/src/display.rs
Merge #8015
[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, from_placeholder_idx, primitive,
15     to_assoc_type_id, traits::chalk::from_chalk, utils::generics, AdtId, AliasTy, CallableDefId,
16     CallableSig, GenericPredicate, ImplTraitId, Interner, Lifetime, Obligation, OpaqueTy,
17     ProjectionTy, Scalar, 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.substitution[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.substitution.len() > 1 {
256             write!(f, "<")?;
257             f.write_joined(&self.substitution[1..], ", ")?;
258             write!(f, ">")?;
259         }
260         write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).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(t) => {
280                 write!(f, "[")?;
281                 t.hir_fmt(f)?;
282                 write!(f, "]")?;
283             }
284             TyKind::Array(t) => {
285                 write!(f, "[")?;
286                 t.hir_fmt(f)?;
287                 write!(f, "; _]")?;
288             }
289             TyKind::Raw(m, t) | TyKind::Ref(m, t) => {
290                 let ty_display =
291                     t.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target);
292
293                 if matches!(self.interned(&Interner), TyKind::Raw(..)) {
294                     write!(
295                         f,
296                         "*{}",
297                         match m {
298                             Mutability::Not => "const ",
299                             Mutability::Mut => "mut ",
300                         }
301                     )?;
302                 } else {
303                     write!(
304                         f,
305                         "&{}",
306                         match m {
307                             Mutability::Not => "",
308                             Mutability::Mut => "mut ",
309                         }
310                     )?;
311                 }
312
313                 // FIXME: all this just to decide whether to use parentheses...
314                 let datas;
315                 let predicates = match t.interned(&Interner) {
316                     TyKind::Dyn(predicates) if predicates.len() > 1 => {
317                         Cow::Borrowed(predicates.as_ref())
318                     }
319                     &TyKind::Alias(AliasTy::Opaque(OpaqueTy {
320                         opaque_ty_id,
321                         substitution: ref parameters,
322                     })) => {
323                         let impl_trait_id = f.db.lookup_intern_impl_trait_id(opaque_ty_id.into());
324                         if let ImplTraitId::ReturnTypeImplTrait(func, idx) = impl_trait_id {
325                             datas =
326                                 f.db.return_type_impl_traits(func)
327                                     .expect("impl trait id without data");
328                             let data = (*datas)
329                                 .as_ref()
330                                 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
331                             let bounds = data.subst(parameters);
332                             Cow::Owned(bounds.value)
333                         } else {
334                             Cow::Borrowed(&[][..])
335                         }
336                     }
337                     _ => Cow::Borrowed(&[][..]),
338                 };
339
340                 if let [GenericPredicate::Implemented(trait_ref), _] = predicates.as_ref() {
341                     let trait_ = trait_ref.trait_;
342                     if fn_traits(f.db.upcast(), trait_).any(|it| it == trait_) {
343                         return write!(f, "{}", ty_display);
344                     }
345                 }
346
347                 if predicates.len() > 1 {
348                     write!(f, "(")?;
349                     write!(f, "{}", ty_display)?;
350                     write!(f, ")")?;
351                 } else {
352                     write!(f, "{}", ty_display)?;
353                 }
354             }
355             TyKind::Tuple(_, substs) => {
356                 if substs.len() == 1 {
357                     write!(f, "(")?;
358                     substs[0].hir_fmt(f)?;
359                     write!(f, ",)")?;
360                 } else {
361                     write!(f, "(")?;
362                     f.write_joined(&*substs.0, ", ")?;
363                     write!(f, ")")?;
364                 }
365             }
366             TyKind::Function(fn_ptr) => {
367                 let sig = CallableSig::from_fn_ptr(fn_ptr);
368                 sig.hir_fmt(f)?;
369             }
370             TyKind::FnDef(def, parameters) => {
371                 let def = from_chalk(f.db, *def);
372                 let sig = f.db.callable_item_signature(def).subst(parameters);
373                 match def {
374                     CallableDefId::FunctionId(ff) => {
375                         write!(f, "fn {}", f.db.function_data(ff).name)?
376                     }
377                     CallableDefId::StructId(s) => write!(f, "{}", f.db.struct_data(s).name)?,
378                     CallableDefId::EnumVariantId(e) => {
379                         write!(f, "{}", f.db.enum_data(e.parent).variants[e.local_id].name)?
380                     }
381                 };
382                 if parameters.len() > 0 {
383                     let generics = generics(f.db.upcast(), def.into());
384                     let (parent_params, self_param, type_params, _impl_trait_params) =
385                         generics.provenance_split();
386                     let total_len = parent_params + self_param + type_params;
387                     // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
388                     if total_len > 0 {
389                         write!(f, "<")?;
390                         f.write_joined(&parameters.0[..total_len], ", ")?;
391                         write!(f, ">")?;
392                     }
393                 }
394                 write!(f, "(")?;
395                 f.write_joined(sig.params(), ", ")?;
396                 write!(f, ")")?;
397                 let ret = sig.ret();
398                 if *ret != Ty::unit() {
399                     let ret_display = ret.into_displayable(
400                         f.db,
401                         f.max_size,
402                         f.omit_verbose_types,
403                         f.display_target,
404                     );
405
406                     write!(f, " -> {}", ret_display)?;
407                 }
408             }
409             TyKind::Adt(AdtId(def_id), parameters) => {
410                 match f.display_target {
411                     DisplayTarget::Diagnostics | DisplayTarget::Test => {
412                         let name = match *def_id {
413                             hir_def::AdtId::StructId(it) => f.db.struct_data(it).name.clone(),
414                             hir_def::AdtId::UnionId(it) => f.db.union_data(it).name.clone(),
415                             hir_def::AdtId::EnumId(it) => f.db.enum_data(it).name.clone(),
416                         };
417                         write!(f, "{}", name)?;
418                     }
419                     DisplayTarget::SourceCode { module_id } => {
420                         if let Some(path) = find_path::find_path(
421                             f.db.upcast(),
422                             ItemInNs::Types((*def_id).into()),
423                             module_id,
424                         ) {
425                             write!(f, "{}", path)?;
426                         } else {
427                             return Err(HirDisplayError::DisplaySourceCodeError(
428                                 DisplaySourceCodeError::PathNotFound,
429                             ));
430                         }
431                     }
432                 }
433
434                 if parameters.len() > 0 {
435                     let parameters_to_write = if f.display_target.is_source_code()
436                         || f.omit_verbose_types()
437                     {
438                         match self
439                             .as_generic_def(f.db)
440                             .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
441                             .filter(|defaults| !defaults.is_empty())
442                         {
443                             None => parameters.0.as_ref(),
444                             Some(default_parameters) => {
445                                 let mut default_from = 0;
446                                 for (i, parameter) in parameters.iter().enumerate() {
447                                     match (parameter.interned(&Interner), default_parameters.get(i))
448                                     {
449                                         (&TyKind::Unknown, _) | (_, None) => {
450                                             default_from = i + 1;
451                                         }
452                                         (_, Some(default_parameter)) => {
453                                             let actual_default = default_parameter
454                                                 .clone()
455                                                 .subst(&parameters.prefix(i));
456                                             if parameter != &actual_default {
457                                                 default_from = i + 1;
458                                             }
459                                         }
460                                     }
461                                 }
462                                 &parameters.0[0..default_from]
463                             }
464                         }
465                     } else {
466                         parameters.0.as_ref()
467                     };
468                     if !parameters_to_write.is_empty() {
469                         write!(f, "<")?;
470                         f.write_joined(parameters_to_write, ", ")?;
471                         write!(f, ">")?;
472                     }
473                 }
474             }
475             TyKind::AssociatedType(assoc_type_id, parameters) => {
476                 let type_alias = from_assoc_type_id(*assoc_type_id);
477                 let trait_ = match type_alias.lookup(f.db.upcast()).container {
478                     AssocContainerId::TraitId(it) => it,
479                     _ => panic!("not an associated type"),
480                 };
481                 let trait_ = f.db.trait_data(trait_);
482                 let type_alias_data = f.db.type_alias_data(type_alias);
483
484                 // Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
485                 if f.display_target.is_test() {
486                     write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
487                     if parameters.len() > 0 {
488                         write!(f, "<")?;
489                         f.write_joined(&*parameters.0, ", ")?;
490                         write!(f, ">")?;
491                     }
492                 } else {
493                     let projection_ty = ProjectionTy {
494                         associated_ty_id: to_assoc_type_id(type_alias),
495                         substitution: parameters.clone(),
496                     };
497
498                     projection_ty.hir_fmt(f)?;
499                 }
500             }
501             TyKind::ForeignType(type_alias) => {
502                 let type_alias = f.db.type_alias_data(from_foreign_def_id(*type_alias));
503                 write!(f, "{}", type_alias.name)?;
504             }
505             TyKind::OpaqueType(opaque_ty_id, parameters) => {
506                 let impl_trait_id = f.db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
507                 match impl_trait_id {
508                     ImplTraitId::ReturnTypeImplTrait(func, idx) => {
509                         let datas =
510                             f.db.return_type_impl_traits(func).expect("impl trait id without data");
511                         let data = (*datas)
512                             .as_ref()
513                             .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
514                         let bounds = data.subst(&parameters);
515                         write_bounds_like_dyn_trait_with_prefix("impl", &bounds.value, f)?;
516                         // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
517                     }
518                     ImplTraitId::AsyncBlockTypeImplTrait(..) => {
519                         write!(f, "impl Future<Output = ")?;
520                         parameters[0].hir_fmt(f)?;
521                         write!(f, ">")?;
522                     }
523                 }
524             }
525             TyKind::Closure(.., substs) => {
526                 let sig = substs[0].callable_sig(f.db);
527                 if let Some(sig) = sig {
528                     if sig.params().is_empty() {
529                         write!(f, "||")?;
530                     } else if f.omit_verbose_types() {
531                         write!(f, "|{}|", TYPE_HINT_TRUNCATION)?;
532                     } else {
533                         write!(f, "|")?;
534                         f.write_joined(sig.params(), ", ")?;
535                         write!(f, "|")?;
536                     };
537
538                     let ret_display = sig.ret().into_displayable(
539                         f.db,
540                         f.max_size,
541                         f.omit_verbose_types,
542                         f.display_target,
543                     );
544                     write!(f, " -> {}", ret_display)?;
545                 } else {
546                     write!(f, "{{closure}}")?;
547                 }
548             }
549             TyKind::Placeholder(idx) => {
550                 let id = from_placeholder_idx(f.db, *idx);
551                 let generics = generics(f.db.upcast(), id.parent);
552                 let param_data = &generics.params.types[id.local_id];
553                 match param_data.provenance {
554                     TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
555                         write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))?
556                     }
557                     TypeParamProvenance::ArgumentImplTrait => {
558                         let bounds = f.db.generic_predicates_for_param(id);
559                         let substs = Substs::type_params_for_generics(f.db, &generics);
560                         write_bounds_like_dyn_trait_with_prefix(
561                             "impl",
562                             &bounds.iter().map(|b| b.clone().subst(&substs)).collect::<Vec<_>>(),
563                             f,
564                         )?;
565                     }
566                 }
567             }
568             TyKind::BoundVar(idx) => write!(f, "?{}.{}", idx.debruijn.depth(), idx.index)?,
569             TyKind::Dyn(predicates) => {
570                 write_bounds_like_dyn_trait_with_prefix("dyn", predicates, f)?;
571             }
572             TyKind::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?,
573             TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
574                 let impl_trait_id = f.db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into());
575                 match impl_trait_id {
576                     ImplTraitId::ReturnTypeImplTrait(func, idx) => {
577                         let datas =
578                             f.db.return_type_impl_traits(func).expect("impl trait id without data");
579                         let data = (*datas)
580                             .as_ref()
581                             .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
582                         let bounds = data.subst(&opaque_ty.substitution);
583                         write_bounds_like_dyn_trait_with_prefix("impl", &bounds.value, f)?;
584                     }
585                     ImplTraitId::AsyncBlockTypeImplTrait(..) => {
586                         write!(f, "{{async block}}")?;
587                     }
588                 };
589             }
590             TyKind::Unknown => {
591                 if f.display_target.is_source_code() {
592                     return Err(HirDisplayError::DisplaySourceCodeError(
593                         DisplaySourceCodeError::UnknownType,
594                     ));
595                 }
596                 write!(f, "{{unknown}}")?;
597             }
598             TyKind::InferenceVar(..) => write!(f, "_")?,
599         }
600         Ok(())
601     }
602 }
603
604 impl HirDisplay for CallableSig {
605     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
606         write!(f, "fn(")?;
607         f.write_joined(self.params(), ", ")?;
608         if self.is_varargs {
609             if self.params().is_empty() {
610                 write!(f, "...")?;
611             } else {
612                 write!(f, ", ...")?;
613             }
614         }
615         write!(f, ")")?;
616         let ret = self.ret();
617         if *ret != Ty::unit() {
618             let ret_display =
619                 ret.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target);
620             write!(f, " -> {}", ret_display)?;
621         }
622         Ok(())
623     }
624 }
625
626 fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> {
627     let krate = trait_.lookup(db).container.krate();
628     let fn_traits = [
629         db.lang_item(krate, "fn".into()),
630         db.lang_item(krate, "fn_mut".into()),
631         db.lang_item(krate, "fn_once".into()),
632     ];
633     // FIXME: Replace ArrayVec when into_iter is a thing on arrays
634     ArrayVec::from(fn_traits).into_iter().flatten().flat_map(|it| it.as_trait())
635 }
636
637 pub fn write_bounds_like_dyn_trait_with_prefix(
638     prefix: &str,
639     predicates: &[GenericPredicate],
640     f: &mut HirFormatter,
641 ) -> Result<(), HirDisplayError> {
642     write!(f, "{}", prefix)?;
643     if !predicates.is_empty() {
644         write!(f, " ")?;
645         write_bounds_like_dyn_trait(predicates, f)
646     } else {
647         Ok(())
648     }
649 }
650
651 fn write_bounds_like_dyn_trait(
652     predicates: &[GenericPredicate],
653     f: &mut HirFormatter,
654 ) -> Result<(), HirDisplayError> {
655     // Note: This code is written to produce nice results (i.e.
656     // corresponding to surface Rust) for types that can occur in
657     // actual Rust. It will have weird results if the predicates
658     // aren't as expected (i.e. self types = $0, projection
659     // predicates for a certain trait come after the Implemented
660     // predicate for that trait).
661     let mut first = true;
662     let mut angle_open = false;
663     let mut is_fn_trait = false;
664     for p in predicates.iter() {
665         match p {
666             GenericPredicate::Implemented(trait_ref) => {
667                 let trait_ = trait_ref.trait_;
668                 if !is_fn_trait {
669                     is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == trait_);
670                 }
671                 if !is_fn_trait && angle_open {
672                     write!(f, ">")?;
673                     angle_open = false;
674                 }
675                 if !first {
676                     write!(f, " + ")?;
677                 }
678                 // We assume that the self type is $0 (i.e. the
679                 // existential) here, which is the only thing that's
680                 // possible in actual Rust, and hence don't print it
681                 write!(f, "{}", f.db.trait_data(trait_).name)?;
682                 if let [_, params @ ..] = &*trait_ref.substs.0 {
683                     if is_fn_trait {
684                         if let Some(args) = params.first().and_then(|it| it.as_tuple()) {
685                             write!(f, "(")?;
686                             f.write_joined(&*args.0, ", ")?;
687                             write!(f, ")")?;
688                         }
689                     } else if !params.is_empty() {
690                         write!(f, "<")?;
691                         f.write_joined(params, ", ")?;
692                         // there might be assoc type bindings, so we leave the angle brackets open
693                         angle_open = true;
694                     }
695                 }
696             }
697             GenericPredicate::Projection(projection_pred) if is_fn_trait => {
698                 is_fn_trait = false;
699                 write!(f, " -> ")?;
700                 projection_pred.ty.hir_fmt(f)?;
701             }
702             GenericPredicate::Projection(projection_pred) => {
703                 // in types in actual Rust, these will always come
704                 // after the corresponding Implemented predicate
705                 if angle_open {
706                     write!(f, ", ")?;
707                 } else {
708                     write!(f, "<")?;
709                     angle_open = true;
710                 }
711                 let type_alias = f.db.type_alias_data(from_assoc_type_id(
712                     projection_pred.projection_ty.associated_ty_id,
713                 ));
714                 write!(f, "{} = ", type_alias.name)?;
715                 projection_pred.ty.hir_fmt(f)?;
716             }
717             GenericPredicate::Error => {
718                 if angle_open {
719                     // impl Trait<X, {error}>
720                     write!(f, ", ")?;
721                 } else if !first {
722                     // impl Trait + {error}
723                     write!(f, " + ")?;
724                 }
725                 p.hir_fmt(f)?;
726             }
727         }
728         first = false;
729     }
730     if angle_open {
731         write!(f, ">")?;
732     }
733     Ok(())
734 }
735
736 impl TraitRef {
737     fn hir_fmt_ext(&self, f: &mut HirFormatter, use_as: bool) -> Result<(), HirDisplayError> {
738         if f.should_truncate() {
739             return write!(f, "{}", TYPE_HINT_TRUNCATION);
740         }
741
742         self.substs[0].hir_fmt(f)?;
743         if use_as {
744             write!(f, " as ")?;
745         } else {
746             write!(f, ": ")?;
747         }
748         write!(f, "{}", f.db.trait_data(self.trait_).name)?;
749         if self.substs.len() > 1 {
750             write!(f, "<")?;
751             f.write_joined(&self.substs[1..], ", ")?;
752             write!(f, ">")?;
753         }
754         Ok(())
755     }
756 }
757
758 impl HirDisplay for TraitRef {
759     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
760         self.hir_fmt_ext(f, false)
761     }
762 }
763
764 impl HirDisplay for &GenericPredicate {
765     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
766         HirDisplay::hir_fmt(*self, f)
767     }
768 }
769
770 impl HirDisplay for GenericPredicate {
771     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
772         if f.should_truncate() {
773             return write!(f, "{}", TYPE_HINT_TRUNCATION);
774         }
775
776         match self {
777             GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
778             GenericPredicate::Projection(projection_pred) => {
779                 write!(f, "<")?;
780                 projection_pred.projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?;
781                 write!(
782                     f,
783                     ">::{} = ",
784                     f.db.type_alias_data(from_assoc_type_id(
785                         projection_pred.projection_ty.associated_ty_id
786                     ))
787                     .name,
788                 )?;
789                 projection_pred.ty.hir_fmt(f)?;
790             }
791             GenericPredicate::Error => write!(f, "{{error}}")?,
792         }
793         Ok(())
794     }
795 }
796
797 impl HirDisplay for Lifetime {
798     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
799         match self {
800             Lifetime::Parameter(id) => {
801                 let generics = generics(f.db.upcast(), id.parent);
802                 let param_data = &generics.params.lifetimes[id.local_id];
803                 write!(f, "{}", &param_data.name)
804             }
805             Lifetime::Static => write!(f, "'static"),
806         }
807     }
808 }
809
810 impl HirDisplay for Obligation {
811     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
812         match self {
813             Obligation::Trait(tr) => {
814                 write!(f, "Implements(")?;
815                 tr.hir_fmt(f)?;
816                 write!(f, ")")
817             }
818             Obligation::Projection(proj) => {
819                 write!(f, "Normalize(")?;
820                 proj.projection_ty.hir_fmt(f)?;
821                 write!(f, " => ")?;
822                 proj.ty.hir_fmt(f)?;
823                 write!(f, ")")
824             }
825         }
826     }
827 }