]> git.lizzy.rs Git - rust.git/blob - crates/hir_ty/src/display.rs
Use chalk_ir::AdtId
[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, HasModule, Lookup, ModuleId, TraitId,
10 };
11 use hir_expand::name::Name;
12
13 use crate::{
14     db::HirDatabase, primitive, utils::generics, AdtId, AliasTy, CallableDefId, CallableSig,
15     GenericPredicate, Lifetime, Obligation, OpaqueTy, OpaqueTyId, ProjectionTy, Scalar, Substs,
16     TraitRef, Ty,
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(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 {
271             Ty::Never => write!(f, "!")?,
272             Ty::Str => write!(f, "str")?,
273             Ty::Scalar(Scalar::Bool) => write!(f, "bool")?,
274             Ty::Scalar(Scalar::Char) => write!(f, "char")?,
275             &Ty::Scalar(Scalar::Float(t)) => write!(f, "{}", primitive::float_ty_to_string(t))?,
276             &Ty::Scalar(Scalar::Int(t)) => write!(f, "{}", primitive::int_ty_to_string(t))?,
277             &Ty::Scalar(Scalar::Uint(t)) => write!(f, "{}", primitive::uint_ty_to_string(t))?,
278             Ty::Slice(parameters) => {
279                 let t = parameters.as_single();
280                 write!(f, "[")?;
281                 t.hir_fmt(f)?;
282                 write!(f, "]")?;
283             }
284             Ty::Array(parameters) => {
285                 let t = parameters.as_single();
286                 write!(f, "[")?;
287                 t.hir_fmt(f)?;
288                 write!(f, "; _]")?;
289             }
290             Ty::Raw(m, parameters) | Ty::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, Ty::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 {
317                     Ty::Dyn(predicates) if predicates.len() > 1 => {
318                         Cow::Borrowed(predicates.as_ref())
319                     }
320                     &Ty::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             Ty::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             Ty::Function(fn_ptr) => {
362                 let sig = CallableSig::from_fn_ptr(fn_ptr);
363                 sig.hir_fmt(f)?;
364             }
365             Ty::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             Ty::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 =
431                         if f.display_target.is_source_code() || f.omit_verbose_types() {
432                             match self
433                                 .as_generic_def()
434                                 .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
435                                 .filter(|defaults| !defaults.is_empty())
436                             {
437                                 None => parameters.0.as_ref(),
438                                 Some(default_parameters) => {
439                                     let mut default_from = 0;
440                                     for (i, parameter) in parameters.iter().enumerate() {
441                                         match (parameter, default_parameters.get(i)) {
442                                             (&Ty::Unknown, _) | (_, None) => {
443                                                 default_from = i + 1;
444                                             }
445                                             (_, Some(default_parameter)) => {
446                                                 let actual_default = default_parameter
447                                                     .clone()
448                                                     .subst(&parameters.prefix(i));
449                                                 if parameter != &actual_default {
450                                                     default_from = i + 1;
451                                                 }
452                                             }
453                                         }
454                                     }
455                                     &parameters.0[0..default_from]
456                                 }
457                             }
458                         } else {
459                             parameters.0.as_ref()
460                         };
461                     if !parameters_to_write.is_empty() {
462                         write!(f, "<")?;
463                         f.write_joined(parameters_to_write, ", ")?;
464                         write!(f, ">")?;
465                     }
466                 }
467             }
468             Ty::AssociatedType(type_alias, parameters) => {
469                 let trait_ = match type_alias.lookup(f.db.upcast()).container {
470                     AssocContainerId::TraitId(it) => it,
471                     _ => panic!("not an associated type"),
472                 };
473                 let trait_ = f.db.trait_data(trait_);
474                 let type_alias_data = f.db.type_alias_data(*type_alias);
475
476                 // Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
477                 if f.display_target.is_test() {
478                     write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
479                     if parameters.len() > 0 {
480                         write!(f, "<")?;
481                         f.write_joined(&*parameters.0, ", ")?;
482                         write!(f, ">")?;
483                     }
484                 } else {
485                     let projection_ty =
486                         ProjectionTy { associated_ty: *type_alias, parameters: parameters.clone() };
487
488                     projection_ty.hir_fmt(f)?;
489                 }
490             }
491             Ty::ForeignType(type_alias) => {
492                 let type_alias = f.db.type_alias_data(*type_alias);
493                 write!(f, "{}", type_alias.name)?;
494             }
495             Ty::OpaqueType(opaque_ty_id, parameters) => {
496                 match opaque_ty_id {
497                     &OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
498                         let datas =
499                             f.db.return_type_impl_traits(func).expect("impl trait id without data");
500                         let data = (*datas)
501                             .as_ref()
502                             .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
503                         let bounds = data.subst(&parameters);
504                         write_bounds_like_dyn_trait_with_prefix("impl", &bounds.value, f)?;
505                         // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
506                     }
507                     OpaqueTyId::AsyncBlockTypeImplTrait(..) => {
508                         write!(f, "impl Future<Output = ")?;
509                         parameters[0].hir_fmt(f)?;
510                         write!(f, ">")?;
511                     }
512                 }
513             }
514             Ty::Closure(.., substs) => {
515                 let sig = substs[0].callable_sig(f.db);
516                 if let Some(sig) = sig {
517                     if sig.params().is_empty() {
518                         write!(f, "||")?;
519                     } else if f.omit_verbose_types() {
520                         write!(f, "|{}|", TYPE_HINT_TRUNCATION)?;
521                     } else {
522                         write!(f, "|")?;
523                         f.write_joined(sig.params(), ", ")?;
524                         write!(f, "|")?;
525                     };
526
527                     let ret_display = sig.ret().into_displayable(
528                         f.db,
529                         f.max_size,
530                         f.omit_verbose_types,
531                         f.display_target,
532                     );
533                     write!(f, " -> {}", ret_display)?;
534                 } else {
535                     write!(f, "{{closure}}")?;
536                 }
537             }
538             Ty::Placeholder(id) => {
539                 let generics = generics(f.db.upcast(), id.parent);
540                 let param_data = &generics.params.types[id.local_id];
541                 match param_data.provenance {
542                     TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
543                         write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))?
544                     }
545                     TypeParamProvenance::ArgumentImplTrait => {
546                         let bounds = f.db.generic_predicates_for_param(*id);
547                         let substs = Substs::type_params_for_generics(&generics);
548                         write_bounds_like_dyn_trait_with_prefix(
549                             "impl",
550                             &bounds.iter().map(|b| b.clone().subst(&substs)).collect::<Vec<_>>(),
551                             f,
552                         )?;
553                     }
554                 }
555             }
556             Ty::BoundVar(idx) => write!(f, "?{}.{}", idx.debruijn.depth(), idx.index)?,
557             Ty::Dyn(predicates) => {
558                 write_bounds_like_dyn_trait_with_prefix("dyn", predicates, f)?;
559             }
560             Ty::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?,
561             Ty::Alias(AliasTy::Opaque(opaque_ty)) => {
562                 match opaque_ty.opaque_ty_id {
563                     OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
564                         let datas =
565                             f.db.return_type_impl_traits(func).expect("impl trait id without data");
566                         let data = (*datas)
567                             .as_ref()
568                             .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
569                         let bounds = data.subst(&opaque_ty.parameters);
570                         write_bounds_like_dyn_trait_with_prefix("impl", &bounds.value, f)?;
571                     }
572                     OpaqueTyId::AsyncBlockTypeImplTrait(..) => {
573                         write!(f, "{{async block}}")?;
574                     }
575                 };
576             }
577             Ty::Unknown => {
578                 if f.display_target.is_source_code() {
579                     return Err(HirDisplayError::DisplaySourceCodeError(
580                         DisplaySourceCodeError::UnknownType,
581                     ));
582                 }
583                 write!(f, "{{unknown}}")?;
584             }
585             Ty::InferenceVar(..) => write!(f, "_")?,
586         }
587         Ok(())
588     }
589 }
590
591 impl HirDisplay for CallableSig {
592     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
593         write!(f, "fn(")?;
594         f.write_joined(self.params(), ", ")?;
595         if self.is_varargs {
596             if self.params().is_empty() {
597                 write!(f, "...")?;
598             } else {
599                 write!(f, ", ...")?;
600             }
601         }
602         write!(f, ")")?;
603         let ret = self.ret();
604         if *ret != Ty::unit() {
605             let ret_display =
606                 ret.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target);
607             write!(f, " -> {}", ret_display)?;
608         }
609         Ok(())
610     }
611 }
612
613 fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> {
614     let krate = trait_.lookup(db).container.module(db).krate();
615     let fn_traits = [
616         db.lang_item(krate, "fn".into()),
617         db.lang_item(krate, "fn_mut".into()),
618         db.lang_item(krate, "fn_once".into()),
619     ];
620     // FIXME: Replace ArrayVec when into_iter is a thing on arrays
621     ArrayVec::from(fn_traits).into_iter().flatten().flat_map(|it| it.as_trait())
622 }
623
624 pub fn write_bounds_like_dyn_trait_with_prefix(
625     prefix: &str,
626     predicates: &[GenericPredicate],
627     f: &mut HirFormatter,
628 ) -> Result<(), HirDisplayError> {
629     write!(f, "{}", prefix)?;
630     if !predicates.is_empty() {
631         write!(f, " ")?;
632         write_bounds_like_dyn_trait(predicates, f)
633     } else {
634         Ok(())
635     }
636 }
637
638 fn write_bounds_like_dyn_trait(
639     predicates: &[GenericPredicate],
640     f: &mut HirFormatter,
641 ) -> Result<(), HirDisplayError> {
642     // Note: This code is written to produce nice results (i.e.
643     // corresponding to surface Rust) for types that can occur in
644     // actual Rust. It will have weird results if the predicates
645     // aren't as expected (i.e. self types = $0, projection
646     // predicates for a certain trait come after the Implemented
647     // predicate for that trait).
648     let mut first = true;
649     let mut angle_open = false;
650     let mut is_fn_trait = false;
651     for p in predicates.iter() {
652         match p {
653             GenericPredicate::Implemented(trait_ref) => {
654                 let trait_ = trait_ref.trait_;
655                 if !is_fn_trait {
656                     is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == trait_);
657                 }
658                 if !is_fn_trait && angle_open {
659                     write!(f, ">")?;
660                     angle_open = false;
661                 }
662                 if !first {
663                     write!(f, " + ")?;
664                 }
665                 // We assume that the self type is $0 (i.e. the
666                 // existential) here, which is the only thing that's
667                 // possible in actual Rust, and hence don't print it
668                 write!(f, "{}", f.db.trait_data(trait_).name)?;
669                 if let [_, params @ ..] = &*trait_ref.substs.0 {
670                     if is_fn_trait {
671                         if let Some(args) = params.first().and_then(|it| it.as_tuple()) {
672                             write!(f, "(")?;
673                             f.write_joined(&*args.0, ", ")?;
674                             write!(f, ")")?;
675                         }
676                     } else if !params.is_empty() {
677                         write!(f, "<")?;
678                         f.write_joined(params, ", ")?;
679                         // there might be assoc type bindings, so we leave the angle brackets open
680                         angle_open = true;
681                     }
682                 }
683             }
684             GenericPredicate::Projection(projection_pred) if is_fn_trait => {
685                 is_fn_trait = false;
686                 write!(f, " -> ")?;
687                 projection_pred.ty.hir_fmt(f)?;
688             }
689             GenericPredicate::Projection(projection_pred) => {
690                 // in types in actual Rust, these will always come
691                 // after the corresponding Implemented predicate
692                 if angle_open {
693                     write!(f, ", ")?;
694                 } else {
695                     write!(f, "<")?;
696                     angle_open = true;
697                 }
698                 let type_alias = f.db.type_alias_data(projection_pred.projection_ty.associated_ty);
699                 write!(f, "{} = ", type_alias.name)?;
700                 projection_pred.ty.hir_fmt(f)?;
701             }
702             GenericPredicate::Error => {
703                 if angle_open {
704                     // impl Trait<X, {error}>
705                     write!(f, ", ")?;
706                 } else if !first {
707                     // impl Trait + {error}
708                     write!(f, " + ")?;
709                 }
710                 p.hir_fmt(f)?;
711             }
712         }
713         first = false;
714     }
715     if angle_open {
716         write!(f, ">")?;
717     }
718     Ok(())
719 }
720
721 impl TraitRef {
722     fn hir_fmt_ext(&self, f: &mut HirFormatter, use_as: bool) -> Result<(), HirDisplayError> {
723         if f.should_truncate() {
724             return write!(f, "{}", TYPE_HINT_TRUNCATION);
725         }
726
727         self.substs[0].hir_fmt(f)?;
728         if use_as {
729             write!(f, " as ")?;
730         } else {
731             write!(f, ": ")?;
732         }
733         write!(f, "{}", f.db.trait_data(self.trait_).name)?;
734         if self.substs.len() > 1 {
735             write!(f, "<")?;
736             f.write_joined(&self.substs[1..], ", ")?;
737             write!(f, ">")?;
738         }
739         Ok(())
740     }
741 }
742
743 impl HirDisplay for TraitRef {
744     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
745         self.hir_fmt_ext(f, false)
746     }
747 }
748
749 impl HirDisplay for &GenericPredicate {
750     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
751         HirDisplay::hir_fmt(*self, f)
752     }
753 }
754
755 impl HirDisplay for GenericPredicate {
756     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
757         if f.should_truncate() {
758             return write!(f, "{}", TYPE_HINT_TRUNCATION);
759         }
760
761         match self {
762             GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
763             GenericPredicate::Projection(projection_pred) => {
764                 write!(f, "<")?;
765                 projection_pred.projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?;
766                 write!(
767                     f,
768                     ">::{} = ",
769                     f.db.type_alias_data(projection_pred.projection_ty.associated_ty).name,
770                 )?;
771                 projection_pred.ty.hir_fmt(f)?;
772             }
773             GenericPredicate::Error => write!(f, "{{error}}")?,
774         }
775         Ok(())
776     }
777 }
778
779 impl HirDisplay for Lifetime {
780     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
781         match self {
782             Lifetime::Parameter(id) => {
783                 let generics = generics(f.db.upcast(), id.parent);
784                 let param_data = &generics.params.lifetimes[id.local_id];
785                 write!(f, "{}", &param_data.name)
786             }
787             Lifetime::Static => write!(f, "'static"),
788         }
789     }
790 }
791
792 impl HirDisplay for Obligation {
793     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
794         match self {
795             Obligation::Trait(tr) => {
796                 write!(f, "Implements(")?;
797                 tr.hir_fmt(f)?;
798                 write!(f, ")")
799             }
800             Obligation::Projection(proj) => {
801                 write!(f, "Normalize(")?;
802                 proj.projection_ty.hir_fmt(f)?;
803                 write!(f, " => ")?;
804                 proj.ty.hir_fmt(f)?;
805                 write!(f, ")")
806             }
807         }
808     }
809 }