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