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