1use std::{
6 fmt::{self, Debug},
7 mem,
8};
9
10use base_db::CrateId;
11use chalk_ir::{BoundVar, Safety, TyKind};
12use either::Either;
13use hir_def::{
14 data::adt::VariantData,
15 db::DefDatabase,
16 find_path::{self, PrefixKind},
17 generics::{TypeOrConstParamData, TypeParamProvenance},
18 item_scope::ItemInNs,
19 lang_item::{LangItem, LangItemTarget},
20 nameres::DefMap,
21 path::{Path, PathKind},
22 type_ref::{
23 TraitBoundModifier, TypeBound, TypeRef, TypeRefId, TypesMap, TypesSourceMap, UseArgRef,
24 },
25 visibility::Visibility,
26 GenericDefId, HasModule, ImportPathConfig, ItemContainerId, LocalFieldId, Lookup, ModuleDefId,
27 ModuleId, TraitId,
28};
29use hir_expand::name::Name;
30use intern::{sym, Internable, Interned};
31use itertools::Itertools;
32use la_arena::ArenaMap;
33use rustc_apfloat::{
34 ieee::{Half as f16, Quad as f128},
35 Float,
36};
37use rustc_hash::FxHashSet;
38use smallvec::SmallVec;
39use span::Edition;
40use stdx::never;
41use triomphe::Arc;
42
43use crate::{
44 consteval::try_const_usize,
45 db::{HirDatabase, InternedClosure},
46 from_assoc_type_id, from_foreign_def_id, from_placeholder_idx,
47 generics::generics,
48 layout::Layout,
49 lt_from_placeholder_idx,
50 mapping::from_chalk,
51 mir::pad16,
52 primitive, to_assoc_type_id,
53 utils::{self, detect_variant_from_bytes, ClosureSubst},
54 AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, ConcreteConst, Const,
55 ConstScalar, ConstValue, DomainGoal, FnAbi, GenericArg, ImplTraitId, Interner, Lifetime,
56 LifetimeData, LifetimeOutlives, MemoryMap, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt,
57 QuantifiedWhereClause, Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty,
58 TyExt, WhereClause,
59};
60
61pub trait HirWrite: fmt::Write {
62 fn start_location_link(&mut self, _location: ModuleDefId) {}
63 fn end_location_link(&mut self) {}
64}
65
66impl HirWrite for String {}
68
69impl HirWrite for fmt::Formatter<'_> {}
71
72pub struct HirFormatter<'a> {
73 pub db: &'a dyn HirDatabase,
75 fmt: &'a mut dyn HirWrite,
77 buf: String,
79 curr_size: usize,
81 max_size: Option<usize>,
83 pub entity_limit: Option<usize>,
86 show_container_bounds: bool,
88 omit_verbose_types: bool,
89 closure_style: ClosureStyle,
90 display_target: DisplayTarget,
91 bounds_formatting_ctx: BoundsFormattingCtx,
92}
93
94#[derive(Default)]
95enum BoundsFormattingCtx {
96 Entered {
97 projection_tys_met: FxHashSet<ProjectionTy>,
106 },
107 #[default]
108 Exited,
109}
110
111impl BoundsFormattingCtx {
112 fn contains(&mut self, proj: &ProjectionTy) -> bool {
113 match self {
114 BoundsFormattingCtx::Entered { projection_tys_met } => {
115 projection_tys_met.contains(proj)
116 }
117 BoundsFormattingCtx::Exited => false,
118 }
119 }
120}
121
122impl HirFormatter<'_> {
123 fn start_location_link(&mut self, location: ModuleDefId) {
124 self.fmt.start_location_link(location);
125 }
126
127 fn end_location_link(&mut self) {
128 self.fmt.end_location_link();
129 }
130
131 fn format_bounds_with<T, F: FnOnce(&mut Self) -> T>(
132 &mut self,
133 target: ProjectionTy,
134 format_bounds: F,
135 ) -> T {
136 match self.bounds_formatting_ctx {
137 BoundsFormattingCtx::Entered { ref mut projection_tys_met } => {
138 projection_tys_met.insert(target);
139 format_bounds(self)
140 }
141 BoundsFormattingCtx::Exited => {
142 let mut projection_tys_met = FxHashSet::default();
143 projection_tys_met.insert(target);
144 self.bounds_formatting_ctx = BoundsFormattingCtx::Entered { projection_tys_met };
145 let res = format_bounds(self);
146 self.bounds_formatting_ctx = BoundsFormattingCtx::Exited;
150 res
151 }
152 }
153 }
154}
155
156pub trait HirDisplay {
157 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>;
158
159 fn into_displayable<'a>(
161 &'a self,
162 db: &'a dyn HirDatabase,
163 max_size: Option<usize>,
164 limited_size: Option<usize>,
165 omit_verbose_types: bool,
166 display_target: DisplayTarget,
167 closure_style: ClosureStyle,
168 show_container_bounds: bool,
169 ) -> HirDisplayWrapper<'a, Self>
170 where
171 Self: Sized,
172 {
173 assert!(
174 !matches!(display_target, DisplayTarget::SourceCode { .. }),
175 "HirDisplayWrapper cannot fail with DisplaySourceCodeError, use HirDisplay::hir_fmt directly instead"
176 );
177 HirDisplayWrapper {
178 db,
179 t: self,
180 max_size,
181 limited_size,
182 omit_verbose_types,
183 display_target,
184 closure_style,
185 show_container_bounds,
186 }
187 }
188
189 fn display<'a>(
192 &'a self,
193 db: &'a dyn HirDatabase,
194 edition: Edition,
195 ) -> HirDisplayWrapper<'a, Self>
196 where
197 Self: Sized,
198 {
199 HirDisplayWrapper {
200 db,
201 t: self,
202 max_size: None,
203 limited_size: None,
204 omit_verbose_types: false,
205 closure_style: ClosureStyle::ImplFn,
206 display_target: DisplayTarget::Diagnostics { edition },
207 show_container_bounds: false,
208 }
209 }
210
211 fn display_truncated<'a>(
214 &'a self,
215 db: &'a dyn HirDatabase,
216 max_size: Option<usize>,
217 edition: Edition,
218 ) -> HirDisplayWrapper<'a, Self>
219 where
220 Self: Sized,
221 {
222 HirDisplayWrapper {
223 db,
224 t: self,
225 max_size,
226 limited_size: None,
227 omit_verbose_types: true,
228 closure_style: ClosureStyle::ImplFn,
229 display_target: DisplayTarget::Diagnostics { edition },
230 show_container_bounds: false,
231 }
232 }
233
234 fn display_limited<'a>(
237 &'a self,
238 db: &'a dyn HirDatabase,
239 limited_size: Option<usize>,
240 edition: Edition,
241 ) -> HirDisplayWrapper<'a, Self>
242 where
243 Self: Sized,
244 {
245 HirDisplayWrapper {
246 db,
247 t: self,
248 max_size: None,
249 limited_size,
250 omit_verbose_types: true,
251 closure_style: ClosureStyle::ImplFn,
252 display_target: DisplayTarget::Diagnostics { edition },
253 show_container_bounds: false,
254 }
255 }
256
257 fn display_source_code<'a>(
260 &'a self,
261 db: &'a dyn HirDatabase,
262 module_id: ModuleId,
263 allow_opaque: bool,
264 ) -> Result<String, DisplaySourceCodeError> {
265 let mut result = String::new();
266 match self.hir_fmt(&mut HirFormatter {
267 db,
268 fmt: &mut result,
269 buf: String::with_capacity(20),
270 curr_size: 0,
271 max_size: None,
272 entity_limit: None,
273 omit_verbose_types: false,
274 closure_style: ClosureStyle::ImplFn,
275 display_target: DisplayTarget::SourceCode { module_id, allow_opaque },
276 show_container_bounds: false,
277 bounds_formatting_ctx: Default::default(),
278 }) {
279 Ok(()) => {}
280 Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"),
281 Err(HirDisplayError::DisplaySourceCodeError(e)) => return Err(e),
282 };
283 Ok(result)
284 }
285
286 fn display_test<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self>
288 where
289 Self: Sized,
290 {
291 HirDisplayWrapper {
292 db,
293 t: self,
294 max_size: None,
295 limited_size: None,
296 omit_verbose_types: false,
297 closure_style: ClosureStyle::ImplFn,
298 display_target: DisplayTarget::Test,
299 show_container_bounds: false,
300 }
301 }
302
303 fn display_with_container_bounds<'a>(
306 &'a self,
307 db: &'a dyn HirDatabase,
308 show_container_bounds: bool,
309 edition: Edition,
310 ) -> HirDisplayWrapper<'a, Self>
311 where
312 Self: Sized,
313 {
314 HirDisplayWrapper {
315 db,
316 t: self,
317 max_size: None,
318 limited_size: None,
319 omit_verbose_types: false,
320 closure_style: ClosureStyle::ImplFn,
321 display_target: DisplayTarget::Diagnostics { edition },
322 show_container_bounds,
323 }
324 }
325}
326
327impl HirFormatter<'_> {
328 pub fn edition(&self) -> Edition {
329 match self.display_target {
330 DisplayTarget::Diagnostics { edition } => edition,
331 DisplayTarget::SourceCode { module_id, .. } => {
332 self.db.crate_graph()[module_id.krate()].edition
333 }
334 DisplayTarget::Test => Edition::CURRENT,
335 }
336 }
337
338 pub fn write_joined<T: HirDisplay>(
339 &mut self,
340 iter: impl IntoIterator<Item = T>,
341 sep: &str,
342 ) -> Result<(), HirDisplayError> {
343 let mut first = true;
344 for e in iter {
345 if !first {
346 write!(self, "{sep}")?;
347 }
348 first = false;
349
350 if self.should_truncate() {
352 return write!(self, "{TYPE_HINT_TRUNCATION}");
353 }
354
355 e.hir_fmt(self)?;
356 }
357 Ok(())
358 }
359
360 pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), HirDisplayError> {
362 self.buf.clear();
364 fmt::write(&mut self.buf, args)?;
365 self.curr_size += self.buf.len();
366
367 self.fmt.write_str(&self.buf).map_err(HirDisplayError::from)
369 }
370
371 pub fn write_str(&mut self, s: &str) -> Result<(), HirDisplayError> {
372 self.fmt.write_str(s)?;
373 Ok(())
374 }
375
376 pub fn write_char(&mut self, c: char) -> Result<(), HirDisplayError> {
377 self.fmt.write_char(c)?;
378 Ok(())
379 }
380
381 pub fn should_truncate(&self) -> bool {
382 match self.max_size {
383 Some(max_size) => self.curr_size >= max_size,
384 None => false,
385 }
386 }
387
388 pub fn omit_verbose_types(&self) -> bool {
389 self.omit_verbose_types
390 }
391
392 pub fn show_container_bounds(&self) -> bool {
393 self.show_container_bounds
394 }
395}
396
397#[derive(Clone, Copy)]
398pub enum DisplayTarget {
399 Diagnostics { edition: Edition },
403 SourceCode { module_id: ModuleId, allow_opaque: bool },
406 Test,
408}
409
410impl DisplayTarget {
411 fn is_source_code(self) -> bool {
412 matches!(self, Self::SourceCode { .. })
413 }
414
415 fn is_test(self) -> bool {
416 matches!(self, Self::Test)
417 }
418
419 fn allows_opaque(self) -> bool {
420 match self {
421 Self::SourceCode { allow_opaque, .. } => allow_opaque,
422 _ => true,
423 }
424 }
425}
426
427#[derive(Debug)]
428pub enum DisplaySourceCodeError {
429 PathNotFound,
430 Coroutine,
431 OpaqueType,
432}
433
434pub enum HirDisplayError {
435 DisplaySourceCodeError(DisplaySourceCodeError),
437 FmtError,
439}
440impl From<fmt::Error> for HirDisplayError {
441 fn from(_: fmt::Error) -> Self {
442 Self::FmtError
443 }
444}
445
446pub struct HirDisplayWrapper<'a, T> {
447 db: &'a dyn HirDatabase,
448 t: &'a T,
449 max_size: Option<usize>,
450 limited_size: Option<usize>,
451 omit_verbose_types: bool,
452 closure_style: ClosureStyle,
453 display_target: DisplayTarget,
454 show_container_bounds: bool,
455}
456
457#[derive(Debug, PartialEq, Eq, Clone, Copy)]
458pub enum ClosureStyle {
459 ImplFn,
462 RANotation,
464 ClosureWithId,
466 ClosureWithSubst,
468 Hide,
470}
471
472impl<T: HirDisplay> HirDisplayWrapper<'_, T> {
473 pub fn write_to<F: HirWrite>(&self, f: &mut F) -> Result<(), HirDisplayError> {
474 self.t.hir_fmt(&mut HirFormatter {
475 db: self.db,
476 fmt: f,
477 buf: String::with_capacity(20),
478 curr_size: 0,
479 max_size: self.max_size,
480 entity_limit: self.limited_size,
481 omit_verbose_types: self.omit_verbose_types,
482 display_target: self.display_target,
483 closure_style: self.closure_style,
484 show_container_bounds: self.show_container_bounds,
485 bounds_formatting_ctx: Default::default(),
486 })
487 }
488
489 pub fn with_closure_style(mut self, c: ClosureStyle) -> Self {
490 self.closure_style = c;
491 self
492 }
493}
494
495impl<T> fmt::Display for HirDisplayWrapper<'_, T>
496where
497 T: HirDisplay,
498{
499 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
500 match self.write_to(f) {
501 Ok(()) => Ok(()),
502 Err(HirDisplayError::FmtError) => Err(fmt::Error),
503 Err(HirDisplayError::DisplaySourceCodeError(_)) => {
504 panic!("HirDisplay::hir_fmt failed with DisplaySourceCodeError when calling Display::fmt!")
506 }
507 }
508 }
509}
510
511const TYPE_HINT_TRUNCATION: &str = "…";
512
513impl<T: HirDisplay> HirDisplay for &T {
514 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
515 HirDisplay::hir_fmt(*self, f)
516 }
517}
518
519impl<T: HirDisplay + Internable> HirDisplay for Interned<T> {
520 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
521 HirDisplay::hir_fmt(self.as_ref(), f)
522 }
523}
524
525impl HirDisplay for ProjectionTy {
526 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
527 if f.should_truncate() {
528 return write!(f, "{TYPE_HINT_TRUNCATION}");
529 }
530 let trait_ref = self.trait_ref(f.db);
531 let self_ty = trait_ref.self_type_parameter(Interner);
532
533 if !f.display_target.is_source_code() {
537 if let TyKind::Placeholder(idx) = self_ty.kind(Interner) {
538 if !f.bounds_formatting_ctx.contains(self) {
539 let db = f.db;
540 let id = from_placeholder_idx(db, *idx);
541 let generics = generics(db.upcast(), id.parent);
542
543 let substs = generics.placeholder_subst(db);
544 let bounds = db
545 .generic_predicates(id.parent)
546 .iter()
547 .map(|pred| pred.clone().substitute(Interner, &substs))
548 .filter(|wc| match wc.skip_binders() {
549 WhereClause::Implemented(tr) => {
550 matches!(
551 tr.self_type_parameter(Interner).kind(Interner),
552 TyKind::Alias(_)
553 )
554 }
555 WhereClause::TypeOutlives(t) => {
556 matches!(t.ty.kind(Interner), TyKind::Alias(_))
557 }
558 WhereClause::AliasEq(_) => false,
560 WhereClause::LifetimeOutlives(_) => false,
561 })
562 .collect::<Vec<_>>();
563 if !bounds.is_empty() {
564 return f.format_bounds_with(self.clone(), |f| {
565 write_bounds_like_dyn_trait_with_prefix(
566 f,
567 "impl",
568 Either::Left(
569 &TyKind::Alias(AliasTy::Projection(self.clone()))
570 .intern(Interner),
571 ),
572 &bounds,
573 SizedByDefault::NotSized,
574 )
575 });
576 }
577 }
578 }
579 }
580
581 write!(f, "<")?;
582 self_ty.hir_fmt(f)?;
583 write!(f, " as ")?;
584 trait_ref.hir_fmt(f)?;
585 write!(
586 f,
587 ">::{}",
588 f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id))
589 .name
590 .display(f.db.upcast(), f.edition())
591 )?;
592 let proj_params_count =
593 self.substitution.len(Interner) - trait_ref.substitution.len(Interner);
594 let proj_params = &self.substitution.as_slice(Interner)[..proj_params_count];
595 hir_fmt_generics(f, proj_params, None, None)
596 }
597}
598
599impl HirDisplay for OpaqueTy {
600 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
601 if f.should_truncate() {
602 return write!(f, "{TYPE_HINT_TRUNCATION}");
603 }
604
605 self.substitution.at(Interner, 0).hir_fmt(f)
606 }
607}
608
609impl HirDisplay for GenericArg {
610 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
611 match self.interned() {
612 crate::GenericArgData::Ty(ty) => ty.hir_fmt(f),
613 crate::GenericArgData::Lifetime(lt) => lt.hir_fmt(f),
614 crate::GenericArgData::Const(c) => c.hir_fmt(f),
615 }
616 }
617}
618
619impl HirDisplay for Const {
620 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
621 let data = self.interned();
622 match &data.value {
623 ConstValue::BoundVar(idx) => idx.hir_fmt(f),
624 ConstValue::InferenceVar(..) => write!(f, "#c#"),
625 ConstValue::Placeholder(idx) => {
626 let id = from_placeholder_idx(f.db, *idx);
627 let generics = generics(f.db.upcast(), id.parent);
628 let param_data = &generics[id.local_id];
629 write!(f, "{}", param_data.name().unwrap().display(f.db.upcast(), f.edition()))?;
630 Ok(())
631 }
632 ConstValue::Concrete(c) => match &c.interned {
633 ConstScalar::Bytes(b, m) => render_const_scalar(f, b, m, &data.ty),
634 ConstScalar::UnevaluatedConst(c, parameters) => {
635 write!(f, "{}", c.name(f.db.upcast()))?;
636 hir_fmt_generics(
637 f,
638 parameters.as_slice(Interner),
639 c.generic_def(f.db.upcast()),
640 None,
641 )?;
642 Ok(())
643 }
644 ConstScalar::Unknown => f.write_char('_'),
645 },
646 }
647 }
648}
649
650fn render_const_scalar(
651 f: &mut HirFormatter<'_>,
652 b: &[u8],
653 memory_map: &MemoryMap,
654 ty: &Ty,
655) -> Result<(), HirDisplayError> {
656 let trait_env =
659 TraitEnvironment::empty(*f.db.crate_graph().crates_in_topological_order().last().unwrap());
660 match ty.kind(Interner) {
661 TyKind::Scalar(s) => match s {
662 Scalar::Bool => write!(f, "{}", b[0] != 0),
663 Scalar::Char => {
664 let it = u128::from_le_bytes(pad16(b, false)) as u32;
665 let Ok(c) = char::try_from(it) else {
666 return f.write_str("<unicode-error>");
667 };
668 write!(f, "{c:?}")
669 }
670 Scalar::Int(_) => {
671 let it = i128::from_le_bytes(pad16(b, true));
672 write!(f, "{it}")
673 }
674 Scalar::Uint(_) => {
675 let it = u128::from_le_bytes(pad16(b, false));
676 write!(f, "{it}")
677 }
678 Scalar::Float(fl) => match fl {
679 chalk_ir::FloatTy::F16 => {
680 let it = f16::from_bits(u16::from_le_bytes(b.try_into().unwrap()).into());
682 let s = it.to_string();
683 if s.strip_prefix('-').unwrap_or(&s).chars().all(|c| c.is_ascii_digit()) {
684 write!(f, "{s}.0")
686 } else {
687 write!(f, "{s}")
688 }
689 }
690 chalk_ir::FloatTy::F32 => {
691 let it = f32::from_le_bytes(b.try_into().unwrap());
692 write!(f, "{it:?}")
693 }
694 chalk_ir::FloatTy::F64 => {
695 let it = f64::from_le_bytes(b.try_into().unwrap());
696 write!(f, "{it:?}")
697 }
698 chalk_ir::FloatTy::F128 => {
699 let it = f128::from_bits(u128::from_le_bytes(b.try_into().unwrap()));
701 let s = it.to_string();
702 if s.strip_prefix('-').unwrap_or(&s).chars().all(|c| c.is_ascii_digit()) {
703 write!(f, "{s}.0")
705 } else {
706 write!(f, "{s}")
707 }
708 }
709 },
710 },
711 TyKind::Ref(_, _, t) => match t.kind(Interner) {
712 TyKind::Str => {
713 let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap());
714 let size = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap());
715 let Some(bytes) = memory_map.get(addr, size) else {
716 return f.write_str("<ref-data-not-available>");
717 };
718 let s = std::str::from_utf8(bytes).unwrap_or("<utf8-error>");
719 write!(f, "{s:?}")
720 }
721 TyKind::Slice(ty) => {
722 let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap());
723 let count = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap());
724 let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env) else {
725 return f.write_str("<layout-error>");
726 };
727 let size_one = layout.size.bytes_usize();
728 let Some(bytes) = memory_map.get(addr, size_one * count) else {
729 return f.write_str("<ref-data-not-available>");
730 };
731 f.write_str("&[")?;
732 let mut first = true;
733 for i in 0..count {
734 if first {
735 first = false;
736 } else {
737 f.write_str(", ")?;
738 }
739 let offset = size_one * i;
740 render_const_scalar(f, &bytes[offset..offset + size_one], memory_map, ty)?;
741 }
742 f.write_str("]")
743 }
744 TyKind::Dyn(_) => {
745 let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap());
746 let ty_id = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap());
747 let Ok(t) = memory_map.vtable_ty(ty_id) else {
748 return f.write_str("<ty-missing-in-vtable-map>");
749 };
750 let Ok(layout) = f.db.layout_of_ty(t.clone(), trait_env) else {
751 return f.write_str("<layout-error>");
752 };
753 let size = layout.size.bytes_usize();
754 let Some(bytes) = memory_map.get(addr, size) else {
755 return f.write_str("<ref-data-not-available>");
756 };
757 f.write_str("&")?;
758 render_const_scalar(f, bytes, memory_map, t)
759 }
760 TyKind::Adt(adt, _) if b.len() == 2 * size_of::<usize>() => match adt.0 {
761 hir_def::AdtId::StructId(s) => {
762 let data = f.db.struct_data(s);
763 write!(f, "&{}", data.name.display(f.db.upcast(), f.edition()))?;
764 Ok(())
765 }
766 _ => f.write_str("<unsized-enum-or-union>"),
767 },
768 _ => {
769 let addr = usize::from_le_bytes(match b.try_into() {
770 Ok(b) => b,
771 Err(_) => {
772 never!(
773 "tried rendering ty {:?} in const ref with incorrect byte count {}",
774 t,
775 b.len()
776 );
777 return f.write_str("<layout-error>");
778 }
779 });
780 let Ok(layout) = f.db.layout_of_ty(t.clone(), trait_env) else {
781 return f.write_str("<layout-error>");
782 };
783 let size = layout.size.bytes_usize();
784 let Some(bytes) = memory_map.get(addr, size) else {
785 return f.write_str("<ref-data-not-available>");
786 };
787 f.write_str("&")?;
788 render_const_scalar(f, bytes, memory_map, t)
789 }
790 },
791 TyKind::Tuple(_, subst) => {
792 let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env.clone()) else {
793 return f.write_str("<layout-error>");
794 };
795 f.write_str("(")?;
796 let mut first = true;
797 for (id, ty) in subst.iter(Interner).enumerate() {
798 if first {
799 first = false;
800 } else {
801 f.write_str(", ")?;
802 }
803 let ty = ty.assert_ty_ref(Interner); let offset = layout.fields.offset(id).bytes_usize();
805 let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env.clone()) else {
806 f.write_str("<layout-error>")?;
807 continue;
808 };
809 let size = layout.size.bytes_usize();
810 render_const_scalar(f, &b[offset..offset + size], memory_map, ty)?;
811 }
812 f.write_str(")")
813 }
814 TyKind::Adt(adt, subst) => {
815 let Ok(layout) = f.db.layout_of_adt(adt.0, subst.clone(), trait_env.clone()) else {
816 return f.write_str("<layout-error>");
817 };
818 match adt.0 {
819 hir_def::AdtId::StructId(s) => {
820 let data = f.db.struct_data(s);
821 write!(f, "{}", data.name.display(f.db.upcast(), f.edition()))?;
822 let field_types = f.db.field_types(s.into());
823 render_variant_after_name(
824 &data.variant_data,
825 f,
826 &field_types,
827 f.db.trait_environment(adt.0.into()),
828 &layout,
829 subst,
830 b,
831 memory_map,
832 )
833 }
834 hir_def::AdtId::UnionId(u) => {
835 write!(f, "{}", f.db.union_data(u).name.display(f.db.upcast(), f.edition()))
836 }
837 hir_def::AdtId::EnumId(e) => {
838 let Ok(target_data_layout) = f.db.target_data_layout(trait_env.krate) else {
839 return f.write_str("<target-layout-not-available>");
840 };
841 let Some((var_id, var_layout)) =
842 detect_variant_from_bytes(&layout, f.db, &target_data_layout, b, e)
843 else {
844 return f.write_str("<failed-to-detect-variant>");
845 };
846 let data = f.db.enum_variant_data(var_id);
847 write!(f, "{}", data.name.display(f.db.upcast(), f.edition()))?;
848 let field_types = f.db.field_types(var_id.into());
849 render_variant_after_name(
850 &data.variant_data,
851 f,
852 &field_types,
853 f.db.trait_environment(adt.0.into()),
854 var_layout,
855 subst,
856 b,
857 memory_map,
858 )
859 }
860 }
861 }
862 TyKind::FnDef(..) => ty.hir_fmt(f),
863 TyKind::Function(_) | TyKind::Raw(_, _) => {
864 let it = u128::from_le_bytes(pad16(b, false));
865 write!(f, "{it:#X} as ")?;
866 ty.hir_fmt(f)
867 }
868 TyKind::Array(ty, len) => {
869 let Some(len) = try_const_usize(f.db, len) else {
870 return f.write_str("<unknown-array-len>");
871 };
872 let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env) else {
873 return f.write_str("<layout-error>");
874 };
875 let size_one = layout.size.bytes_usize();
876 f.write_str("[")?;
877 let mut first = true;
878 for i in 0..len as usize {
879 if first {
880 first = false;
881 } else {
882 f.write_str(", ")?;
883 }
884 let offset = size_one * i;
885 render_const_scalar(f, &b[offset..offset + size_one], memory_map, ty)?;
886 }
887 f.write_str("]")
888 }
889 TyKind::Never => f.write_str("!"),
890 TyKind::Closure(_, _) => f.write_str("<closure>"),
891 TyKind::Coroutine(_, _) => f.write_str("<coroutine>"),
892 TyKind::CoroutineWitness(_, _) => f.write_str("<coroutine-witness>"),
893 TyKind::Foreign(_) => f.write_str("<extern-type>"),
895 TyKind::Error
896 | TyKind::Placeholder(_)
897 | TyKind::Alias(_)
898 | TyKind::AssociatedType(_, _)
899 | TyKind::OpaqueType(_, _)
900 | TyKind::BoundVar(_)
901 | TyKind::InferenceVar(_, _) => f.write_str("<placeholder-or-unknown-type>"),
902 TyKind::Slice(_) | TyKind::Str | TyKind::Dyn(_) => f.write_str("<unsized-value>"),
904 }
905}
906
907fn render_variant_after_name(
908 data: &VariantData,
909 f: &mut HirFormatter<'_>,
910 field_types: &ArenaMap<LocalFieldId, Binders<Ty>>,
911 trait_env: Arc<TraitEnvironment>,
912 layout: &Layout,
913 subst: &Substitution,
914 b: &[u8],
915 memory_map: &MemoryMap,
916) -> Result<(), HirDisplayError> {
917 match data {
918 VariantData::Record { fields, .. } | VariantData::Tuple { fields, .. } => {
919 let render_field = |f: &mut HirFormatter<'_>, id: LocalFieldId| {
920 let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize();
921 let ty = field_types[id].clone().substitute(Interner, subst);
922 let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env.clone()) else {
923 return f.write_str("<layout-error>");
924 };
925 let size = layout.size.bytes_usize();
926 render_const_scalar(f, &b[offset..offset + size], memory_map, &ty)
927 };
928 let mut it = fields.iter();
929 if matches!(data, VariantData::Record { .. }) {
930 write!(f, " {{")?;
931 if let Some((id, data)) = it.next() {
932 write!(f, " {}: ", data.name.display(f.db.upcast(), f.edition()))?;
933 render_field(f, id)?;
934 }
935 for (id, data) in it {
936 write!(f, ", {}: ", data.name.display(f.db.upcast(), f.edition()))?;
937 render_field(f, id)?;
938 }
939 write!(f, " }}")?;
940 } else {
941 let mut it = it.map(|it| it.0);
942 write!(f, "(")?;
943 if let Some(id) = it.next() {
944 render_field(f, id)?;
945 }
946 for id in it {
947 write!(f, ", ")?;
948 render_field(f, id)?;
949 }
950 write!(f, ")")?;
951 }
952 Ok(())
953 }
954 VariantData::Unit => Ok(()),
955 }
956}
957
958impl HirDisplay for BoundVar {
959 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
960 write!(f, "?{}.{}", self.debruijn.depth(), self.index)
961 }
962}
963
964impl HirDisplay for Ty {
965 fn hir_fmt(
966 &self,
967 f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_>,
968 ) -> Result<(), HirDisplayError> {
969 if f.should_truncate() {
970 return write!(f, "{TYPE_HINT_TRUNCATION}");
971 }
972
973 match self.kind(Interner) {
974 TyKind::Never => write!(f, "!")?,
975 TyKind::Str => write!(f, "str")?,
976 TyKind::Scalar(Scalar::Bool) => write!(f, "bool")?,
977 TyKind::Scalar(Scalar::Char) => write!(f, "char")?,
978 &TyKind::Scalar(Scalar::Float(t)) => write!(f, "{}", primitive::float_ty_to_string(t))?,
979 &TyKind::Scalar(Scalar::Int(t)) => write!(f, "{}", primitive::int_ty_to_string(t))?,
980 &TyKind::Scalar(Scalar::Uint(t)) => write!(f, "{}", primitive::uint_ty_to_string(t))?,
981 TyKind::Slice(t) => {
982 write!(f, "[")?;
983 t.hir_fmt(f)?;
984 write!(f, "]")?;
985 }
986 TyKind::Array(t, c) => {
987 write!(f, "[")?;
988 t.hir_fmt(f)?;
989 write!(f, "; ")?;
990 c.hir_fmt(f)?;
991 write!(f, "]")?;
992 }
993 kind @ (TyKind::Raw(m, t) | TyKind::Ref(m, _, t)) => {
994 if let TyKind::Ref(_, l, _) = kind {
995 f.write_char('&')?;
996 if cfg!(test) {
997 l.hir_fmt(f)?;
1000 f.write_char(' ')?;
1001 }
1002 match m {
1003 Mutability::Not => (),
1004 Mutability::Mut => f.write_str("mut ")?,
1005 }
1006 } else {
1007 write!(
1008 f,
1009 "*{}",
1010 match m {
1011 Mutability::Not => "const ",
1012 Mutability::Mut => "mut ",
1013 }
1014 )?;
1015 }
1016
1017 let contains_impl_fn = |bounds: &[QuantifiedWhereClause]| {
1019 bounds.iter().any(|bound| {
1020 if let WhereClause::Implemented(trait_ref) = bound.skip_binders() {
1021 let trait_ = trait_ref.hir_trait_id();
1022 fn_traits(db.upcast(), trait_).any(|it| it == trait_)
1023 } else {
1024 false
1025 }
1026 })
1027 };
1028 let (preds_to_print, has_impl_fn_pred) = match t.kind(Interner) {
1029 TyKind::Dyn(dyn_ty) if dyn_ty.bounds.skip_binders().interned().len() > 1 => {
1030 let bounds = dyn_ty.bounds.skip_binders().interned();
1031 (bounds.len(), contains_impl_fn(bounds))
1032 }
1033 TyKind::Alias(AliasTy::Opaque(OpaqueTy {
1034 opaque_ty_id,
1035 substitution: parameters,
1036 }))
1037 | TyKind::OpaqueType(opaque_ty_id, parameters) => {
1038 let impl_trait_id = db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
1039 if let ImplTraitId::ReturnTypeImplTrait(func, idx) = impl_trait_id {
1040 let datas = db
1041 .return_type_impl_traits(func)
1042 .expect("impl trait id without data");
1043 let data =
1044 (*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
1045 let bounds = data.substitute(Interner, parameters);
1046 let mut len = bounds.skip_binders().len();
1047
1048 let default_sized =
1051 SizedByDefault::Sized { anchor: func.krate(db.upcast()) };
1052 let sized_bounds = bounds
1053 .skip_binders()
1054 .iter()
1055 .filter(|b| {
1056 matches!(
1057 b.skip_binders(),
1058 WhereClause::Implemented(trait_ref)
1059 if default_sized.is_sized_trait(
1060 trait_ref.hir_trait_id(),
1061 db.upcast(),
1062 ),
1063 )
1064 })
1065 .count();
1066 match sized_bounds {
1067 0 => len += 1,
1068 _ => {
1069 len = len.saturating_sub(sized_bounds);
1070 }
1071 }
1072
1073 (len, contains_impl_fn(bounds.skip_binders()))
1074 } else {
1075 (0, false)
1076 }
1077 }
1078 _ => (0, false),
1079 };
1080
1081 if has_impl_fn_pred && preds_to_print <= 2 {
1082 return t.hir_fmt(f);
1083 }
1084
1085 if preds_to_print > 1 {
1086 write!(f, "(")?;
1087 t.hir_fmt(f)?;
1088 write!(f, ")")?;
1089 } else {
1090 t.hir_fmt(f)?;
1091 }
1092 }
1093 TyKind::Tuple(_, substs) => {
1094 if substs.len(Interner) == 1 {
1095 write!(f, "(")?;
1096 substs.at(Interner, 0).hir_fmt(f)?;
1097 write!(f, ",)")?;
1098 } else {
1099 write!(f, "(")?;
1100 f.write_joined(substs.as_slice(Interner), ", ")?;
1101 write!(f, ")")?;
1102 }
1103 }
1104 TyKind::Function(fn_ptr) => {
1105 let sig = CallableSig::from_fn_ptr(fn_ptr);
1106 sig.hir_fmt(f)?;
1107 }
1108 TyKind::FnDef(def, parameters) => {
1109 let def = from_chalk(db, *def);
1110 let sig = db.callable_item_signature(def).substitute(Interner, parameters);
1111
1112 if f.display_target.is_source_code() {
1113 return sig.hir_fmt(f);
1116 }
1117 if let Safety::Unsafe = sig.safety {
1118 write!(f, "unsafe ")?;
1119 }
1120 if !matches!(sig.abi, FnAbi::Rust | FnAbi::RustCall) {
1121 f.write_str("extern \"")?;
1122 f.write_str(sig.abi.as_str())?;
1123 f.write_str("\" ")?;
1124 }
1125
1126 write!(f, "fn ")?;
1127 f.start_location_link(def.into());
1128 match def {
1129 CallableDefId::FunctionId(ff) => write!(
1130 f,
1131 "{}",
1132 db.function_data(ff).name.display(f.db.upcast(), f.edition())
1133 )?,
1134 CallableDefId::StructId(s) => {
1135 write!(f, "{}", db.struct_data(s).name.display(f.db.upcast(), f.edition()))?
1136 }
1137 CallableDefId::EnumVariantId(e) => write!(
1138 f,
1139 "{}",
1140 db.enum_variant_data(e).name.display(f.db.upcast(), f.edition())
1141 )?,
1142 };
1143 f.end_location_link();
1144
1145 if parameters.len(Interner) > 0 {
1146 let generic_def_id = GenericDefId::from_callable(db.upcast(), def);
1147 let generics = generics(db.upcast(), generic_def_id);
1148 let (parent_len, self_param, type_, const_, impl_, lifetime) =
1149 generics.provenance_split();
1150 let parameters = parameters.as_slice(Interner);
1151 debug_assert_eq!(
1152 parameters.len(),
1153 parent_len + self_param as usize + type_ + const_ + impl_ + lifetime
1154 );
1155 if parameters.len() - impl_ > 0 {
1157 let params_len = parameters.len();
1158 let parameters =
1160 generic_args_sans_defaults(f, Some(generic_def_id), parameters);
1161 assert!(params_len >= parameters.len());
1162 let defaults = params_len - parameters.len();
1163
1164 let without_impl = if parent_len > 0 {
1174 params_len - parent_len - impl_
1175 } else {
1176 params_len - parent_len - impl_ - defaults
1177 };
1178 let (fn_params, parent_params) = parameters.split_at(without_impl + impl_);
1180
1181 write!(f, "<")?;
1182 hir_fmt_generic_arguments(f, parent_params, None)?;
1183 if !parent_params.is_empty() && !fn_params.is_empty() {
1184 write!(f, ", ")?;
1185 }
1186 hir_fmt_generic_arguments(f, &fn_params[0..without_impl], None)?;
1187 write!(f, ">")?;
1188 }
1189 }
1190 write!(f, "(")?;
1191 f.write_joined(sig.params(), ", ")?;
1192 write!(f, ")")?;
1193 let ret = sig.ret();
1194 if !ret.is_unit() {
1195 write!(f, " -> ")?;
1196 ret.hir_fmt(f)?;
1197 }
1198 }
1199 TyKind::Adt(AdtId(def_id), parameters) => {
1200 f.start_location_link((*def_id).into());
1201 match f.display_target {
1202 DisplayTarget::Diagnostics { .. } | DisplayTarget::Test => {
1203 let name = match *def_id {
1204 hir_def::AdtId::StructId(it) => db.struct_data(it).name.clone(),
1205 hir_def::AdtId::UnionId(it) => db.union_data(it).name.clone(),
1206 hir_def::AdtId::EnumId(it) => db.enum_data(it).name.clone(),
1207 };
1208 write!(f, "{}", name.display(f.db.upcast(), f.edition()))?;
1209 }
1210 DisplayTarget::SourceCode { module_id, allow_opaque: _ } => {
1211 if let Some(path) = find_path::find_path(
1212 db.upcast(),
1213 ItemInNs::Types((*def_id).into()),
1214 module_id,
1215 PrefixKind::Plain,
1216 false,
1217 ImportPathConfig {
1219 prefer_no_std: false,
1220 prefer_prelude: true,
1221 prefer_absolute: false,
1222 allow_unstable: true,
1223 },
1224 ) {
1225 write!(f, "{}", path.display(f.db.upcast(), f.edition()))?;
1226 } else {
1227 return Err(HirDisplayError::DisplaySourceCodeError(
1228 DisplaySourceCodeError::PathNotFound,
1229 ));
1230 }
1231 }
1232 }
1233 f.end_location_link();
1234
1235 let generic_def = self.as_generic_def(db);
1236
1237 hir_fmt_generics(f, parameters.as_slice(Interner), generic_def, None)?;
1238 }
1239 TyKind::AssociatedType(assoc_type_id, parameters) => {
1240 let type_alias = from_assoc_type_id(*assoc_type_id);
1241 let trait_ = match type_alias.lookup(db.upcast()).container {
1242 ItemContainerId::TraitId(it) => it,
1243 _ => panic!("not an associated type"),
1244 };
1245 let trait_data = db.trait_data(trait_);
1246 let type_alias_data = db.type_alias_data(type_alias);
1247
1248 if f.display_target.is_test() {
1250 f.start_location_link(trait_.into());
1251 write!(f, "{}", trait_data.name.display(f.db.upcast(), f.edition()))?;
1252 f.end_location_link();
1253 write!(f, "::")?;
1254
1255 f.start_location_link(type_alias.into());
1256 write!(f, "{}", type_alias_data.name.display(f.db.upcast(), f.edition()))?;
1257 f.end_location_link();
1258 hir_fmt_generics(f, parameters.as_slice(Interner), None, None)
1261 } else {
1262 let projection_ty = ProjectionTy {
1263 associated_ty_id: to_assoc_type_id(type_alias),
1264 substitution: parameters.clone(),
1265 };
1266
1267 projection_ty.hir_fmt(f)
1268 }?;
1269 }
1270 TyKind::Foreign(type_alias) => {
1271 let alias = from_foreign_def_id(*type_alias);
1272 let type_alias = db.type_alias_data(alias);
1273 f.start_location_link(alias.into());
1274 write!(f, "{}", type_alias.name.display(f.db.upcast(), f.edition()))?;
1275 f.end_location_link();
1276 }
1277 TyKind::OpaqueType(opaque_ty_id, parameters) => {
1278 if !f.display_target.allows_opaque() {
1279 return Err(HirDisplayError::DisplaySourceCodeError(
1280 DisplaySourceCodeError::OpaqueType,
1281 ));
1282 }
1283 let impl_trait_id = db.lookup_intern_impl_trait_id((*opaque_ty_id).into());
1284 match impl_trait_id {
1285 ImplTraitId::ReturnTypeImplTrait(func, idx) => {
1286 let datas =
1287 db.return_type_impl_traits(func).expect("impl trait id without data");
1288 let data =
1289 (*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
1290 let bounds = data.substitute(Interner, ¶meters);
1291 let krate = func.krate(db.upcast());
1292 write_bounds_like_dyn_trait_with_prefix(
1293 f,
1294 "impl",
1295 Either::Left(self),
1296 bounds.skip_binders(),
1297 SizedByDefault::Sized { anchor: krate },
1298 )?;
1299 }
1301 ImplTraitId::TypeAliasImplTrait(alias, idx) => {
1302 let datas =
1303 db.type_alias_impl_traits(alias).expect("impl trait id without data");
1304 let data = (*datas).as_ref().map(|it| it.impl_traits[idx].bounds.clone());
1305 let bounds = data.substitute(Interner, ¶meters);
1306 let krate = alias.krate(db.upcast());
1307 write_bounds_like_dyn_trait_with_prefix(
1308 f,
1309 "impl",
1310 Either::Left(self),
1311 bounds.skip_binders(),
1312 SizedByDefault::Sized { anchor: krate },
1313 )?;
1314 }
1315 ImplTraitId::AsyncBlockTypeImplTrait(body, ..) => {
1316 let future_trait = db
1317 .lang_item(body.module(db.upcast()).krate(), LangItem::Future)
1318 .and_then(LangItemTarget::as_trait);
1319 let output = future_trait.and_then(|t| {
1320 db.trait_data(t).associated_type_by_name(&Name::new_symbol_root(
1321 sym::Output.clone(),
1322 ))
1323 });
1324 write!(f, "impl ")?;
1325 if let Some(t) = future_trait {
1326 f.start_location_link(t.into());
1327 }
1328 write!(f, "Future")?;
1329 if future_trait.is_some() {
1330 f.end_location_link();
1331 }
1332 write!(f, "<")?;
1333 if let Some(t) = output {
1334 f.start_location_link(t.into());
1335 }
1336 write!(f, "Output")?;
1337 if output.is_some() {
1338 f.end_location_link();
1339 }
1340 write!(f, " = ")?;
1341 parameters.at(Interner, 0).hir_fmt(f)?;
1342 write!(f, ">")?;
1343 }
1344 }
1345 }
1346 TyKind::Closure(id, substs) => {
1347 if f.display_target.is_source_code() {
1348 if !f.display_target.allows_opaque() {
1349 return Err(HirDisplayError::DisplaySourceCodeError(
1350 DisplaySourceCodeError::OpaqueType,
1351 ));
1352 } else if f.closure_style != ClosureStyle::ImplFn {
1353 never!("Only `impl Fn` is valid for displaying closures in source code");
1354 }
1355 }
1356 match f.closure_style {
1357 ClosureStyle::Hide => return write!(f, "{TYPE_HINT_TRUNCATION}"),
1358 ClosureStyle::ClosureWithId => {
1359 return write!(f, "{{closure#{:?}}}", id.0.as_u32())
1360 }
1361 ClosureStyle::ClosureWithSubst => {
1362 write!(f, "{{closure#{:?}}}", id.0.as_u32())?;
1363 return hir_fmt_generics(f, substs.as_slice(Interner), None, None);
1364 }
1365 _ => (),
1366 }
1367 let sig = ClosureSubst(substs).sig_ty().callable_sig(db);
1368 if let Some(sig) = sig {
1369 let InternedClosure(def, _) = db.lookup_intern_closure((*id).into());
1370 let infer = db.infer(def);
1371 let (_, kind) = infer.closure_info(id);
1372 match f.closure_style {
1373 ClosureStyle::ImplFn => write!(f, "impl {kind:?}(")?,
1374 ClosureStyle::RANotation => write!(f, "|")?,
1375 _ => unreachable!(),
1376 }
1377 if sig.params().is_empty() {
1378 } else if f.should_truncate() {
1379 write!(f, "{TYPE_HINT_TRUNCATION}")?;
1380 } else {
1381 f.write_joined(sig.params(), ", ")?;
1382 };
1383 match f.closure_style {
1384 ClosureStyle::ImplFn => write!(f, ")")?,
1385 ClosureStyle::RANotation => write!(f, "|")?,
1386 _ => unreachable!(),
1387 }
1388 if f.closure_style == ClosureStyle::RANotation || !sig.ret().is_unit() {
1389 write!(f, " -> ")?;
1390 sig.ret().hir_fmt(f)?;
1391 }
1392 } else {
1393 write!(f, "{{closure}}")?;
1394 }
1395 }
1396 TyKind::Placeholder(idx) => {
1397 let id = from_placeholder_idx(db, *idx);
1398 let generics = generics(db.upcast(), id.parent);
1399 let param_data = &generics[id.local_id];
1400 match param_data {
1401 TypeOrConstParamData::TypeParamData(p) => match p.provenance {
1402 TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
1403 write!(
1404 f,
1405 "{}",
1406 p.name
1407 .clone()
1408 .unwrap_or_else(Name::missing)
1409 .display(f.db.upcast(), f.edition())
1410 )?
1411 }
1412 TypeParamProvenance::ArgumentImplTrait => {
1413 let substs = generics.placeholder_subst(db);
1414 let bounds = db
1415 .generic_predicates(id.parent)
1416 .iter()
1417 .map(|pred| pred.clone().substitute(Interner, &substs))
1418 .filter(|wc| match wc.skip_binders() {
1419 WhereClause::Implemented(tr) => {
1420 tr.self_type_parameter(Interner) == *self
1421 }
1422 WhereClause::AliasEq(AliasEq {
1423 alias: AliasTy::Projection(proj),
1424 ty: _,
1425 }) => proj.self_type_parameter(db) == *self,
1426 WhereClause::AliasEq(_) => false,
1427 WhereClause::TypeOutlives(to) => to.ty == *self,
1428 WhereClause::LifetimeOutlives(_) => false,
1429 })
1430 .collect::<Vec<_>>();
1431 let krate = id.parent.module(db.upcast()).krate();
1432 write_bounds_like_dyn_trait_with_prefix(
1433 f,
1434 "impl",
1435 Either::Left(self),
1436 &bounds,
1437 SizedByDefault::Sized { anchor: krate },
1438 )?;
1439 }
1440 },
1441 TypeOrConstParamData::ConstParamData(p) => {
1442 write!(f, "{}", p.name.display(f.db.upcast(), f.edition()))?;
1443 }
1444 }
1445 }
1446 TyKind::BoundVar(idx) => idx.hir_fmt(f)?,
1447 TyKind::Dyn(dyn_ty) => {
1448 let mut bounds: SmallVec<[_; 4]> =
1452 dyn_ty.bounds.skip_binders().iter(Interner).cloned().collect();
1453 let (auto_traits, others): (SmallVec<[_; 4]>, _) =
1454 bounds.drain(1..).partition(|b| b.skip_binders().trait_id().is_some());
1455 bounds.extend(others);
1456 bounds.extend(auto_traits);
1457
1458 write_bounds_like_dyn_trait_with_prefix(
1459 f,
1460 "dyn",
1461 Either::Left(self),
1462 &bounds,
1463 SizedByDefault::NotSized,
1464 )?;
1465 }
1466 TyKind::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?,
1467 TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
1468 if !f.display_target.allows_opaque() {
1469 return Err(HirDisplayError::DisplaySourceCodeError(
1470 DisplaySourceCodeError::OpaqueType,
1471 ));
1472 }
1473 let impl_trait_id = db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into());
1474 match impl_trait_id {
1475 ImplTraitId::ReturnTypeImplTrait(func, idx) => {
1476 let datas =
1477 db.return_type_impl_traits(func).expect("impl trait id without data");
1478 let data =
1479 (*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
1480 let bounds = data.substitute(Interner, &opaque_ty.substitution);
1481 let krate = func.krate(db.upcast());
1482 write_bounds_like_dyn_trait_with_prefix(
1483 f,
1484 "impl",
1485 Either::Left(self),
1486 bounds.skip_binders(),
1487 SizedByDefault::Sized { anchor: krate },
1488 )?;
1489 }
1490 ImplTraitId::TypeAliasImplTrait(alias, idx) => {
1491 let datas =
1492 db.type_alias_impl_traits(alias).expect("impl trait id without data");
1493 let data =
1494 (*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
1495 let bounds = data.substitute(Interner, &opaque_ty.substitution);
1496 let krate = alias.krate(db.upcast());
1497 write_bounds_like_dyn_trait_with_prefix(
1498 f,
1499 "impl",
1500 Either::Left(self),
1501 bounds.skip_binders(),
1502 SizedByDefault::Sized { anchor: krate },
1503 )?;
1504 }
1505 ImplTraitId::AsyncBlockTypeImplTrait(..) => {
1506 write!(f, "{{async block}}")?;
1507 }
1508 };
1509 }
1510 TyKind::Error => {
1511 if f.display_target.is_source_code() {
1512 f.write_char('_')?;
1513 } else {
1514 write!(f, "{{unknown}}")?;
1515 }
1516 }
1517 TyKind::InferenceVar(..) => write!(f, "_")?,
1518 TyKind::Coroutine(_, subst) => {
1519 if f.display_target.is_source_code() {
1520 return Err(HirDisplayError::DisplaySourceCodeError(
1521 DisplaySourceCodeError::Coroutine,
1522 ));
1523 }
1524 let subst = subst.as_slice(Interner);
1525 let a: Option<SmallVec<[&Ty; 3]>> = subst
1526 .get(subst.len() - 3..)
1527 .and_then(|args| args.iter().map(|arg| arg.ty(Interner)).collect());
1528
1529 if let Some([resume_ty, yield_ty, ret_ty]) = a.as_deref() {
1530 write!(f, "|")?;
1531 resume_ty.hir_fmt(f)?;
1532 write!(f, "|")?;
1533
1534 write!(f, " yields ")?;
1535 yield_ty.hir_fmt(f)?;
1536
1537 write!(f, " -> ")?;
1538 ret_ty.hir_fmt(f)?;
1539 } else {
1540 write!(f, "{{coroutine}}")?;
1542 }
1543 }
1544 TyKind::CoroutineWitness(..) => write!(f, "{{coroutine witness}}")?,
1545 }
1546 Ok(())
1547 }
1548}
1549
1550fn hir_fmt_generics(
1551 f: &mut HirFormatter<'_>,
1552 parameters: &[GenericArg],
1553 generic_def: Option<hir_def::GenericDefId>,
1554 self_: Option<&Ty>,
1555) -> Result<(), HirDisplayError> {
1556 if parameters.is_empty() {
1557 return Ok(());
1558 }
1559
1560 let parameters_to_write = generic_args_sans_defaults(f, generic_def, parameters);
1561
1562 if !parameters_to_write.is_empty() {
1563 write!(f, "<")?;
1564 hir_fmt_generic_arguments(f, parameters_to_write, self_)?;
1565 write!(f, ">")?;
1566 }
1567
1568 Ok(())
1569}
1570
1571fn generic_args_sans_defaults<'ga>(
1572 f: &mut HirFormatter<'_>,
1573 generic_def: Option<hir_def::GenericDefId>,
1574 parameters: &'ga [GenericArg],
1575) -> &'ga [GenericArg] {
1576 if f.display_target.is_source_code() || f.omit_verbose_types() {
1577 match generic_def
1578 .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
1579 .filter(|it| !it.is_empty())
1580 {
1581 None => parameters,
1582 Some(default_parameters) => {
1583 let should_show = |arg: &GenericArg, i: usize| {
1584 let is_err = |arg: &GenericArg| match arg.data(Interner) {
1585 chalk_ir::GenericArgData::Lifetime(it) => {
1586 *it.data(Interner) == LifetimeData::Error
1587 }
1588 chalk_ir::GenericArgData::Ty(it) => *it.kind(Interner) == TyKind::Error,
1589 chalk_ir::GenericArgData::Const(it) => matches!(
1590 it.data(Interner).value,
1591 ConstValue::Concrete(ConcreteConst {
1592 interned: ConstScalar::Unknown,
1593 ..
1594 })
1595 ),
1596 };
1597 if is_err(arg) {
1599 return true;
1600 }
1601 match default_parameters.get(i) {
1604 None => true,
1605 Some(default_parameter) => {
1606 arg != &default_parameter.clone().substitute(Interner, ¶meters)
1609 }
1610 }
1611 };
1612 let mut default_from = 0;
1613 for (i, parameter) in parameters.iter().enumerate() {
1614 if should_show(parameter, i) {
1615 default_from = i + 1;
1616 }
1617 }
1618 ¶meters[0..default_from]
1619 }
1620 }
1621 } else {
1622 parameters
1623 }
1624}
1625
1626fn hir_fmt_generic_arguments(
1627 f: &mut HirFormatter<'_>,
1628 parameters: &[GenericArg],
1629 self_: Option<&Ty>,
1630) -> Result<(), HirDisplayError> {
1631 let mut first = true;
1632 let lifetime_offset = parameters.iter().position(|arg| arg.lifetime(Interner).is_some());
1633
1634 let (ty_or_const, lifetimes) = match lifetime_offset {
1635 Some(offset) => parameters.split_at(offset),
1636 None => (parameters, &[][..]),
1637 };
1638 for generic_arg in lifetimes.iter().chain(ty_or_const) {
1639 if !mem::take(&mut first) {
1640 write!(f, ", ")?;
1641 }
1642 match self_ {
1643 self_ @ Some(_) if generic_arg.ty(Interner) == self_ => write!(f, "Self")?,
1644 _ => generic_arg.hir_fmt(f)?,
1645 }
1646 }
1647 Ok(())
1648}
1649
1650impl HirDisplay for CallableSig {
1651 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
1652 let CallableSig { params_and_return: _, is_varargs, safety, abi: _ } = *self;
1653 if let Safety::Unsafe = safety {
1654 write!(f, "unsafe ")?;
1655 }
1656 write!(f, "fn(")?;
1663 f.write_joined(self.params(), ", ")?;
1664 if is_varargs {
1665 if self.params().is_empty() {
1666 write!(f, "...")?;
1667 } else {
1668 write!(f, ", ...")?;
1669 }
1670 }
1671 write!(f, ")")?;
1672 let ret = self.ret();
1673 if !ret.is_unit() {
1674 write!(f, " -> ")?;
1675 ret.hir_fmt(f)?;
1676 }
1677 Ok(())
1678 }
1679}
1680
1681fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> + '_ {
1682 let krate = trait_.lookup(db).container.krate();
1683 utils::fn_traits(db, krate)
1684}
1685
1686#[derive(Clone, Copy, PartialEq, Eq)]
1687pub enum SizedByDefault {
1688 NotSized,
1689 Sized { anchor: CrateId },
1690}
1691
1692impl SizedByDefault {
1693 fn is_sized_trait(self, trait_: TraitId, db: &dyn DefDatabase) -> bool {
1694 match self {
1695 Self::NotSized => false,
1696 Self::Sized { anchor } => {
1697 let sized_trait = db
1698 .lang_item(anchor, LangItem::Sized)
1699 .and_then(|lang_item| lang_item.as_trait());
1700 Some(trait_) == sized_trait
1701 }
1702 }
1703 }
1704}
1705
1706pub fn write_bounds_like_dyn_trait_with_prefix(
1707 f: &mut HirFormatter<'_>,
1708 prefix: &str,
1709 this: Either<&Ty, &Lifetime>,
1710 predicates: &[QuantifiedWhereClause],
1711 default_sized: SizedByDefault,
1712) -> Result<(), HirDisplayError> {
1713 write!(f, "{prefix}")?;
1714 if !predicates.is_empty()
1715 || predicates.is_empty() && matches!(default_sized, SizedByDefault::Sized { .. })
1716 {
1717 write!(f, " ")?;
1718 write_bounds_like_dyn_trait(f, this, predicates, default_sized)
1719 } else {
1720 Ok(())
1721 }
1722}
1723
1724fn write_bounds_like_dyn_trait(
1725 f: &mut HirFormatter<'_>,
1726 this: Either<&Ty, &Lifetime>,
1727 predicates: &[QuantifiedWhereClause],
1728 default_sized: SizedByDefault,
1729) -> Result<(), HirDisplayError> {
1730 let mut first = true;
1737 let mut angle_open = false;
1738 let mut is_fn_trait = false;
1739 let mut is_sized = false;
1740 for p in predicates.iter() {
1741 match p.skip_binders() {
1742 WhereClause::Implemented(trait_ref) => {
1743 let trait_ = trait_ref.hir_trait_id();
1744 if default_sized.is_sized_trait(trait_, f.db.upcast()) {
1745 is_sized = true;
1746 if matches!(default_sized, SizedByDefault::Sized { .. }) {
1747 continue;
1749 }
1750 }
1751 if !is_fn_trait {
1752 is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == trait_);
1753 }
1754 if !is_fn_trait && angle_open {
1755 write!(f, ">")?;
1756 angle_open = false;
1757 }
1758 if !first {
1759 write!(f, " + ")?;
1760 }
1761 f.start_location_link(trait_.into());
1765 write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast(), f.edition()))?;
1766 f.end_location_link();
1767 if is_fn_trait {
1768 if let [self_, params @ ..] = trait_ref.substitution.as_slice(Interner) {
1769 if let Some(args) =
1770 params.first().and_then(|it| it.assert_ty_ref(Interner).as_tuple())
1771 {
1772 write!(f, "(")?;
1773 hir_fmt_generic_arguments(
1774 f,
1775 args.as_slice(Interner),
1776 self_.ty(Interner),
1777 )?;
1778 write!(f, ")")?;
1779 }
1780 }
1781 } else {
1782 let params = generic_args_sans_defaults(
1783 f,
1784 Some(trait_.into()),
1785 trait_ref.substitution.as_slice(Interner),
1786 );
1787 if let [self_, params @ ..] = params {
1788 if !params.is_empty() {
1789 write!(f, "<")?;
1790 hir_fmt_generic_arguments(f, params, self_.ty(Interner))?;
1791 angle_open = true;
1793 }
1794 }
1795 }
1796 }
1797 WhereClause::TypeOutlives(to) if Either::Left(&to.ty) == this => {
1798 if !is_fn_trait && angle_open {
1799 write!(f, ">")?;
1800 angle_open = false;
1801 }
1802 if !first {
1803 write!(f, " + ")?;
1804 }
1805 to.lifetime.hir_fmt(f)?;
1806 }
1807 WhereClause::TypeOutlives(_) => {}
1808 WhereClause::LifetimeOutlives(lo) if Either::Right(&lo.a) == this => {
1809 if !is_fn_trait && angle_open {
1810 write!(f, ">")?;
1811 angle_open = false;
1812 }
1813 if !first {
1814 write!(f, " + ")?;
1815 }
1816 lo.b.hir_fmt(f)?;
1817 }
1818 WhereClause::LifetimeOutlives(_) => {}
1819 WhereClause::AliasEq(alias_eq) if is_fn_trait => {
1820 is_fn_trait = false;
1821 if !alias_eq.ty.is_unit() {
1822 write!(f, " -> ")?;
1823 alias_eq.ty.hir_fmt(f)?;
1824 }
1825 }
1826 WhereClause::AliasEq(AliasEq { ty, alias }) => {
1827 if angle_open {
1830 write!(f, ", ")?;
1831 } else {
1832 write!(f, "<")?;
1833 angle_open = true;
1834 }
1835 if let AliasTy::Projection(proj) = alias {
1836 let assoc_ty_id = from_assoc_type_id(proj.associated_ty_id);
1837 let type_alias = f.db.type_alias_data(assoc_ty_id);
1838 f.start_location_link(assoc_ty_id.into());
1839 write!(f, "{}", type_alias.name.display(f.db.upcast(), f.edition()))?;
1840 f.end_location_link();
1841
1842 let proj_arg_count = generics(f.db.upcast(), assoc_ty_id.into()).len_self();
1843 if proj_arg_count > 0 {
1844 write!(f, "<")?;
1845 hir_fmt_generic_arguments(
1846 f,
1847 &proj.substitution.as_slice(Interner)[..proj_arg_count],
1848 None,
1849 )?;
1850 write!(f, ">")?;
1851 }
1852 write!(f, " = ")?;
1853 }
1854 ty.hir_fmt(f)?;
1855 }
1856 }
1857 first = false;
1858 }
1859 if angle_open {
1860 write!(f, ">")?;
1861 }
1862 if let SizedByDefault::Sized { anchor } = default_sized {
1863 let sized_trait =
1864 f.db.lang_item(anchor, LangItem::Sized).and_then(|lang_item| lang_item.as_trait());
1865 if !is_sized {
1866 if !first {
1867 write!(f, " + ")?;
1868 }
1869 if let Some(sized_trait) = sized_trait {
1870 f.start_location_link(sized_trait.into());
1871 }
1872 write!(f, "?Sized")?;
1873 } else if first {
1874 if let Some(sized_trait) = sized_trait {
1875 f.start_location_link(sized_trait.into());
1876 }
1877 write!(f, "Sized")?;
1878 }
1879 if sized_trait.is_some() {
1880 f.end_location_link();
1881 }
1882 }
1883 Ok(())
1884}
1885
1886impl HirDisplay for TraitRef {
1887 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
1888 let trait_ = self.hir_trait_id();
1889 f.start_location_link(trait_.into());
1890 write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast(), f.edition()))?;
1891 f.end_location_link();
1892 let substs = self.substitution.as_slice(Interner);
1893 hir_fmt_generics(f, &substs[1..], None, substs[0].ty(Interner))
1894 }
1895}
1896
1897impl HirDisplay for WhereClause {
1898 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
1899 if f.should_truncate() {
1900 return write!(f, "{TYPE_HINT_TRUNCATION}");
1901 }
1902
1903 match self {
1904 WhereClause::Implemented(trait_ref) => {
1905 trait_ref.self_type_parameter(Interner).hir_fmt(f)?;
1906 write!(f, ": ")?;
1907 trait_ref.hir_fmt(f)?;
1908 }
1909 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
1910 write!(f, "<")?;
1911 let trait_ref = &projection_ty.trait_ref(f.db);
1912 trait_ref.self_type_parameter(Interner).hir_fmt(f)?;
1913 write!(f, " as ")?;
1914 trait_ref.hir_fmt(f)?;
1915 write!(f, ">::",)?;
1916 let type_alias = from_assoc_type_id(projection_ty.associated_ty_id);
1917 f.start_location_link(type_alias.into());
1918 write!(
1919 f,
1920 "{}",
1921 f.db.type_alias_data(type_alias).name.display(f.db.upcast(), f.edition()),
1922 )?;
1923 f.end_location_link();
1924 write!(f, " = ")?;
1925 ty.hir_fmt(f)?;
1926 }
1927 WhereClause::AliasEq(_) => write!(f, "{{error}}")?,
1928
1929 WhereClause::TypeOutlives(..) => {}
1931 WhereClause::LifetimeOutlives(..) => {}
1932 }
1933 Ok(())
1934 }
1935}
1936
1937impl HirDisplay for LifetimeOutlives {
1938 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
1939 self.a.hir_fmt(f)?;
1940 write!(f, ": ")?;
1941 self.b.hir_fmt(f)
1942 }
1943}
1944
1945impl HirDisplay for Lifetime {
1946 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
1947 self.interned().hir_fmt(f)
1948 }
1949}
1950
1951impl HirDisplay for LifetimeData {
1952 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
1953 match self {
1954 LifetimeData::Placeholder(idx) => {
1955 let id = lt_from_placeholder_idx(f.db, *idx);
1956 let generics = generics(f.db.upcast(), id.parent);
1957 let param_data = &generics[id.local_id];
1958 write!(f, "{}", param_data.name.display(f.db.upcast(), f.edition()))?;
1959 Ok(())
1960 }
1961 _ if f.display_target.is_source_code() => write!(f, "'_"),
1962 LifetimeData::BoundVar(idx) => idx.hir_fmt(f),
1963 LifetimeData::InferenceVar(_) => write!(f, "_"),
1964 LifetimeData::Static => write!(f, "'static"),
1965 LifetimeData::Error => {
1966 if cfg!(test) {
1967 write!(f, "'?")
1968 } else {
1969 write!(f, "'_")
1970 }
1971 }
1972 LifetimeData::Erased => write!(f, "'<erased>"),
1973 LifetimeData::Phantom(void, _) => match *void {},
1974 }
1975 }
1976}
1977
1978impl HirDisplay for DomainGoal {
1979 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
1980 match self {
1981 DomainGoal::Holds(wc) => {
1982 write!(f, "Holds(")?;
1983 wc.hir_fmt(f)?;
1984 write!(f, ")")?;
1985 }
1986 _ => write!(f, "_")?,
1987 }
1988 Ok(())
1989 }
1990}
1991
1992pub fn write_visibility(
1993 module_id: ModuleId,
1994 vis: Visibility,
1995 f: &mut HirFormatter<'_>,
1996) -> Result<(), HirDisplayError> {
1997 match vis {
1998 Visibility::Public => write!(f, "pub "),
1999 Visibility::Module(vis_id, _) => {
2000 let def_map = module_id.def_map(f.db.upcast());
2001 let root_module_id = def_map.module_id(DefMap::ROOT);
2002 if vis_id == module_id {
2003 Ok(())
2005 } else if root_module_id == vis_id {
2006 write!(f, "pub(crate) ")
2007 } else if module_id.containing_module(f.db.upcast()) == Some(vis_id) {
2008 write!(f, "pub(super) ")
2009 } else {
2010 write!(f, "pub(in ...) ")
2011 }
2012 }
2013 }
2014}
2015
2016pub trait HirDisplayWithTypesMap {
2017 fn hir_fmt(
2018 &self,
2019 f: &mut HirFormatter<'_>,
2020 types_map: &TypesMap,
2021 ) -> Result<(), HirDisplayError>;
2022}
2023
2024impl<T: ?Sized + HirDisplayWithTypesMap> HirDisplayWithTypesMap for &'_ T {
2025 fn hir_fmt(
2026 &self,
2027 f: &mut HirFormatter<'_>,
2028 types_map: &TypesMap,
2029 ) -> Result<(), HirDisplayError> {
2030 T::hir_fmt(&**self, f, types_map)
2031 }
2032}
2033
2034pub fn hir_display_with_types_map<'a, T: HirDisplayWithTypesMap + 'a>(
2035 value: T,
2036 types_map: &'a TypesMap,
2037) -> impl HirDisplay + 'a {
2038 TypesMapAdapter(value, types_map)
2039}
2040
2041struct TypesMapAdapter<'a, T>(T, &'a TypesMap);
2042
2043impl<'a, T> TypesMapAdapter<'a, T> {
2044 fn wrap(types_map: &'a TypesMap) -> impl Fn(T) -> TypesMapAdapter<'a, T> {
2045 move |value| TypesMapAdapter(value, types_map)
2046 }
2047}
2048
2049impl<T: HirDisplayWithTypesMap> HirDisplay for TypesMapAdapter<'_, T> {
2050 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
2051 T::hir_fmt(&self.0, f, self.1)
2052 }
2053}
2054
2055impl HirDisplayWithTypesMap for TypeRefId {
2056 fn hir_fmt(
2057 &self,
2058 f: &mut HirFormatter<'_>,
2059 types_map: &TypesMap,
2060 ) -> Result<(), HirDisplayError> {
2061 match &types_map[*self] {
2062 TypeRef::Never => write!(f, "!")?,
2063 TypeRef::Placeholder => write!(f, "_")?,
2064 TypeRef::Tuple(elems) => {
2065 write!(f, "(")?;
2066 f.write_joined(elems.iter().map(TypesMapAdapter::wrap(types_map)), ", ")?;
2067 if elems.len() == 1 {
2068 write!(f, ",")?;
2069 }
2070 write!(f, ")")?;
2071 }
2072 TypeRef::Path(path) => path.hir_fmt(f, types_map)?,
2073 TypeRef::RawPtr(inner, mutability) => {
2074 let mutability = match mutability {
2075 hir_def::type_ref::Mutability::Shared => "*const ",
2076 hir_def::type_ref::Mutability::Mut => "*mut ",
2077 };
2078 write!(f, "{mutability}")?;
2079 inner.hir_fmt(f, types_map)?;
2080 }
2081 TypeRef::Reference(ref_) => {
2082 let mutability = match ref_.mutability {
2083 hir_def::type_ref::Mutability::Shared => "",
2084 hir_def::type_ref::Mutability::Mut => "mut ",
2085 };
2086 write!(f, "&")?;
2087 if let Some(lifetime) = &ref_.lifetime {
2088 write!(f, "{} ", lifetime.name.display(f.db.upcast(), f.edition()))?;
2089 }
2090 write!(f, "{mutability}")?;
2091 ref_.ty.hir_fmt(f, types_map)?;
2092 }
2093 TypeRef::Array(array) => {
2094 write!(f, "[")?;
2095 array.ty.hir_fmt(f, types_map)?;
2096 write!(f, "; {}]", array.len.display(f.db.upcast(), f.edition()))?;
2097 }
2098 TypeRef::Slice(inner) => {
2099 write!(f, "[")?;
2100 inner.hir_fmt(f, types_map)?;
2101 write!(f, "]")?;
2102 }
2103 TypeRef::Fn(fn_) => {
2104 if fn_.is_unsafe() {
2105 write!(f, "unsafe ")?;
2106 }
2107 if let Some(abi) = fn_.abi() {
2108 f.write_str("extern \"")?;
2109 f.write_str(abi.as_str())?;
2110 f.write_str("\" ")?;
2111 }
2112 write!(f, "fn(")?;
2113 if let Some(((_, return_type), function_parameters)) = fn_.params().split_last() {
2114 for index in 0..function_parameters.len() {
2115 let (param_name, param_type) = &function_parameters[index];
2116 if let Some(name) = param_name {
2117 write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?;
2118 }
2119
2120 param_type.hir_fmt(f, types_map)?;
2121
2122 if index != function_parameters.len() - 1 {
2123 write!(f, ", ")?;
2124 }
2125 }
2126 if fn_.is_varargs() {
2127 write!(f, "{}...", if fn_.params().len() == 1 { "" } else { ", " })?;
2128 }
2129 write!(f, ")")?;
2130 match &types_map[*return_type] {
2131 TypeRef::Tuple(tup) if tup.is_empty() => {}
2132 _ => {
2133 write!(f, " -> ")?;
2134 return_type.hir_fmt(f, types_map)?;
2135 }
2136 }
2137 }
2138 }
2139 TypeRef::ImplTrait(bounds) => {
2140 write!(f, "impl ")?;
2141 f.write_joined(bounds.iter().map(TypesMapAdapter::wrap(types_map)), " + ")?;
2142 }
2143 TypeRef::DynTrait(bounds) => {
2144 write!(f, "dyn ")?;
2145 f.write_joined(bounds.iter().map(TypesMapAdapter::wrap(types_map)), " + ")?;
2146 }
2147 TypeRef::Macro(macro_call) => {
2148 let (mut types_map, mut types_source_map) =
2149 (TypesMap::default(), TypesSourceMap::default());
2150 let mut ctx = hir_def::lower::LowerCtx::new(
2151 f.db.upcast(),
2152 macro_call.file_id,
2153 &mut types_map,
2154 &mut types_source_map,
2155 );
2156 let macro_call = macro_call.to_node(f.db.upcast());
2157 match macro_call.path() {
2158 Some(path) => match Path::from_src(&mut ctx, path) {
2159 Some(path) => path.hir_fmt(f, &types_map)?,
2160 None => write!(f, "{{macro}}")?,
2161 },
2162 None => write!(f, "{{macro}}")?,
2163 }
2164 write!(f, "!(..)")?;
2165 }
2166 TypeRef::Error => write!(f, "{{error}}")?,
2167 }
2168 Ok(())
2169 }
2170}
2171
2172impl HirDisplayWithTypesMap for TypeBound {
2173 fn hir_fmt(
2174 &self,
2175 f: &mut HirFormatter<'_>,
2176 types_map: &TypesMap,
2177 ) -> Result<(), HirDisplayError> {
2178 match self {
2179 &TypeBound::Path(path, modifier) => {
2180 match modifier {
2181 TraitBoundModifier::None => (),
2182 TraitBoundModifier::Maybe => write!(f, "?")?,
2183 }
2184 types_map[path].hir_fmt(f, types_map)
2185 }
2186 TypeBound::Lifetime(lifetime) => {
2187 write!(f, "{}", lifetime.name.display(f.db.upcast(), f.edition()))
2188 }
2189 TypeBound::ForLifetime(lifetimes, path) => {
2190 let edition = f.edition();
2191 write!(
2192 f,
2193 "for<{}> ",
2194 lifetimes.iter().map(|it| it.display(f.db.upcast(), edition)).format(", ")
2195 )?;
2196 types_map[*path].hir_fmt(f, types_map)
2197 }
2198 TypeBound::Use(args) => {
2199 let edition = f.edition();
2200 write!(
2201 f,
2202 "use<{}> ",
2203 args.iter()
2204 .map(|it| match it {
2205 UseArgRef::Lifetime(lt) => lt.name.display(f.db.upcast(), edition),
2206 UseArgRef::Name(n) => n.display(f.db.upcast(), edition),
2207 })
2208 .format(", ")
2209 )
2210 }
2211 TypeBound::Error => write!(f, "{{error}}"),
2212 }
2213 }
2214}
2215
2216impl HirDisplayWithTypesMap for Path {
2217 fn hir_fmt(
2218 &self,
2219 f: &mut HirFormatter<'_>,
2220 types_map: &TypesMap,
2221 ) -> Result<(), HirDisplayError> {
2222 match (self.type_anchor(), self.kind()) {
2223 (Some(anchor), _) => {
2224 write!(f, "<")?;
2225 anchor.hir_fmt(f, types_map)?;
2226 write!(f, ">")?;
2227 }
2228 (_, PathKind::Plain) => {}
2229 (_, PathKind::Abs) => {}
2230 (_, PathKind::Crate) => write!(f, "crate")?,
2231 (_, &PathKind::SELF) => write!(f, "self")?,
2232 (_, PathKind::Super(n)) => {
2233 for i in 0..*n {
2234 if i > 0 {
2235 write!(f, "::")?;
2236 }
2237 write!(f, "super")?;
2238 }
2239 }
2240 (_, PathKind::DollarCrate(id)) => {
2241 let crate_graph = f.db.crate_graph();
2245 let name = crate_graph[*id]
2246 .display_name
2247 .as_ref()
2248 .map(|name| name.canonical_name())
2249 .unwrap_or(&sym::dollar_crate);
2250 write!(f, "{name}")?
2251 }
2252 }
2253
2254 let trait_self_ty = self.segments().iter().find_map(|seg| {
2263 let generic_args = seg.args_and_bindings?;
2264 generic_args.has_self_type.then(|| &generic_args.args[0])
2265 });
2266 if let Some(ty) = trait_self_ty {
2267 write!(f, "<")?;
2268 ty.hir_fmt(f, types_map)?;
2269 write!(f, " as ")?;
2270 }
2272
2273 for (seg_idx, segment) in self.segments().iter().enumerate() {
2274 if !matches!(self.kind(), PathKind::Plain) || seg_idx > 0 {
2275 write!(f, "::")?;
2276 }
2277 write!(f, "{}", segment.name.display(f.db.upcast(), f.edition()))?;
2278 if let Some(generic_args) = segment.args_and_bindings {
2279 if generic_args.desugared_from_fn {
2282 let tuple = match generic_args.args[0] {
2285 hir_def::path::GenericArg::Type(ty) => match &types_map[ty] {
2286 TypeRef::Tuple(it) => Some(it),
2287 _ => None,
2288 },
2289 _ => None,
2290 };
2291 if let Some(v) = tuple {
2292 if v.len() == 1 {
2293 write!(f, "(")?;
2294 v[0].hir_fmt(f, types_map)?;
2295 write!(f, ")")?;
2296 } else {
2297 generic_args.args[0].hir_fmt(f, types_map)?;
2298 }
2299 }
2300 if let Some(ret) = generic_args.bindings[0].type_ref {
2301 if !matches!(&types_map[ret], TypeRef::Tuple(v) if v.is_empty()) {
2302 write!(f, " -> ")?;
2303 ret.hir_fmt(f, types_map)?;
2304 }
2305 }
2306 return Ok(());
2307 }
2308
2309 let mut first = true;
2310 for arg in &generic_args.args[generic_args.has_self_type as usize..] {
2312 if first {
2313 first = false;
2314 write!(f, "<")?;
2315 } else {
2316 write!(f, ", ")?;
2317 }
2318 arg.hir_fmt(f, types_map)?;
2319 }
2320 for binding in generic_args.bindings.iter() {
2321 if first {
2322 first = false;
2323 write!(f, "<")?;
2324 } else {
2325 write!(f, ", ")?;
2326 }
2327 write!(f, "{}", binding.name.display(f.db.upcast(), f.edition()))?;
2328 match &binding.type_ref {
2329 Some(ty) => {
2330 write!(f, " = ")?;
2331 ty.hir_fmt(f, types_map)?
2332 }
2333 None => {
2334 write!(f, ": ")?;
2335 f.write_joined(
2336 binding.bounds.iter().map(TypesMapAdapter::wrap(types_map)),
2337 " + ",
2338 )?;
2339 }
2340 }
2341 }
2342
2343 if !first {
2346 write!(f, ">")?;
2347 }
2348
2349 if generic_args.has_self_type {
2351 write!(f, ">")?;
2352 }
2353 }
2354 }
2355
2356 Ok(())
2357 }
2358}
2359
2360impl HirDisplayWithTypesMap for hir_def::path::GenericArg {
2361 fn hir_fmt(
2362 &self,
2363 f: &mut HirFormatter<'_>,
2364 types_map: &TypesMap,
2365 ) -> Result<(), HirDisplayError> {
2366 match self {
2367 hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f, types_map),
2368 hir_def::path::GenericArg::Const(c) => {
2369 write!(f, "{}", c.display(f.db.upcast(), f.edition()))
2370 }
2371 hir_def::path::GenericArg::Lifetime(lifetime) => {
2372 write!(f, "{}", lifetime.name.display(f.db.upcast(), f.edition()))
2373 }
2374 }
2375 }
2376}