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