]> git.lizzy.rs Git - rust.git/blob - crates/hir_ty/src/display.rs
Add lowering of array lengths in types
[rust.git] / crates / hir_ty / src / display.rs
1 //! The `HirDisplay` trait, which serves two purposes: Turning various bits from
2 //! HIR back into source code, and just displaying them for debugging/testing
3 //! purposes.
4
5 use std::{
6     array,
7     fmt::{self, Debug},
8 };
9
10 use chalk_ir::BoundVar;
11 use hir_def::{
12     body,
13     db::DefDatabase,
14     find_path,
15     generics::TypeParamProvenance,
16     item_scope::ItemInNs,
17     path::{Path, PathKind},
18     type_ref::{TypeBound, TypeRef},
19     visibility::Visibility,
20     AssocContainerId, Lookup, ModuleId, TraitId,
21 };
22 use hir_expand::{hygiene::Hygiene, name::Name};
23
24 use crate::{
25     const_from_placeholder_idx, db::HirDatabase, from_assoc_type_id, from_foreign_def_id,
26     from_placeholder_idx, lt_from_placeholder_idx, mapping::from_chalk, primitive, subst_prefix,
27     to_assoc_type_id, utils::generics, AdtId, AliasEq, AliasTy, CallableDefId, CallableSig, Const,
28     ConstValue, DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData,
29     LifetimeOutlives, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause,
30     Scalar, TraitRef, TraitRefExt, Ty, TyExt, TyKind, WhereClause,
31 };
32
33 pub struct HirFormatter<'a> {
34     pub db: &'a dyn HirDatabase,
35     fmt: &'a mut dyn fmt::Write,
36     buf: String,
37     curr_size: usize,
38     pub(crate) max_size: Option<usize>,
39     omit_verbose_types: bool,
40     display_target: DisplayTarget,
41 }
42
43 pub trait HirDisplay {
44     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError>;
45
46     /// Returns a `Display`able type that is human-readable.
47     fn into_displayable<'a>(
48         &'a self,
49         db: &'a dyn HirDatabase,
50         max_size: Option<usize>,
51         omit_verbose_types: bool,
52         display_target: DisplayTarget,
53     ) -> HirDisplayWrapper<'a, Self>
54     where
55         Self: Sized,
56     {
57         assert!(
58             !matches!(display_target, DisplayTarget::SourceCode { .. }),
59             "HirDisplayWrapper cannot fail with DisplaySourceCodeError, use HirDisplay::hir_fmt directly instead"
60         );
61         HirDisplayWrapper { db, t: self, max_size, omit_verbose_types, display_target }
62     }
63
64     /// Returns a `Display`able type that is human-readable.
65     /// Use this for showing types to the user (e.g. diagnostics)
66     fn display<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self>
67     where
68         Self: Sized,
69     {
70         HirDisplayWrapper {
71             db,
72             t: self,
73             max_size: None,
74             omit_verbose_types: false,
75             display_target: DisplayTarget::Diagnostics,
76         }
77     }
78
79     /// Returns a `Display`able type that is human-readable and tries to be succinct.
80     /// Use this for showing types to the user where space is constrained (e.g. doc popups)
81     fn display_truncated<'a>(
82         &'a self,
83         db: &'a dyn HirDatabase,
84         max_size: Option<usize>,
85     ) -> HirDisplayWrapper<'a, Self>
86     where
87         Self: Sized,
88     {
89         HirDisplayWrapper {
90             db,
91             t: self,
92             max_size,
93             omit_verbose_types: true,
94             display_target: DisplayTarget::Diagnostics,
95         }
96     }
97
98     /// Returns a String representation of `self` that can be inserted into the given module.
99     /// Use this when generating code (e.g. assists)
100     fn display_source_code<'a>(
101         &'a self,
102         db: &'a dyn HirDatabase,
103         module_id: ModuleId,
104     ) -> Result<String, DisplaySourceCodeError> {
105         let mut result = String::new();
106         match self.hir_fmt(&mut HirFormatter {
107             db,
108             fmt: &mut result,
109             buf: String::with_capacity(20),
110             curr_size: 0,
111             max_size: None,
112             omit_verbose_types: false,
113             display_target: DisplayTarget::SourceCode { module_id },
114         }) {
115             Ok(()) => {}
116             Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"),
117             Err(HirDisplayError::DisplaySourceCodeError(e)) => return Err(e),
118         };
119         Ok(result)
120     }
121
122     /// Returns a String representation of `self` for test purposes
123     fn display_test<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self>
124     where
125         Self: Sized,
126     {
127         HirDisplayWrapper {
128             db,
129             t: self,
130             max_size: None,
131             omit_verbose_types: false,
132             display_target: DisplayTarget::Test,
133         }
134     }
135 }
136
137 impl<'a> HirFormatter<'a> {
138     pub fn write_joined<T: HirDisplay>(
139         &mut self,
140         iter: impl IntoIterator<Item = T>,
141         sep: &str,
142     ) -> Result<(), HirDisplayError> {
143         let mut first = true;
144         for e in iter {
145             if !first {
146                 write!(self, "{}", sep)?;
147             }
148             first = false;
149             e.hir_fmt(self)?;
150         }
151         Ok(())
152     }
153
154     /// This allows using the `write!` macro directly with a `HirFormatter`.
155     pub fn write_fmt(&mut self, args: fmt::Arguments) -> Result<(), HirDisplayError> {
156         // We write to a buffer first to track output size
157         self.buf.clear();
158         fmt::write(&mut self.buf, args)?;
159         self.curr_size += self.buf.len();
160
161         // Then we write to the internal formatter from the buffer
162         self.fmt.write_str(&self.buf).map_err(HirDisplayError::from)
163     }
164
165     pub fn should_truncate(&self) -> bool {
166         if let Some(max_size) = self.max_size {
167             self.curr_size >= max_size
168         } else {
169             false
170         }
171     }
172
173     pub fn omit_verbose_types(&self) -> bool {
174         self.omit_verbose_types
175     }
176 }
177
178 #[derive(Clone, Copy)]
179 pub enum DisplayTarget {
180     /// Display types for inlays, doc popups, autocompletion, etc...
181     /// Showing `{unknown}` or not qualifying paths is fine here.
182     /// There's no reason for this to fail.
183     Diagnostics,
184     /// Display types for inserting them in source files.
185     /// The generated code should compile, so paths need to be qualified.
186     SourceCode { module_id: ModuleId },
187     /// Only for test purpose to keep real types
188     Test,
189 }
190
191 impl DisplayTarget {
192     fn is_source_code(&self) -> bool {
193         matches!(self, Self::SourceCode { .. })
194     }
195     fn is_test(&self) -> bool {
196         matches!(self, Self::Test)
197     }
198 }
199
200 #[derive(Debug)]
201 pub enum DisplaySourceCodeError {
202     PathNotFound,
203     UnknownType,
204     Closure,
205 }
206
207 pub enum HirDisplayError {
208     /// Errors that can occur when generating source code
209     DisplaySourceCodeError(DisplaySourceCodeError),
210     /// `FmtError` is required to be compatible with std::fmt::Display
211     FmtError,
212 }
213 impl From<fmt::Error> for HirDisplayError {
214     fn from(_: fmt::Error) -> Self {
215         Self::FmtError
216     }
217 }
218
219 pub struct HirDisplayWrapper<'a, T> {
220     db: &'a dyn HirDatabase,
221     t: &'a T,
222     max_size: Option<usize>,
223     omit_verbose_types: bool,
224     display_target: DisplayTarget,
225 }
226
227 impl<'a, T> fmt::Display for HirDisplayWrapper<'a, T>
228 where
229     T: HirDisplay,
230 {
231     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
232         match self.t.hir_fmt(&mut HirFormatter {
233             db: self.db,
234             fmt: f,
235             buf: String::with_capacity(20),
236             curr_size: 0,
237             max_size: self.max_size,
238             omit_verbose_types: self.omit_verbose_types,
239             display_target: self.display_target,
240         }) {
241             Ok(()) => Ok(()),
242             Err(HirDisplayError::FmtError) => Err(fmt::Error),
243             Err(HirDisplayError::DisplaySourceCodeError(_)) => {
244                 // This should never happen
245                 panic!("HirDisplay::hir_fmt failed with DisplaySourceCodeError when calling Display::fmt!")
246             }
247         }
248     }
249 }
250
251 const TYPE_HINT_TRUNCATION: &str = "…";
252
253 impl<T: HirDisplay> HirDisplay for &'_ T {
254     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
255         HirDisplay::hir_fmt(*self, f)
256     }
257 }
258
259 impl HirDisplay for ProjectionTy {
260     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
261         if f.should_truncate() {
262             return write!(f, "{}", TYPE_HINT_TRUNCATION);
263         }
264
265         let trait_ = f.db.trait_data(self.trait_(f.db));
266         write!(f, "<")?;
267         self.self_type_parameter(&Interner).hir_fmt(f)?;
268         write!(f, " as {}", trait_.name)?;
269         if self.substitution.len(&Interner) > 1 {
270             write!(f, "<")?;
271             f.write_joined(&self.substitution.as_slice(&Interner)[1..], ", ")?;
272             write!(f, ">")?;
273         }
274         write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
275         Ok(())
276     }
277 }
278
279 impl HirDisplay for OpaqueTy {
280     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
281         if f.should_truncate() {
282             return write!(f, "{}", TYPE_HINT_TRUNCATION);
283         }
284
285         self.substitution.at(&Interner, 0).hir_fmt(f)
286     }
287 }
288
289 impl HirDisplay for GenericArg {
290     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
291         match self.interned() {
292             crate::GenericArgData::Ty(ty) => ty.hir_fmt(f),
293             crate::GenericArgData::Lifetime(lt) => lt.hir_fmt(f),
294             crate::GenericArgData::Const(c) => c.hir_fmt(f),
295         }
296     }
297 }
298
299 impl HirDisplay for Const {
300     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
301         let data = self.interned();
302         match data.value {
303             ConstValue::BoundVar(idx) => idx.hir_fmt(f),
304             ConstValue::InferenceVar(..) => write!(f, "_"),
305             ConstValue::Placeholder(idx) => {
306                 let id = const_from_placeholder_idx(f.db, idx);
307                 let generics = generics(f.db.upcast(), id.parent);
308                 let param_data = &generics.params.consts[id.local_id];
309                 write!(f, "{}", param_data.name)
310             }
311             ConstValue::Concrete(c) => write!(f, "{}", c.interned),
312         }
313     }
314 }
315
316 impl HirDisplay for BoundVar {
317     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
318         write!(f, "?{}.{}", self.debruijn.depth(), self.index)
319     }
320 }
321
322 impl HirDisplay for Ty {
323     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
324         if f.should_truncate() {
325             return write!(f, "{}", TYPE_HINT_TRUNCATION);
326         }
327
328         match self.kind(&Interner) {
329             TyKind::Never => write!(f, "!")?,
330             TyKind::Str => write!(f, "str")?,
331             TyKind::Scalar(Scalar::Bool) => write!(f, "bool")?,
332             TyKind::Scalar(Scalar::Char) => write!(f, "char")?,
333             &TyKind::Scalar(Scalar::Float(t)) => write!(f, "{}", primitive::float_ty_to_string(t))?,
334             &TyKind::Scalar(Scalar::Int(t)) => write!(f, "{}", primitive::int_ty_to_string(t))?,
335             &TyKind::Scalar(Scalar::Uint(t)) => write!(f, "{}", primitive::uint_ty_to_string(t))?,
336             TyKind::Slice(t) => {
337                 write!(f, "[")?;
338                 t.hir_fmt(f)?;
339                 write!(f, "]")?;
340             }
341             TyKind::Array(t, c) => {
342                 write!(f, "[")?;
343                 t.hir_fmt(f)?;
344                 write!(f, "; ")?;
345                 c.hir_fmt(f)?;
346                 write!(f, "]")?;
347             }
348             TyKind::Raw(m, t) | TyKind::Ref(m, _, t) => {
349                 if matches!(self.kind(&Interner), TyKind::Raw(..)) {
350                     write!(
351                         f,
352                         "*{}",
353                         match m {
354                             Mutability::Not => "const ",
355                             Mutability::Mut => "mut ",
356                         }
357                     )?;
358                 } else {
359                     write!(
360                         f,
361                         "&{}",
362                         match m {
363                             Mutability::Not => "",
364                             Mutability::Mut => "mut ",
365                         }
366                     )?;
367                 }
368
369                 // FIXME: all this just to decide whether to use parentheses...
370                 let datas;
371                 let predicates: Vec<_> = match t.kind(&Interner) {
372                     TyKind::Dyn(dyn_ty) if dyn_ty.bounds.skip_binders().interned().len() > 1 => {
373                         dyn_ty.bounds.skip_binders().interned().iter().cloned().collect()
374                     }
375                     &TyKind::Alias(AliasTy::Opaque(OpaqueTy {
376                         opaque_ty_id,
377                         substitution: ref parameters,
378                     })) => {
379                         let impl_trait_id = f.db.lookup_intern_impl_trait_id(opaque_ty_id.into());
380                         if let ImplTraitId::ReturnTypeImplTrait(func, idx) = impl_trait_id {
381                             datas =
382                                 f.db.return_type_impl_traits(func)
383                                     .expect("impl trait id without data");
384                             let data = (*datas)
385                                 .as_ref()
386                                 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
387                             let bounds = data.substitute(&Interner, parameters);
388                             bounds.into_value_and_skipped_binders().0
389                         } else {
390                             Vec::new()
391                         }
392                     }
393                     _ => Vec::new(),
394                 };
395
396                 if let Some(WhereClause::Implemented(trait_ref)) =
397                     predicates.get(0).map(|b| b.skip_binders())
398                 {
399                     let trait_ = trait_ref.hir_trait_id();
400                     if fn_traits(f.db.upcast(), trait_).any(|it| it == trait_)
401                         && predicates.len() <= 2
402                     {
403                         return t.hir_fmt(f);
404                     }
405                 }
406
407                 if predicates.len() > 1 {
408                     write!(f, "(")?;
409                     t.hir_fmt(f)?;
410                     write!(f, ")")?;
411                 } else {
412                     t.hir_fmt(f)?;
413                 }
414             }
415             TyKind::Tuple(_, substs) => {
416                 if substs.len(&Interner) == 1 {
417                     write!(f, "(")?;
418                     substs.at(&Interner, 0).hir_fmt(f)?;
419                     write!(f, ",)")?;
420                 } else {
421                     write!(f, "(")?;
422                     f.write_joined(&*substs.as_slice(&Interner), ", ")?;
423                     write!(f, ")")?;
424                 }
425             }
426             TyKind::Function(fn_ptr) => {
427                 let sig = CallableSig::from_fn_ptr(fn_ptr);
428                 sig.hir_fmt(f)?;
429             }
430             TyKind::FnDef(def, parameters) => {
431                 let def = from_chalk(f.db, *def);
432                 let sig = f.db.callable_item_signature(def).substitute(&Interner, parameters);
433                 match def {
434                     CallableDefId::FunctionId(ff) => {
435                         write!(f, "fn {}", f.db.function_data(ff).name)?
436                     }
437                     CallableDefId::StructId(s) => write!(f, "{}", f.db.struct_data(s).name)?,
438                     CallableDefId::EnumVariantId(e) => {
439                         write!(f, "{}", f.db.enum_data(e.parent).variants[e.local_id].name)?
440                     }
441                 };
442                 if parameters.len(&Interner) > 0 {
443                     let generics = generics(f.db.upcast(), def.into());
444                     let (parent_params, self_param, type_params, _impl_trait_params) =
445                         generics.provenance_split();
446                     let total_len = parent_params + self_param + type_params;
447                     // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
448                     if total_len > 0 {
449                         write!(f, "<")?;
450                         f.write_joined(&parameters.as_slice(&Interner)[..total_len], ", ")?;
451                         write!(f, ">")?;
452                     }
453                 }
454                 write!(f, "(")?;
455                 f.write_joined(sig.params(), ", ")?;
456                 write!(f, ")")?;
457                 let ret = sig.ret();
458                 if !ret.is_unit() {
459                     write!(f, " -> ")?;
460                     ret.hir_fmt(f)?;
461                 }
462             }
463             TyKind::Adt(AdtId(def_id), parameters) => {
464                 match f.display_target {
465                     DisplayTarget::Diagnostics | DisplayTarget::Test => {
466                         let name = match *def_id {
467                             hir_def::AdtId::StructId(it) => f.db.struct_data(it).name.clone(),
468                             hir_def::AdtId::UnionId(it) => f.db.union_data(it).name.clone(),
469                             hir_def::AdtId::EnumId(it) => f.db.enum_data(it).name.clone(),
470                         };
471                         write!(f, "{}", name)?;
472                     }
473                     DisplayTarget::SourceCode { module_id } => {
474                         if let Some(path) = find_path::find_path(
475                             f.db.upcast(),
476                             ItemInNs::Types((*def_id).into()),
477                             module_id,
478                         ) {
479                             write!(f, "{}", path)?;
480                         } else {
481                             return Err(HirDisplayError::DisplaySourceCodeError(
482                                 DisplaySourceCodeError::PathNotFound,
483                             ));
484                         }
485                     }
486                 }
487
488                 if parameters.len(&Interner) > 0 {
489                     let parameters_to_write = if f.display_target.is_source_code()
490                         || f.omit_verbose_types()
491                     {
492                         match self
493                             .as_generic_def(f.db)
494                             .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
495                             .filter(|defaults| !defaults.is_empty())
496                         {
497                             None => parameters.as_slice(&Interner),
498                             Some(default_parameters) => {
499                                 let mut default_from = 0;
500                                 for (i, parameter) in parameters.iter(&Interner).enumerate() {
501                                     match (
502                                         parameter.assert_ty_ref(&Interner).kind(&Interner),
503                                         default_parameters.get(i),
504                                     ) {
505                                         (&TyKind::Error, _) | (_, None) => {
506                                             default_from = i + 1;
507                                         }
508                                         (_, Some(default_parameter)) => {
509                                             let actual_default =
510                                                 default_parameter.clone().substitute(
511                                                     &Interner,
512                                                     &subst_prefix(parameters, i),
513                                                 );
514                                             if parameter.assert_ty_ref(&Interner) != &actual_default
515                                             {
516                                                 default_from = i + 1;
517                                             }
518                                         }
519                                     }
520                                 }
521                                 &parameters.as_slice(&Interner)[0..default_from]
522                             }
523                         }
524                     } else {
525                         parameters.as_slice(&Interner)
526                     };
527                     if !parameters_to_write.is_empty() {
528                         write!(f, "<")?;
529                         f.write_joined(parameters_to_write, ", ")?;
530                         write!(f, ">")?;
531                     }
532                 }
533             }
534             TyKind::AssociatedType(assoc_type_id, parameters) => {
535                 let type_alias = from_assoc_type_id(*assoc_type_id);
536                 let trait_ = match type_alias.lookup(f.db.upcast()).container {
537                     AssocContainerId::TraitId(it) => it,
538                     _ => panic!("not an associated type"),
539                 };
540                 let trait_ = f.db.trait_data(trait_);
541                 let type_alias_data = f.db.type_alias_data(type_alias);
542
543                 // Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
544                 if f.display_target.is_test() {
545                     write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
546                     if parameters.len(&Interner) > 0 {
547                         write!(f, "<")?;
548                         f.write_joined(&*parameters.as_slice(&Interner), ", ")?;
549                         write!(f, ">")?;
550                     }
551                 } else {
552                     let projection_ty = ProjectionTy {
553                         associated_ty_id: to_assoc_type_id(type_alias),
554                         substitution: parameters.clone(),
555                     };
556
557                     projection_ty.hir_fmt(f)?;
558                 }
559             }
560             TyKind::Foreign(type_alias) => {
561                 let type_alias = f.db.type_alias_data(from_foreign_def_id(*type_alias));
562                 write!(f, "{}", type_alias.name)?;
563             }
564             TyKind::OpaqueType(opaque_ty_id, parameters) => {
565                 let impl_trait_id = f.db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
566                 match impl_trait_id {
567                     ImplTraitId::ReturnTypeImplTrait(func, idx) => {
568                         let datas =
569                             f.db.return_type_impl_traits(func).expect("impl trait id without data");
570                         let data = (*datas)
571                             .as_ref()
572                             .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
573                         let bounds = data.substitute(&Interner, &parameters);
574                         write_bounds_like_dyn_trait_with_prefix("impl", bounds.skip_binders(), f)?;
575                         // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
576                     }
577                     ImplTraitId::AsyncBlockTypeImplTrait(..) => {
578                         write!(f, "impl Future<Output = ")?;
579                         parameters.at(&Interner, 0).hir_fmt(f)?;
580                         write!(f, ">")?;
581                     }
582                 }
583             }
584             TyKind::Closure(.., substs) => {
585                 if f.display_target.is_source_code() {
586                     return Err(HirDisplayError::DisplaySourceCodeError(
587                         DisplaySourceCodeError::Closure,
588                     ));
589                 }
590                 let sig = substs.at(&Interner, 0).assert_ty_ref(&Interner).callable_sig(f.db);
591                 if let Some(sig) = sig {
592                     if sig.params().is_empty() {
593                         write!(f, "||")?;
594                     } else if f.omit_verbose_types() {
595                         write!(f, "|{}|", TYPE_HINT_TRUNCATION)?;
596                     } else {
597                         write!(f, "|")?;
598                         f.write_joined(sig.params(), ", ")?;
599                         write!(f, "|")?;
600                     };
601
602                     write!(f, " -> ")?;
603                     sig.ret().hir_fmt(f)?;
604                 } else {
605                     write!(f, "{{closure}}")?;
606                 }
607             }
608             TyKind::Placeholder(idx) => {
609                 let id = from_placeholder_idx(f.db, *idx);
610                 let generics = generics(f.db.upcast(), id.parent);
611                 let param_data = &generics.params.types[id.local_id];
612                 match param_data.provenance {
613                     TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
614                         write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))?
615                     }
616                     TypeParamProvenance::ArgumentImplTrait => {
617                         let substs = generics.type_params_subst(f.db);
618                         let bounds =
619                             f.db.generic_predicates(id.parent)
620                                 .into_iter()
621                                 .map(|pred| pred.clone().substitute(&Interner, &substs))
622                                 .filter(|wc| match &wc.skip_binders() {
623                                     WhereClause::Implemented(tr) => {
624                                         &tr.self_type_parameter(&Interner) == self
625                                     }
626                                     WhereClause::AliasEq(AliasEq {
627                                         alias: AliasTy::Projection(proj),
628                                         ty: _,
629                                     }) => &proj.self_type_parameter(&Interner) == self,
630                                     _ => false,
631                                 })
632                                 .collect::<Vec<_>>();
633                         write_bounds_like_dyn_trait_with_prefix("impl", &bounds, f)?;
634                     }
635                 }
636             }
637             TyKind::BoundVar(idx) => idx.hir_fmt(f)?,
638             TyKind::Dyn(dyn_ty) => {
639                 write_bounds_like_dyn_trait_with_prefix(
640                     "dyn",
641                     dyn_ty.bounds.skip_binders().interned(),
642                     f,
643                 )?;
644             }
645             TyKind::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?,
646             TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
647                 let impl_trait_id = f.db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into());
648                 match impl_trait_id {
649                     ImplTraitId::ReturnTypeImplTrait(func, idx) => {
650                         let datas =
651                             f.db.return_type_impl_traits(func).expect("impl trait id without data");
652                         let data = (*datas)
653                             .as_ref()
654                             .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
655                         let bounds = data.substitute(&Interner, &opaque_ty.substitution);
656                         write_bounds_like_dyn_trait_with_prefix("impl", bounds.skip_binders(), f)?;
657                     }
658                     ImplTraitId::AsyncBlockTypeImplTrait(..) => {
659                         write!(f, "{{async block}}")?;
660                     }
661                 };
662             }
663             TyKind::Error => {
664                 if f.display_target.is_source_code() {
665                     return Err(HirDisplayError::DisplaySourceCodeError(
666                         DisplaySourceCodeError::UnknownType,
667                     ));
668                 }
669                 write!(f, "{{unknown}}")?;
670             }
671             TyKind::InferenceVar(..) => write!(f, "_")?,
672             TyKind::Generator(..) => write!(f, "{{generator}}")?,
673             TyKind::GeneratorWitness(..) => write!(f, "{{generator witness}}")?,
674         }
675         Ok(())
676     }
677 }
678
679 impl HirDisplay for CallableSig {
680     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
681         write!(f, "fn(")?;
682         f.write_joined(self.params(), ", ")?;
683         if self.is_varargs {
684             if self.params().is_empty() {
685                 write!(f, "...")?;
686             } else {
687                 write!(f, ", ...")?;
688             }
689         }
690         write!(f, ")")?;
691         let ret = self.ret();
692         if !ret.is_unit() {
693             write!(f, " -> ")?;
694             ret.hir_fmt(f)?;
695         }
696         Ok(())
697     }
698 }
699
700 fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> {
701     let krate = trait_.lookup(db).container.krate();
702     let fn_traits = [
703         db.lang_item(krate, "fn".into()),
704         db.lang_item(krate, "fn_mut".into()),
705         db.lang_item(krate, "fn_once".into()),
706     ];
707     array::IntoIter::new(fn_traits).into_iter().flatten().flat_map(|it| it.as_trait())
708 }
709
710 pub fn write_bounds_like_dyn_trait_with_prefix(
711     prefix: &str,
712     predicates: &[QuantifiedWhereClause],
713     f: &mut HirFormatter,
714 ) -> Result<(), HirDisplayError> {
715     write!(f, "{}", prefix)?;
716     if !predicates.is_empty() {
717         write!(f, " ")?;
718         write_bounds_like_dyn_trait(predicates, f)
719     } else {
720         Ok(())
721     }
722 }
723
724 fn write_bounds_like_dyn_trait(
725     predicates: &[QuantifiedWhereClause],
726     f: &mut HirFormatter,
727 ) -> Result<(), HirDisplayError> {
728     // Note: This code is written to produce nice results (i.e.
729     // corresponding to surface Rust) for types that can occur in
730     // actual Rust. It will have weird results if the predicates
731     // aren't as expected (i.e. self types = $0, projection
732     // predicates for a certain trait come after the Implemented
733     // predicate for that trait).
734     let mut first = true;
735     let mut angle_open = false;
736     let mut is_fn_trait = false;
737     for p in predicates.iter() {
738         match p.skip_binders() {
739             WhereClause::Implemented(trait_ref) => {
740                 let trait_ = trait_ref.hir_trait_id();
741                 if !is_fn_trait {
742                     is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == trait_);
743                 }
744                 if !is_fn_trait && angle_open {
745                     write!(f, ">")?;
746                     angle_open = false;
747                 }
748                 if !first {
749                     write!(f, " + ")?;
750                 }
751                 // We assume that the self type is ^0.0 (i.e. the
752                 // existential) here, which is the only thing that's
753                 // possible in actual Rust, and hence don't print it
754                 write!(f, "{}", f.db.trait_data(trait_).name)?;
755                 if let [_, params @ ..] = &*trait_ref.substitution.as_slice(&Interner) {
756                     if is_fn_trait {
757                         if let Some(args) =
758                             params.first().and_then(|it| it.assert_ty_ref(&Interner).as_tuple())
759                         {
760                             write!(f, "(")?;
761                             f.write_joined(args.as_slice(&Interner), ", ")?;
762                             write!(f, ")")?;
763                         }
764                     } else if !params.is_empty() {
765                         write!(f, "<")?;
766                         f.write_joined(params, ", ")?;
767                         // there might be assoc type bindings, so we leave the angle brackets open
768                         angle_open = true;
769                     }
770                 }
771             }
772             WhereClause::AliasEq(alias_eq) if is_fn_trait => {
773                 is_fn_trait = false;
774                 write!(f, " -> ")?;
775                 alias_eq.ty.hir_fmt(f)?;
776             }
777             WhereClause::AliasEq(AliasEq { ty, alias }) => {
778                 // in types in actual Rust, these will always come
779                 // after the corresponding Implemented predicate
780                 if angle_open {
781                     write!(f, ", ")?;
782                 } else {
783                     write!(f, "<")?;
784                     angle_open = true;
785                 }
786                 if let AliasTy::Projection(proj) = alias {
787                     let type_alias =
788                         f.db.type_alias_data(from_assoc_type_id(proj.associated_ty_id));
789                     write!(f, "{} = ", type_alias.name)?;
790                 }
791                 ty.hir_fmt(f)?;
792             }
793
794             // FIXME implement these
795             WhereClause::LifetimeOutlives(_) => {}
796             WhereClause::TypeOutlives(_) => {}
797         }
798         first = false;
799     }
800     if angle_open {
801         write!(f, ">")?;
802     }
803     Ok(())
804 }
805
806 fn fmt_trait_ref(tr: &TraitRef, f: &mut HirFormatter, use_as: bool) -> Result<(), HirDisplayError> {
807     if f.should_truncate() {
808         return write!(f, "{}", TYPE_HINT_TRUNCATION);
809     }
810
811     tr.self_type_parameter(&Interner).hir_fmt(f)?;
812     if use_as {
813         write!(f, " as ")?;
814     } else {
815         write!(f, ": ")?;
816     }
817     write!(f, "{}", f.db.trait_data(tr.hir_trait_id()).name)?;
818     if tr.substitution.len(&Interner) > 1 {
819         write!(f, "<")?;
820         f.write_joined(&tr.substitution.as_slice(&Interner)[1..], ", ")?;
821         write!(f, ">")?;
822     }
823     Ok(())
824 }
825
826 impl HirDisplay for TraitRef {
827     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
828         fmt_trait_ref(self, f, false)
829     }
830 }
831
832 impl HirDisplay for WhereClause {
833     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
834         if f.should_truncate() {
835             return write!(f, "{}", TYPE_HINT_TRUNCATION);
836         }
837
838         match self {
839             WhereClause::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
840             WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
841                 write!(f, "<")?;
842                 fmt_trait_ref(&projection_ty.trait_ref(f.db), f, true)?;
843                 write!(
844                     f,
845                     ">::{} = ",
846                     f.db.type_alias_data(from_assoc_type_id(projection_ty.associated_ty_id)).name,
847                 )?;
848                 ty.hir_fmt(f)?;
849             }
850             WhereClause::AliasEq(_) => write!(f, "{{error}}")?,
851
852             // FIXME implement these
853             WhereClause::TypeOutlives(..) => {}
854             WhereClause::LifetimeOutlives(..) => {}
855         }
856         Ok(())
857     }
858 }
859
860 impl HirDisplay for LifetimeOutlives {
861     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
862         self.a.hir_fmt(f)?;
863         write!(f, ": ")?;
864         self.b.hir_fmt(f)
865     }
866 }
867
868 impl HirDisplay for Lifetime {
869     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
870         self.interned().hir_fmt(f)
871     }
872 }
873
874 impl HirDisplay for LifetimeData {
875     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
876         match self {
877             LifetimeData::BoundVar(idx) => idx.hir_fmt(f),
878             LifetimeData::InferenceVar(_) => write!(f, "_"),
879             LifetimeData::Placeholder(idx) => {
880                 let id = lt_from_placeholder_idx(f.db, *idx);
881                 let generics = generics(f.db.upcast(), id.parent);
882                 let param_data = &generics.params.lifetimes[id.local_id];
883                 write!(f, "{}", param_data.name)
884             }
885             LifetimeData::Static => write!(f, "'static"),
886             LifetimeData::Empty(_) => Ok(()),
887             LifetimeData::Erased => Ok(()),
888             LifetimeData::Phantom(_, _) => Ok(()),
889         }
890     }
891 }
892
893 impl HirDisplay for DomainGoal {
894     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
895         match self {
896             DomainGoal::Holds(wc) => {
897                 write!(f, "Holds(")?;
898                 wc.hir_fmt(f)?;
899                 write!(f, ")")?;
900             }
901             _ => write!(f, "?")?,
902         }
903         Ok(())
904     }
905 }
906
907 pub fn write_visibility(
908     module_id: ModuleId,
909     vis: Visibility,
910     f: &mut HirFormatter,
911 ) -> Result<(), HirDisplayError> {
912     match vis {
913         Visibility::Public => write!(f, "pub "),
914         Visibility::Module(vis_id) => {
915             let def_map = module_id.def_map(f.db.upcast());
916             let root_module_id = def_map.module_id(def_map.root());
917             if vis_id == module_id {
918                 // pub(self) or omitted
919                 Ok(())
920             } else if root_module_id == vis_id {
921                 write!(f, "pub(crate) ")
922             } else if module_id.containing_module(f.db.upcast()) == Some(vis_id) {
923                 write!(f, "pub(super) ")
924             } else {
925                 write!(f, "pub(in ...) ")
926             }
927         }
928     }
929 }
930
931 impl HirDisplay for TypeRef {
932     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
933         match self {
934             TypeRef::Never => write!(f, "!")?,
935             TypeRef::Placeholder => write!(f, "_")?,
936             TypeRef::Tuple(elems) => {
937                 write!(f, "(")?;
938                 f.write_joined(elems, ", ")?;
939                 if elems.len() == 1 {
940                     write!(f, ",")?;
941                 }
942                 write!(f, ")")?;
943             }
944             TypeRef::Path(path) => path.hir_fmt(f)?,
945             TypeRef::RawPtr(inner, mutability) => {
946                 let mutability = match mutability {
947                     hir_def::type_ref::Mutability::Shared => "*const ",
948                     hir_def::type_ref::Mutability::Mut => "*mut ",
949                 };
950                 write!(f, "{}", mutability)?;
951                 inner.hir_fmt(f)?;
952             }
953             TypeRef::Reference(inner, lifetime, mutability) => {
954                 let mutability = match mutability {
955                     hir_def::type_ref::Mutability::Shared => "",
956                     hir_def::type_ref::Mutability::Mut => "mut ",
957                 };
958                 write!(f, "&")?;
959                 if let Some(lifetime) = lifetime {
960                     write!(f, "{} ", lifetime.name)?;
961                 }
962                 write!(f, "{}", mutability)?;
963                 inner.hir_fmt(f)?;
964             }
965             TypeRef::Array(inner, len) => {
966                 write!(f, "[")?;
967                 inner.hir_fmt(f)?;
968                 write!(f, "; {}]", len)?;
969             }
970             TypeRef::Slice(inner) => {
971                 write!(f, "[")?;
972                 inner.hir_fmt(f)?;
973                 write!(f, "]")?;
974             }
975             TypeRef::Fn(tys, is_varargs) => {
976                 // FIXME: Function pointer qualifiers.
977                 write!(f, "fn(")?;
978                 f.write_joined(&tys[..tys.len() - 1], ", ")?;
979                 if *is_varargs {
980                     write!(f, "{}...", if tys.len() == 1 { "" } else { ", " })?;
981                 }
982                 write!(f, ")")?;
983                 let ret_ty = tys.last().unwrap();
984                 match ret_ty {
985                     TypeRef::Tuple(tup) if tup.is_empty() => {}
986                     _ => {
987                         write!(f, " -> ")?;
988                         ret_ty.hir_fmt(f)?;
989                     }
990                 }
991             }
992             TypeRef::ImplTrait(bounds) => {
993                 write!(f, "impl ")?;
994                 f.write_joined(bounds, " + ")?;
995             }
996             TypeRef::DynTrait(bounds) => {
997                 write!(f, "dyn ")?;
998                 f.write_joined(bounds, " + ")?;
999             }
1000             TypeRef::Macro(macro_call) => {
1001                 let macro_call = macro_call.to_node(f.db.upcast());
1002                 let ctx = body::LowerCtx::with_hygiene(f.db.upcast(), &Hygiene::new_unhygienic());
1003                 match macro_call.path() {
1004                     Some(path) => match Path::from_src(path, &ctx) {
1005                         Some(path) => path.hir_fmt(f)?,
1006                         None => write!(f, "{{macro}}")?,
1007                     },
1008                     None => write!(f, "{{macro}}")?,
1009                 }
1010                 write!(f, "!(..)")?;
1011             }
1012             TypeRef::Error => write!(f, "{{error}}")?,
1013         }
1014         Ok(())
1015     }
1016 }
1017
1018 impl HirDisplay for TypeBound {
1019     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
1020         match self {
1021             TypeBound::Path(path) => path.hir_fmt(f),
1022             TypeBound::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
1023             TypeBound::Error => write!(f, "{{error}}"),
1024         }
1025     }
1026 }
1027
1028 impl HirDisplay for Path {
1029     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
1030         match (self.type_anchor(), self.kind()) {
1031             (Some(anchor), _) => {
1032                 write!(f, "<")?;
1033                 anchor.hir_fmt(f)?;
1034                 write!(f, ">")?;
1035             }
1036             (_, PathKind::Plain) => {}
1037             (_, PathKind::Abs) => write!(f, "::")?,
1038             (_, PathKind::Crate) => write!(f, "crate")?,
1039             (_, PathKind::Super(0)) => write!(f, "self")?,
1040             (_, PathKind::Super(n)) => {
1041                 write!(f, "super")?;
1042                 for _ in 0..*n {
1043                     write!(f, "::super")?;
1044                 }
1045             }
1046             (_, PathKind::DollarCrate(_)) => write!(f, "{{extern_crate}}")?,
1047         }
1048
1049         for (seg_idx, segment) in self.segments().iter().enumerate() {
1050             if seg_idx != 0 {
1051                 write!(f, "::")?;
1052             }
1053             write!(f, "{}", segment.name)?;
1054             if let Some(generic_args) = segment.args_and_bindings {
1055                 // We should be in type context, so format as `Foo<Bar>` instead of `Foo::<Bar>`.
1056                 // Do we actually format expressions?
1057                 write!(f, "<")?;
1058                 let mut first = true;
1059                 for arg in &generic_args.args {
1060                     if first {
1061                         first = false;
1062                         if generic_args.has_self_type {
1063                             // FIXME: Convert to `<Ty as Trait>` form.
1064                             write!(f, "Self = ")?;
1065                         }
1066                     } else {
1067                         write!(f, ", ")?;
1068                     }
1069                     arg.hir_fmt(f)?;
1070                 }
1071                 for binding in &generic_args.bindings {
1072                     if first {
1073                         first = false;
1074                     } else {
1075                         write!(f, ", ")?;
1076                     }
1077                     write!(f, "{}", binding.name)?;
1078                     match &binding.type_ref {
1079                         Some(ty) => {
1080                             write!(f, " = ")?;
1081                             ty.hir_fmt(f)?
1082                         }
1083                         None => {
1084                             write!(f, ": ")?;
1085                             f.write_joined(&binding.bounds, " + ")?;
1086                         }
1087                     }
1088                 }
1089                 write!(f, ">")?;
1090             }
1091         }
1092         Ok(())
1093     }
1094 }
1095
1096 impl HirDisplay for hir_def::path::GenericArg {
1097     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
1098         match self {
1099             hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f),
1100             hir_def::path::GenericArg::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
1101         }
1102     }
1103 }