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