1use std::{
6 fmt::{self, Debug},
7 mem,
8};
9
10use base_db::{Crate, FxIndexMap};
11use either::Either;
12use hir_def::{
13 ExpressionStoreOwnerId, FindPathConfig, GenericDefId, GenericParamId, HasModule,
14 ItemContainerId, LocalFieldId, Lookup, ModuleDefId, ModuleId, TraitId, TypeAliasId,
15 expr_store::{ExpressionStore, path::Path},
16 find_path::{self, PrefixKind},
17 hir::{
18 ClosureKind as HirClosureKind, CoroutineKind, PatId,
19 generics::{GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate},
20 },
21 item_scope::ItemInNs,
22 item_tree::FieldsShape,
23 lang_item::LangItems,
24 signatures::{
25 ConstSignature, EnumSignature, FunctionSignature, StaticSignature, StructSignature,
26 TraitSignature, TypeAliasSignature, UnionSignature, VariantFields,
27 },
28 type_ref::{
29 ConstRef, LifetimeRef, LifetimeRefId, TraitBoundModifier, TypeBound, TypeRef, TypeRefId,
30 UseArgRef,
31 },
32 visibility::Visibility,
33};
34use hir_expand::{mod_path::PathKind, name::Name};
35use intern::{Internable, Interned, sym};
36use itertools::Itertools;
37use la_arena::ArenaMap;
38use rustc_abi::ExternAbi;
39use rustc_apfloat::{
40 Float,
41 ieee::{Half as f16, Quad as f128},
42};
43use rustc_ast_ir::FloatTy;
44use rustc_hash::FxHashSet;
45use rustc_type_ir::{
46 AliasTyKind, BoundVarIndexKind, CoroutineArgsParts, RegionKind, Upcast,
47 inherent::{GenericArgs as _, IntoKind, Term as _, Ty as _, Tys as _},
48};
49use smallvec::SmallVec;
50use span::Edition;
51use stdx::never;
52
53use crate::{
54 CallableDefId, FieldType, ImplTraitId, MemoryMap, ParamEnvAndCrate, consteval,
55 db::{GeneralConstId, HirDatabase},
56 generics::{ProvenanceSplit, generics},
57 layout::Layout,
58 lower::GenericPredicates,
59 mir::{IsSigned, pad16},
60 next_solver::{
61 AliasTy, Allocation, Clause, ClauseKind, Const, ConstKind, DbInterner,
62 ExistentialPredicate, FnSig, GenericArg, GenericArgKind, GenericArgs, ParamEnv, PolyFnSig,
63 Region, Term, TermId, TermKind, TraitPredicate, TraitRef, Ty, TyKind, TypingMode,
64 Unnormalized, ValTree,
65 abi::Safety,
66 infer::{DbInternerInferExt, traits::ObligationCause},
67 },
68 primitive,
69 utils::{detect_variant_from_bytes, fn_traits},
70};
71
72fn async_gen_item_ty_from_yield_ty<'db>(
73 lang_items: &LangItems,
74 yield_ty: Ty<'db>,
75) -> Option<Ty<'db>> {
76 let poll_id = lang_items.Poll.map(hir_def::AdtId::EnumId)?;
77 let option_id = lang_items.Option.map(hir_def::AdtId::EnumId)?;
78
79 let TyKind::Adt(poll_def, poll_args) = yield_ty.kind() else {
80 return None;
81 };
82 if poll_def.def_id() != poll_id {
83 return None;
84 }
85 let [poll_inner] = poll_args.as_slice() else {
86 return None;
87 };
88 let poll_inner = poll_inner.ty()?;
89
90 let TyKind::Adt(option_def, option_args) = poll_inner.kind() else {
91 return None;
92 };
93 if option_def.def_id() != option_id {
94 return None;
95 }
96 let [item] = option_args.as_slice() else {
97 return None;
98 };
99 item.ty()
100}
101
102pub type Result<T = (), E = HirDisplayError> = std::result::Result<T, E>;
103
104pub trait HirWrite: fmt::Write {
105 fn start_location_link(&mut self, _location: ModuleDefId) {}
106 fn start_location_link_generic(&mut self, _location: GenericParamId) {}
107 fn end_location_link(&mut self) {}
108}
109
110impl HirWrite for String {}
112
113impl HirWrite for fmt::Formatter<'_> {}
115
116pub struct HirFormatter<'a, 'db> {
117 pub db: &'db dyn HirDatabase,
119 pub interner: DbInterner<'db>,
120 fmt: &'a mut dyn HirWrite,
122 buf: String,
124 curr_size: usize,
126 max_size: Option<usize>,
128 pub entity_limit: Option<usize>,
131 show_container_bounds: bool,
133 render_private_fields: bool,
134 omit_verbose_types: bool,
135 closure_style: ClosureStyle,
136 display_lifetimes: DisplayLifetime,
137 display_kind: DisplayKind,
138 display_target: DisplayTarget,
139 currently_formatting_bounds: FxHashSet<AliasTy<'db>>,
148 trait_bounds_need_parens: bool,
151}
152
153#[derive(Copy, Clone)]
159pub enum DisplayLifetime {
160 Always,
161 OnlyStatic,
162 OnlyNamed,
163 OnlyNamedOrStatic,
164 Never,
165}
166
167impl<'db> HirFormatter<'_, 'db> {
168 pub fn start_location_link(&mut self, location: ModuleDefId) {
169 self.fmt.start_location_link(location);
170 }
171
172 pub fn start_location_link_generic(&mut self, location: GenericParamId) {
173 self.fmt.start_location_link_generic(location);
174 }
175
176 pub fn end_location_link(&mut self) {
177 self.fmt.end_location_link();
178 }
179
180 fn format_bounds_with<F: FnOnce(&mut Self) -> Result>(
181 &mut self,
182 target: AliasTy<'db>,
183 format_bounds: F,
184 ) -> Result {
185 if self.currently_formatting_bounds.insert(target) {
186 let result = format_bounds(self);
187 self.currently_formatting_bounds.remove(&target);
188 result
189 } else {
190 if self.display_kind.is_source_code() {
191 Err(HirDisplayError::DisplaySourceCodeError(DisplaySourceCodeError::Cycle))
192 } else {
193 match target.kind {
194 AliasTyKind::Projection { def_id } => {
195 let def_id = def_id.0;
196 let ItemContainerId::TraitId(trait_) = def_id.loc(self.db).container else {
197 panic!("expected an assoc type");
198 };
199 let trait_name = &TraitSignature::of(self.db, trait_).name;
200 let assoc_type_name = &TypeAliasSignature::of(self.db, def_id).name;
201 write!(
202 self,
203 "<… as {}>::{}",
204 trait_name.display(self.db, self.edition()),
205 assoc_type_name.display(self.db, self.edition()),
206 )?;
207 if target.args.len() > 1 {
208 self.write_str("<…>")?;
209 }
210 Ok(())
211 }
212 AliasTyKind::Inherent { .. }
213 | AliasTyKind::Opaque { .. }
214 | AliasTyKind::Free { .. } => self.write_str("…"),
215 }
216 }
217 }
218 }
219
220 fn render_region(&self, lifetime: Region<'db>) -> bool {
221 match self.display_lifetimes {
222 DisplayLifetime::Always => true,
223 DisplayLifetime::OnlyStatic => matches!(lifetime.kind(), RegionKind::ReStatic),
224 DisplayLifetime::OnlyNamed => {
225 matches!(lifetime.kind(), RegionKind::ReEarlyParam(_))
226 }
227 DisplayLifetime::OnlyNamedOrStatic => {
228 matches!(lifetime.kind(), RegionKind::ReStatic | RegionKind::ReEarlyParam(_))
229 }
230 DisplayLifetime::Never => false,
231 }
232 }
233}
234
235pub trait HirDisplay<'db> {
236 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result;
237
238 fn into_displayable<'a>(
240 &'a self,
241 db: &'db dyn HirDatabase,
242 max_size: Option<usize>,
243 limited_size: Option<usize>,
244 omit_verbose_types: bool,
245 display_target: DisplayTarget,
246 display_kind: DisplayKind,
247 closure_style: ClosureStyle,
248 show_container_bounds: bool,
249 ) -> HirDisplayWrapper<'a, 'db, Self>
250 where
251 Self: Sized,
252 {
253 assert!(
254 !matches!(display_kind, DisplayKind::SourceCode { .. }),
255 "HirDisplayWrapper cannot fail with DisplaySourceCodeError, use HirDisplay::hir_fmt directly instead"
256 );
257 HirDisplayWrapper {
258 db,
259 t: self,
260 max_size,
261 limited_size,
262 omit_verbose_types,
263 display_target,
264 display_kind,
265 closure_style,
266 show_container_bounds,
267 render_private_fields: true,
268 display_lifetimes: DisplayLifetime::OnlyNamedOrStatic,
269 }
270 }
271
272 fn display<'a>(
275 &'a self,
276 db: &'db dyn HirDatabase,
277 display_target: DisplayTarget,
278 ) -> HirDisplayWrapper<'a, 'db, Self>
279 where
280 Self: Sized,
281 {
282 HirDisplayWrapper {
283 db,
284 t: self,
285 max_size: None,
286 limited_size: None,
287 omit_verbose_types: false,
288 closure_style: ClosureStyle::ImplFn,
289 display_target,
290 display_kind: DisplayKind::Diagnostics,
291 show_container_bounds: false,
292 render_private_fields: true,
293 display_lifetimes: DisplayLifetime::OnlyNamedOrStatic,
294 }
295 }
296
297 fn display_truncated<'a>(
300 &'a self,
301 db: &'db dyn HirDatabase,
302 max_size: Option<usize>,
303 display_target: DisplayTarget,
304 ) -> HirDisplayWrapper<'a, 'db, Self>
305 where
306 Self: Sized,
307 {
308 HirDisplayWrapper {
309 db,
310 t: self,
311 max_size,
312 limited_size: None,
313 omit_verbose_types: true,
314 closure_style: ClosureStyle::ImplFn,
315 display_target,
316 display_kind: DisplayKind::Diagnostics,
317 show_container_bounds: false,
318 render_private_fields: true,
319 display_lifetimes: DisplayLifetime::OnlyNamedOrStatic,
320 }
321 }
322
323 fn display_limited<'a>(
326 &'a self,
327 db: &'db dyn HirDatabase,
328 limited_size: Option<usize>,
329 display_target: DisplayTarget,
330 ) -> HirDisplayWrapper<'a, 'db, Self>
331 where
332 Self: Sized,
333 {
334 HirDisplayWrapper {
335 db,
336 t: self,
337 max_size: None,
338 limited_size,
339 omit_verbose_types: true,
340 closure_style: ClosureStyle::ImplFn,
341 display_target,
342 display_kind: DisplayKind::Diagnostics,
343 show_container_bounds: false,
344 render_private_fields: true,
345 display_lifetimes: DisplayLifetime::OnlyNamedOrStatic,
346 }
347 }
348
349 fn display_source_code<'a>(
352 &'a self,
353 db: &'db dyn HirDatabase,
354 module_id: ModuleId,
355 allow_opaque: bool,
356 ) -> Result<String, DisplaySourceCodeError> {
357 let mut result = String::new();
358 let interner = DbInterner::new_with(db, module_id.krate(db));
359 match self.hir_fmt(&mut HirFormatter {
360 db,
361 interner,
362 fmt: &mut result,
363 buf: String::with_capacity(20),
364 curr_size: 0,
365 max_size: None,
366 entity_limit: None,
367 omit_verbose_types: false,
368 closure_style: ClosureStyle::ImplFn,
369 display_target: DisplayTarget::from_crate(db, module_id.krate(db)),
370 display_kind: DisplayKind::SourceCode { target_module_id: module_id, allow_opaque },
371 show_container_bounds: false,
372 render_private_fields: true,
373 display_lifetimes: DisplayLifetime::OnlyNamedOrStatic,
374 currently_formatting_bounds: Default::default(),
375 trait_bounds_need_parens: false,
376 }) {
377 Ok(()) => {}
378 Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"),
379 Err(HirDisplayError::DisplaySourceCodeError(e)) => return Err(e),
380 };
381 Ok(result)
382 }
383
384 fn display_test<'a>(
386 &'a self,
387 db: &'db dyn HirDatabase,
388 display_target: DisplayTarget,
389 ) -> HirDisplayWrapper<'a, 'db, Self>
390 where
391 Self: Sized,
392 {
393 HirDisplayWrapper {
394 db,
395 t: self,
396 max_size: None,
397 limited_size: None,
398 omit_verbose_types: false,
399 closure_style: ClosureStyle::ImplFn,
400 display_target,
401 display_kind: DisplayKind::Test,
402 show_container_bounds: false,
403 render_private_fields: true,
404 display_lifetimes: DisplayLifetime::Always,
405 }
406 }
407
408 fn display_with_container_bounds<'a>(
411 &'a self,
412 db: &'db dyn HirDatabase,
413 show_container_bounds: bool,
414 display_target: DisplayTarget,
415 ) -> HirDisplayWrapper<'a, 'db, Self>
416 where
417 Self: Sized,
418 {
419 HirDisplayWrapper {
420 db,
421 t: self,
422 max_size: None,
423 limited_size: None,
424 omit_verbose_types: false,
425 closure_style: ClosureStyle::ImplFn,
426 display_target,
427 display_kind: DisplayKind::Diagnostics,
428 show_container_bounds,
429 render_private_fields: true,
430 display_lifetimes: DisplayLifetime::OnlyNamedOrStatic,
431 }
432 }
433}
434
435impl<'db> HirFormatter<'_, 'db> {
436 pub fn krate(&self) -> Crate {
437 self.display_target.krate
438 }
439
440 pub fn edition(&self) -> Edition {
441 self.display_target.edition
442 }
443
444 #[inline]
445 pub fn lang_items(&self) -> &'db LangItems {
446 self.interner.lang_items()
447 }
448
449 pub fn write_joined<T: HirDisplay<'db>>(
450 &mut self,
451 iter: impl IntoIterator<Item = T>,
452 sep: &str,
453 ) -> Result {
454 let mut first = true;
455 for e in iter {
456 if !first {
457 write!(self, "{sep}")?;
458 }
459 first = false;
460
461 if self.should_truncate() {
463 return write!(self, "{TYPE_HINT_TRUNCATION}");
464 }
465
466 e.hir_fmt(self)?;
467 }
468 Ok(())
469 }
470
471 pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result {
473 self.buf.clear();
475 fmt::write(&mut self.buf, args)?;
476 self.curr_size += self.buf.len();
477
478 self.fmt.write_str(&self.buf).map_err(HirDisplayError::from)
480 }
481
482 pub fn write_str(&mut self, s: &str) -> Result {
483 self.fmt.write_str(s)?;
484 Ok(())
485 }
486
487 pub fn write_char(&mut self, c: char) -> Result {
488 self.fmt.write_char(c)?;
489 Ok(())
490 }
491
492 pub fn should_truncate(&self) -> bool {
493 match self.max_size {
494 Some(max_size) => self.curr_size >= max_size,
495 None => false,
496 }
497 }
498
499 pub fn omit_verbose_types(&self) -> bool {
500 self.omit_verbose_types
501 }
502
503 pub fn show_container_bounds(&self) -> bool {
504 self.show_container_bounds
505 }
506
507 pub fn render_private_fields(&self) -> bool {
508 self.render_private_fields
509 }
510}
511
512#[derive(Debug, Clone, Copy)]
513pub struct DisplayTarget {
514 krate: Crate,
515 pub edition: Edition,
516}
517
518impl DisplayTarget {
519 pub fn from_crate(db: &dyn HirDatabase, krate: Crate) -> Self {
520 let edition = krate.data(db).edition;
521 Self { krate, edition }
522 }
523
524 pub fn from_crate_and_edition(db: &dyn HirDatabase, krate: Crate, edition: Edition) -> Self {
525 let _ = db;
526 Self { krate, edition }
527 }
528}
529
530#[derive(Clone, Copy)]
531pub enum DisplayKind {
532 Diagnostics,
536 SourceCode { target_module_id: ModuleId, allow_opaque: bool },
539 Test,
541}
542
543impl DisplayKind {
544 fn is_source_code(self) -> bool {
545 matches!(self, Self::SourceCode { .. })
546 }
547
548 fn allows_opaque(self) -> bool {
549 match self {
550 Self::SourceCode { allow_opaque, .. } => allow_opaque,
551 _ => true,
552 }
553 }
554}
555
556#[derive(Debug)]
557pub enum DisplaySourceCodeError {
558 PathNotFound,
559 Coroutine,
560 OpaqueType,
561 Cycle,
562}
563
564pub enum HirDisplayError {
565 DisplaySourceCodeError(DisplaySourceCodeError),
567 FmtError,
569}
570impl From<fmt::Error> for HirDisplayError {
571 fn from(_: fmt::Error) -> Self {
572 Self::FmtError
573 }
574}
575
576pub struct HirDisplayWrapper<'a, 'db, T> {
577 db: &'db dyn HirDatabase,
578 t: &'a T,
579 max_size: Option<usize>,
580 limited_size: Option<usize>,
581 omit_verbose_types: bool,
582 closure_style: ClosureStyle,
583 display_kind: DisplayKind,
584 display_target: DisplayTarget,
585 show_container_bounds: bool,
586 render_private_fields: bool,
587 display_lifetimes: DisplayLifetime,
588}
589
590#[derive(Debug, PartialEq, Eq, Clone, Copy)]
591pub enum ClosureStyle {
592 ImplFn,
595 RANotation,
597 ClosureWithId,
599 ClosureWithSubst,
601 Hide,
603}
604
605impl<'db, T: HirDisplay<'db>> HirDisplayWrapper<'_, 'db, T> {
606 pub fn write_to<F: HirWrite>(&self, f: &mut F) -> Result {
607 let krate = self.display_target.krate;
608 let interner = DbInterner::new_with(self.db, krate);
609 self.t.hir_fmt(&mut HirFormatter {
610 db: self.db,
611 interner,
612 fmt: f,
613 buf: String::with_capacity(self.max_size.unwrap_or(20)),
614 curr_size: 0,
615 max_size: self.max_size,
616 entity_limit: self.limited_size,
617 omit_verbose_types: self.omit_verbose_types,
618 display_kind: self.display_kind,
619 display_target: self.display_target,
620 closure_style: self.closure_style,
621 show_container_bounds: self.show_container_bounds,
622 render_private_fields: self.render_private_fields,
623 display_lifetimes: self.display_lifetimes,
624 currently_formatting_bounds: Default::default(),
625 trait_bounds_need_parens: false,
626 })
627 }
628
629 pub fn with_closure_style(mut self, c: ClosureStyle) -> Self {
630 self.closure_style = c;
631 self
632 }
633
634 pub fn with_lifetime_display(mut self, l: DisplayLifetime) -> Self {
635 self.display_lifetimes = l;
636 self
637 }
638
639 pub fn with_private_fields(mut self, render: bool) -> Self {
640 self.render_private_fields = render;
641 self
642 }
643}
644
645impl<'db, T> fmt::Display for HirDisplayWrapper<'_, 'db, T>
646where
647 T: HirDisplay<'db>,
648{
649 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
650 match self.write_to(f) {
651 Ok(()) => Ok(()),
652 Err(HirDisplayError::FmtError) => Err(fmt::Error),
653 Err(HirDisplayError::DisplaySourceCodeError(_)) => {
654 panic!(
656 "HirDisplay::hir_fmt failed with DisplaySourceCodeError when calling Display::fmt!"
657 )
658 }
659 }
660 }
661}
662
663const TYPE_HINT_TRUNCATION: &str = "…";
664
665impl<'db, T: HirDisplay<'db>> HirDisplay<'db> for &T {
666 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
667 HirDisplay::hir_fmt(*self, f)
668 }
669}
670
671impl<'db, T: HirDisplay<'db> + Internable> HirDisplay<'db> for Interned<T> {
672 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
673 HirDisplay::hir_fmt(&**self, f)
674 }
675}
676
677fn write_projection<'db>(
678 f: &mut HirFormatter<'_, 'db>,
679 alias: &AliasTy<'db>,
680 needs_parens_if_multi: bool,
681 def_id: TypeAliasId,
682) -> Result {
683 f.format_bounds_with(*alias, |f| {
684 if f.should_truncate() {
685 return write!(f, "{TYPE_HINT_TRUNCATION}");
686 }
687 let trait_ref = alias.trait_ref(f.interner);
688 let self_ty = trait_ref.self_ty();
689
690 if !f.display_kind.is_source_code()
694 && let TyKind::Param(param) = self_ty.kind()
695 {
696 let bounds = GenericPredicates::query_all(f.db, param.id.parent())
699 .iter_identity()
700 .map(Unnormalized::skip_norm_wip)
701 .filter(|wc| {
702 let ty = match wc.kind().skip_binder() {
703 ClauseKind::Trait(tr) => tr.self_ty(),
704 ClauseKind::TypeOutlives(t) => t.0,
705 _ => return false,
706 };
707 let TyKind::Alias(a) = ty.kind() else {
708 return false;
709 };
710 a == *alias
711 })
712 .collect::<Vec<_>>();
713 if !bounds.is_empty() {
714 return write_bounds_like_dyn_trait_with_prefix(
715 f,
716 "impl",
717 Either::Left(Ty::new_alias(f.interner, *alias)),
718 &bounds,
719 SizedByDefault::NotSized,
720 needs_parens_if_multi,
721 );
722 }
723 }
724
725 write!(f, "<")?;
726 self_ty.hir_fmt(f)?;
727 write!(f, " as ")?;
728 trait_ref.hir_fmt(f)?;
729 write!(f, ">::{}", TypeAliasSignature::of(f.db, def_id).name.display(f.db, f.edition()))?;
730 let proj_params = &alias.args.as_slice()[trait_ref.args.len()..];
731 hir_fmt_generics(f, proj_params, None, None)
732 })
733}
734
735impl<'db> HirDisplay<'db> for GenericArg<'db> {
736 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
737 match self.kind() {
738 GenericArgKind::Type(ty) => ty.hir_fmt(f),
739 GenericArgKind::Lifetime(lt) => lt.hir_fmt(f),
740 GenericArgKind::Const(c) => c.hir_fmt(f),
741 }
742 }
743}
744
745impl<'db> HirDisplay<'db> for Allocation<'db> {
746 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
747 render_const_scalar(f, &self.memory, &self.memory_map, self.ty)
748 }
749}
750
751impl<'db> HirDisplay<'db> for Const<'db> {
752 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
753 match self.kind() {
754 ConstKind::Placeholder(_) => write!(f, "<placeholder>"),
755 ConstKind::Bound(BoundVarIndexKind::Bound(db), bound_const) => {
756 write!(f, "?{}.{}", db.as_u32(), bound_const.var.as_u32())
757 }
758 ConstKind::Bound(BoundVarIndexKind::Canonical, bound_const) => {
759 write!(f, "?c.{}", bound_const.var.as_u32())
760 }
761 ConstKind::Infer(..) => write!(f, "#c#"),
762 ConstKind::Param(param) => {
763 let generics = GenericParams::of(f.db, param.id.parent());
764 let param_data = &generics[param.id.local_id()];
765 f.start_location_link_generic(param.id.into());
766 write!(f, "{}", param_data.name().unwrap().display(f.db, f.edition()))?;
767 f.end_location_link();
768 Ok(())
769 }
770 ConstKind::Value(value) => render_const_scalar_from_valtree(f, value.ty, value.value),
771 ConstKind::Unevaluated(unev) => {
772 let c = unev.def.0;
773 let generic_def = match c {
774 GeneralConstId::ConstId(id) => {
775 match &ConstSignature::of(f.db, id).name {
776 Some(name) => {
777 f.start_location_link(id.into());
778 write!(f, "{}", name.display(f.db, f.edition()))?;
779 f.end_location_link();
780 }
781 None => f.write_str("_")?,
782 }
783 Some(id.into())
784 }
785 GeneralConstId::StaticId(id) => {
786 let name = &StaticSignature::of(f.db, id).name;
787 f.start_location_link(id.into());
788 write!(f, "{}", name.display(f.db, f.edition()))?;
789 f.end_location_link();
790 Some(id.into())
791 }
792 GeneralConstId::AnonConstId(_) => {
793 f.write_str(if f.display_kind.is_source_code() { "_" } else { "{const}" })?;
794 None
795 }
796 };
797 if let Some(generic_def) = generic_def {
798 hir_fmt_generics(f, unev.args.as_slice(), Some(generic_def), None)?;
799 }
800 Ok(())
801 }
802 ConstKind::Error(..) => f.write_char('_'),
803 ConstKind::Expr(..) => write!(f, "<const-expr>"),
804 }
805 }
806}
807
808fn render_const_scalar<'db>(
809 f: &mut HirFormatter<'_, 'db>,
810 b: &[u8],
811 memory_map: &MemoryMap<'db>,
812 ty: Ty<'db>,
813) -> Result {
814 let param_env = ParamEnv::empty(f.interner);
815 let infcx = f.interner.infer_ctxt().build(TypingMode::PostAnalysis);
816 let ty = infcx.at(&ObligationCause::dummy(), param_env).deeply_normalize(ty).unwrap_or(ty);
817 render_const_scalar_inner(f, b, memory_map, ty, param_env)
818}
819
820fn render_const_scalar_inner<'db>(
821 f: &mut HirFormatter<'_, 'db>,
822 b: &[u8],
823 memory_map: &MemoryMap<'db>,
824 ty: Ty<'db>,
825 param_env: ParamEnv<'db>,
826) -> Result {
827 use TyKind;
828 let param_env = ParamEnvAndCrate { param_env, krate: f.krate() };
829 match ty.kind() {
830 TyKind::Bool => write!(f, "{}", b[0] != 0),
831 TyKind::Char => {
832 let it = u128::from_le_bytes(pad16(b, IsSigned::No)) as u32;
833 let Ok(c) = char::try_from(it) else {
834 return f.write_str("<unicode-error>");
835 };
836 write!(f, "{c:?}")
837 }
838 TyKind::Int(_) => {
839 let it = i128::from_le_bytes(pad16(b, IsSigned::Yes));
840 write!(f, "{it}")
841 }
842 TyKind::Uint(_) => {
843 let it = u128::from_le_bytes(pad16(b, IsSigned::No));
844 write!(f, "{it}")
845 }
846 TyKind::Float(fl) => match fl {
847 FloatTy::F16 => {
848 let it = f16::from_bits(u16::from_le_bytes(b.try_into().unwrap()).into());
850 let s = it.to_string();
851 if s.strip_prefix('-').unwrap_or(&s).chars().all(|c| c.is_ascii_digit()) {
852 write!(f, "{s}.0")
854 } else {
855 write!(f, "{s}")
856 }
857 }
858 FloatTy::F32 => {
859 let it = f32::from_le_bytes(b.try_into().unwrap());
860 write!(f, "{it:?}")
861 }
862 FloatTy::F64 => {
863 let it = f64::from_le_bytes(b.try_into().unwrap());
864 write!(f, "{it:?}")
865 }
866 FloatTy::F128 => {
867 let it = f128::from_bits(u128::from_le_bytes(b.try_into().unwrap()));
869 let s = it.to_string();
870 if s.strip_prefix('-').unwrap_or(&s).chars().all(|c| c.is_ascii_digit()) {
871 write!(f, "{s}.0")
873 } else {
874 write!(f, "{s}")
875 }
876 }
877 },
878 TyKind::Ref(_, t, _) => match t.kind() {
879 TyKind::Str => {
880 let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap());
881 let size = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap());
882 let Some(bytes) = memory_map.get(addr, size) else {
883 return f.write_str("<ref-data-not-available>");
884 };
885 let s = std::str::from_utf8(bytes).unwrap_or("<utf8-error>");
886 write!(f, "{s:?}")
887 }
888 TyKind::Slice(ty) => {
889 let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap());
890 let count = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap());
891 let Ok(layout) = f.db.layout_of_ty(ty.store(), param_env.store()) else {
892 return f.write_str("<layout-error>");
893 };
894 let size_one = layout.size.bytes_usize();
895 let Some(bytes) = memory_map.get(addr, size_one * count) else {
896 return f.write_str("<ref-data-not-available>");
897 };
898 let expected_len = count * size_one;
899 if bytes.len() < expected_len {
900 never!(
901 "Memory map size is too small. Expected {expected_len}, got {}",
902 bytes.len(),
903 );
904 return f.write_str("<layout-error>");
905 }
906 f.write_str("&[")?;
907 let mut first = true;
908 for i in 0..count {
909 if first {
910 first = false;
911 } else {
912 f.write_str(", ")?;
913 }
914 let offset = size_one * i;
915 render_const_scalar(f, &bytes[offset..offset + size_one], memory_map, ty)?;
916 }
917 f.write_str("]")
918 }
919 TyKind::Dynamic(_, _) => {
920 let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap());
921 let ty_id = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap());
922 let Ok(t) = memory_map.vtable_ty(ty_id) else {
923 return f.write_str("<ty-missing-in-vtable-map>");
924 };
925 let Ok(layout) = f.db.layout_of_ty(t.store(), param_env.store()) else {
926 return f.write_str("<layout-error>");
927 };
928 let size = layout.size.bytes_usize();
929 let Some(bytes) = memory_map.get(addr, size) else {
930 return f.write_str("<ref-data-not-available>");
931 };
932 f.write_str("&")?;
933 render_const_scalar(f, bytes, memory_map, t)
934 }
935 TyKind::Adt(adt, _) if b.len() == 2 * size_of::<usize>() => match adt.def_id() {
936 hir_def::AdtId::StructId(s) => {
937 let data = StructSignature::of(f.db, s);
938 write!(f, "&{}", data.name.display(f.db, f.edition()))?;
939 Ok(())
940 }
941 _ => f.write_str("<unsized-enum-or-union>"),
942 },
943 _ => {
944 let addr = usize::from_le_bytes(match b.try_into() {
945 Ok(b) => b,
946 Err(_) => {
947 never!(
948 "tried rendering ty {:?} in const ref with incorrect byte count {}",
949 t,
950 b.len()
951 );
952 return f.write_str("<layout-error>");
953 }
954 });
955 let Ok(layout) = f.db.layout_of_ty(t.store(), param_env.store()) else {
956 return f.write_str("<layout-error>");
957 };
958 let size = layout.size.bytes_usize();
959 let Some(bytes) = memory_map.get(addr, size) else {
960 return f.write_str("<ref-data-not-available>");
961 };
962 f.write_str("&")?;
963 render_const_scalar(f, bytes, memory_map, t)
964 }
965 },
966 TyKind::Tuple(tys) => {
967 let Ok(layout) = f.db.layout_of_ty(ty.store(), param_env.store()) else {
968 return f.write_str("<layout-error>");
969 };
970 f.write_str("(")?;
971 let mut first = true;
972 for (id, ty) in tys.iter().enumerate() {
973 if first {
974 first = false;
975 } else {
976 f.write_str(", ")?;
977 }
978 let offset = layout.fields.offset(id).bytes_usize();
979 let Ok(layout) = f.db.layout_of_ty(ty.store(), param_env.store()) else {
980 f.write_str("<layout-error>")?;
981 continue;
982 };
983 let size = layout.size.bytes_usize();
984 render_const_scalar(f, &b[offset..offset + size], memory_map, ty)?;
985 }
986 f.write_str(")")
987 }
988 TyKind::Adt(def, args) => {
989 let def = def.def_id();
990 let Ok(layout) = f.db.layout_of_adt(def, args.store(), param_env.store()) else {
991 return f.write_str("<layout-error>");
992 };
993 match def {
994 hir_def::AdtId::StructId(s) => {
995 let data = StructSignature::of(f.db, s);
996 write!(f, "{}", data.name.display(f.db, f.edition()))?;
997 let field_types = f.db.field_types(s.into());
998 render_variant_after_name(
999 s.fields(f.db),
1000 f,
1001 field_types,
1002 f.db.trait_environment(def.into()),
1003 &layout,
1004 args,
1005 b,
1006 memory_map,
1007 )
1008 }
1009 hir_def::AdtId::UnionId(u) => {
1010 write!(f, "{}", UnionSignature::of(f.db, u).name.display(f.db, f.edition()))
1011 }
1012 hir_def::AdtId::EnumId(e) => {
1013 let Ok(target_data_layout) = f.db.target_data_layout(f.krate()) else {
1014 return f.write_str("<target-layout-not-available>");
1015 };
1016 let Some((var_id, var_layout)) =
1017 detect_variant_from_bytes(&layout, f.db, target_data_layout, b, e)
1018 else {
1019 return f.write_str("<failed-to-detect-variant>");
1020 };
1021 let loc = var_id.lookup(f.db);
1022 write!(f, "{}", loc.name.display(f.db, f.edition()))?;
1023 let field_types = f.db.field_types(var_id.into());
1024 render_variant_after_name(
1025 var_id.fields(f.db),
1026 f,
1027 field_types,
1028 f.db.trait_environment(def.into()),
1029 var_layout,
1030 args,
1031 b,
1032 memory_map,
1033 )
1034 }
1035 }
1036 }
1037 TyKind::FnDef(..) => ty.hir_fmt(f),
1038 TyKind::FnPtr(_, _) | TyKind::RawPtr(_, _) => {
1039 let it = u128::from_le_bytes(pad16(b, IsSigned::No));
1040 write!(f, "{it:#X} as ")?;
1041 ty.hir_fmt(f)
1042 }
1043 TyKind::Array(ty, len) => {
1044 let Some(len) = consteval::try_const_usize(f.db, len) else {
1045 return f.write_str("<unknown-array-len>");
1046 };
1047 let Ok(layout) = f.db.layout_of_ty(ty.store(), param_env.store()) else {
1048 return f.write_str("<layout-error>");
1049 };
1050 let size_one = layout.size.bytes_usize();
1051 f.write_str("[")?;
1052 let mut first = true;
1053 for i in 0..len as usize {
1054 if first {
1055 first = false;
1056 } else {
1057 f.write_str(", ")?;
1058 }
1059 let offset = size_one * i;
1060 render_const_scalar(f, &b[offset..offset + size_one], memory_map, ty)?;
1061 }
1062 f.write_str("]")
1063 }
1064 TyKind::Never => f.write_str("!"),
1065 TyKind::Closure(_, _) => f.write_str("<closure>"),
1066 TyKind::Coroutine(_, _) => f.write_str("<coroutine>"),
1067 TyKind::CoroutineWitness(_, _) => f.write_str("<coroutine-witness>"),
1068 TyKind::CoroutineClosure(_, _) => f.write_str("<coroutine-closure>"),
1069 TyKind::UnsafeBinder(_) => f.write_str("<unsafe-binder>"),
1070 TyKind::Foreign(_) => f.write_str("<extern-type>"),
1072 TyKind::Pat(_, _) => f.write_str("<pat>"),
1073 TyKind::Error(..)
1074 | TyKind::Placeholder(_)
1075 | TyKind::Alias(..)
1076 | TyKind::Param(_)
1077 | TyKind::Bound(_, _)
1078 | TyKind::Infer(_) => f.write_str("<placeholder-or-unknown-type>"),
1079 TyKind::Slice(_) | TyKind::Str | TyKind::Dynamic(_, _) => f.write_str("<unsized-value>"),
1081 }
1082}
1083
1084fn render_const_scalar_from_valtree<'db>(
1085 f: &mut HirFormatter<'_, 'db>,
1086 ty: Ty<'db>,
1087 valtree: ValTree<'db>,
1088) -> Result {
1089 let param_env = ParamEnv::empty(f.interner);
1090 let infcx = f.interner.infer_ctxt().build(TypingMode::PostAnalysis);
1091 let ty = infcx.at(&ObligationCause::dummy(), param_env).deeply_normalize(ty).unwrap_or(ty);
1092 render_const_scalar_from_valtree_inner(f, ty, valtree, param_env)
1093}
1094
1095fn render_const_scalar_from_valtree_inner<'db>(
1096 f: &mut HirFormatter<'_, 'db>,
1097 ty: Ty<'db>,
1098 valtree: ValTree<'db>,
1099 _param_env: ParamEnv<'db>,
1100) -> Result {
1101 use TyKind;
1102 match ty.kind() {
1103 TyKind::Bool => write!(f, "{}", valtree.inner().to_leaf().try_to_bool().unwrap()),
1104 TyKind::Char => {
1105 let it = valtree.inner().to_leaf().to_u32();
1106 let Ok(c) = char::try_from(it) else {
1107 return f.write_str("<unicode-error>");
1108 };
1109 write!(f, "{c:?}")
1110 }
1111 TyKind::Int(_) => {
1112 let it = valtree.inner().to_leaf().to_int_unchecked();
1113 write!(f, "{it}")
1114 }
1115 TyKind::Uint(_) => {
1116 let it = valtree.inner().to_leaf().to_uint_unchecked();
1117 write!(f, "{it}")
1118 }
1119 TyKind::Float(fl) => match fl {
1120 FloatTy::F16 => {
1121 let it = f16::from_bits(valtree.inner().to_leaf().to_u16() as u128);
1123 let s = it.to_string();
1124 if s.strip_prefix('-').unwrap_or(&s).chars().all(|c| c.is_ascii_digit()) {
1125 write!(f, "{s}.0")
1127 } else {
1128 write!(f, "{s}")
1129 }
1130 }
1131 FloatTy::F32 => {
1132 let it = f32::from_bits(valtree.inner().to_leaf().to_u32());
1133 write!(f, "{it:?}")
1134 }
1135 FloatTy::F64 => {
1136 let it = f64::from_bits(valtree.inner().to_leaf().to_u64());
1137 write!(f, "{it:?}")
1138 }
1139 FloatTy::F128 => {
1140 let it = f128::from_bits(valtree.inner().to_leaf().to_u128());
1142 let s = it.to_string();
1143 if s.strip_prefix('-').unwrap_or(&s).chars().all(|c| c.is_ascii_digit()) {
1144 write!(f, "{s}.0")
1146 } else {
1147 write!(f, "{s}")
1148 }
1149 }
1150 },
1151 TyKind::Ref(_, inner_ty, _) => {
1152 render_const_scalar_from_valtree_inner(f, inner_ty, valtree, _param_env)
1153 }
1154 TyKind::Str => {
1155 let bytes = valtree
1156 .inner()
1157 .to_branch()
1158 .iter()
1159 .map(|konst| match konst.kind() {
1160 ConstKind::Value(value) => Some(value.value.inner().to_leaf().to_u8()),
1161 _ => None,
1162 })
1163 .collect::<Option<Vec<_>>>();
1164 let Some(bytes) = bytes else { return f.write_str("<invalid-str>") };
1165 let s = std::str::from_utf8(&bytes).unwrap_or("<utf8-error>");
1166 write!(f, "{s:?}")
1167 }
1168 TyKind::Slice(inner_ty) | TyKind::Array(inner_ty, _) => {
1169 let mut first = true;
1170 write!(f, "[")?;
1171 for item in valtree.inner().to_branch() {
1172 if !first {
1173 write!(f, ", ")?;
1174 } else {
1175 first = false;
1176 }
1177 let ConstKind::Value(value) = item.kind() else {
1178 return f.write_str("<invalid-const>");
1179 };
1180 render_const_scalar_from_valtree_inner(f, inner_ty, value.value, _param_env)?;
1181 }
1182 write!(f, "]")
1183 }
1184 TyKind::Tuple(tys) => {
1185 let mut first = true;
1186 write!(f, "(")?;
1187 for (inner_ty, item) in std::iter::zip(tys, valtree.inner().to_branch()) {
1188 if !first {
1189 write!(f, ", ")?;
1190 } else {
1191 first = false;
1192 }
1193 let ConstKind::Value(value) = item.kind() else {
1194 return f.write_str("<invalid-const>");
1195 };
1196 render_const_scalar_from_valtree_inner(f, inner_ty, value.value, _param_env)?;
1197 }
1198 write!(f, ")")
1199 }
1200 TyKind::Adt(..) => {
1201 f.write_str("<adt>")
1203 }
1204 TyKind::FnDef(..) => ty.hir_fmt(f),
1205 TyKind::FnPtr(_, _) | TyKind::RawPtr(_, _) => {
1206 let it = valtree.inner().to_leaf().to_uint_unchecked();
1207 write!(f, "{it:#X} as ")?;
1208 ty.hir_fmt(f)
1209 }
1210 TyKind::Never => f.write_str("!"),
1211 TyKind::Closure(_, _) => f.write_str("<closure>"),
1212 TyKind::Coroutine(_, _) => f.write_str("<coroutine>"),
1213 TyKind::CoroutineWitness(_, _) => f.write_str("<coroutine-witness>"),
1214 TyKind::CoroutineClosure(_, _) => f.write_str("<coroutine-closure>"),
1215 TyKind::UnsafeBinder(_) => f.write_str("<unsafe-binder>"),
1216 TyKind::Foreign(_) => f.write_str("<extern-type>"),
1218 TyKind::Pat(_, _) => f.write_str("<pat>"),
1219 TyKind::Error(..)
1220 | TyKind::Placeholder(_)
1221 | TyKind::Alias(..)
1222 | TyKind::Param(_)
1223 | TyKind::Bound(_, _)
1224 | TyKind::Infer(_) => f.write_str("<placeholder-or-unknown-type>"),
1225 TyKind::Dynamic(_, _) => f.write_str("<dyn-trait>"),
1226 }
1227}
1228
1229fn render_variant_after_name<'db>(
1230 data: &VariantFields,
1231 f: &mut HirFormatter<'_, 'db>,
1232 field_types: &'db ArenaMap<LocalFieldId, FieldType>,
1233 param_env: ParamEnv<'db>,
1234 layout: &Layout,
1235 args: GenericArgs<'db>,
1236 b: &[u8],
1237 memory_map: &MemoryMap<'db>,
1238) -> Result {
1239 let param_env = ParamEnvAndCrate { param_env, krate: f.krate() };
1240 let render_field = |f: &mut HirFormatter<'_, 'db>, id: LocalFieldId| {
1241 let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize();
1242 let ty = field_types[id].ty().instantiate(f.interner, args).skip_norm_wip();
1243 let Ok(layout) = f.db.layout_of_ty(ty.store(), param_env.store()) else {
1244 return f.write_str("<layout-error>");
1245 };
1246 let size = layout.size.bytes_usize();
1247 render_const_scalar(f, &b[offset..offset + size], memory_map, ty)
1248 };
1249 match data.shape {
1250 FieldsShape::Record => {
1251 let mut it = data.fields().iter();
1252 write!(f, " {{")?;
1253 if let Some((id, data)) = it.next() {
1254 write!(f, " {}: ", data.name.display(f.db, f.edition()))?;
1255 render_field(f, id)?;
1256 }
1257 for (id, data) in it {
1258 write!(f, ", {}: ", data.name.display(f.db, f.edition()))?;
1259 render_field(f, id)?;
1260 }
1261 write!(f, " }}")?;
1262 Ok(())
1263 }
1264 FieldsShape::Tuple => {
1265 let mut it = data.fields().iter().map(|it| it.0);
1266 write!(f, "(")?;
1267 if let Some(id) = it.next() {
1268 render_field(f, id)?;
1269 }
1270 for id in it {
1271 write!(f, ", ")?;
1272 render_field(f, id)?;
1273 }
1274 write!(f, ")")?;
1275 Ok(())
1276 }
1277 FieldsShape::Unit => Ok(()),
1278 }
1279}
1280
1281impl<'db> HirDisplay<'db> for Ty<'db> {
1282 fn hir_fmt(&self, f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>) -> Result {
1283 let interner = f.interner;
1284 if f.should_truncate() {
1285 return write!(f, "{TYPE_HINT_TRUNCATION}");
1286 }
1287
1288 let trait_bounds_need_parens = mem::replace(&mut f.trait_bounds_need_parens, false);
1289 match self.kind() {
1290 TyKind::Never => write!(f, "!")?,
1291 TyKind::Str => write!(f, "str")?,
1292 TyKind::Bool => write!(f, "bool")?,
1293 TyKind::Char => write!(f, "char")?,
1294 TyKind::Float(t) => write!(f, "{}", primitive::float_ty_to_string(t))?,
1295 TyKind::Int(t) => write!(f, "{}", primitive::int_ty_to_string(t))?,
1296 TyKind::Uint(t) => write!(f, "{}", primitive::uint_ty_to_string(t))?,
1297 TyKind::Slice(t) => {
1298 write!(f, "[")?;
1299 t.hir_fmt(f)?;
1300 write!(f, "]")?;
1301 }
1302 TyKind::Array(t, c) => {
1303 write!(f, "[")?;
1304 t.hir_fmt(f)?;
1305 write!(f, "; ")?;
1306 c.hir_fmt(f)?;
1307 write!(f, "]")?;
1308 }
1309 TyKind::Ref(l, t, m) => {
1310 f.write_char('&')?;
1311 if f.render_region(l) {
1312 l.hir_fmt(f)?;
1313 f.write_char(' ')?;
1314 }
1315 match m {
1316 rustc_ast_ir::Mutability::Not => (),
1317 rustc_ast_ir::Mutability::Mut => f.write_str("mut ")?,
1318 }
1319
1320 f.trait_bounds_need_parens = true;
1321 t.hir_fmt(f)?;
1322 f.trait_bounds_need_parens = false;
1323 }
1324 TyKind::RawPtr(t, m) => {
1325 write!(
1326 f,
1327 "*{}",
1328 match m {
1329 rustc_ast_ir::Mutability::Not => "const ",
1330 rustc_ast_ir::Mutability::Mut => "mut ",
1331 }
1332 )?;
1333
1334 f.trait_bounds_need_parens = true;
1335 t.hir_fmt(f)?;
1336 f.trait_bounds_need_parens = false;
1337 }
1338 TyKind::Tuple(tys) => {
1339 if tys.len() == 1 {
1340 write!(f, "(")?;
1341 tys.as_slice()[0].hir_fmt(f)?;
1342 write!(f, ",)")?;
1343 } else {
1344 write!(f, "(")?;
1345 f.write_joined(tys.as_slice(), ", ")?;
1346 write!(f, ")")?;
1347 }
1348 }
1349 TyKind::FnPtr(sig, header) => {
1350 let sig = sig.with(header);
1351 sig.hir_fmt(f)?;
1352 }
1353 TyKind::FnDef(def, args) => {
1354 let def = def.0;
1355 let sig =
1356 db.callable_item_signature(def).instantiate(interner, args).skip_norm_wip();
1357
1358 if f.display_kind.is_source_code() {
1359 return sig.hir_fmt(f);
1362 }
1363 if let Safety::Unsafe = sig.safety() {
1364 write!(f, "unsafe ")?;
1365 }
1366 if !sig.abi().is_rustic_abi() {
1367 f.write_str("extern \"")?;
1368 f.write_str(sig.abi().as_str())?;
1369 f.write_str("\" ")?;
1370 }
1371
1372 let sig = sig.skip_binder();
1373 write!(f, "fn ")?;
1374 f.start_location_link(def.into());
1375 match def {
1376 CallableDefId::FunctionId(ff) => write!(
1377 f,
1378 "{}",
1379 FunctionSignature::of(db, ff).name.display(f.db, f.edition())
1380 )?,
1381 CallableDefId::StructId(s) => {
1382 write!(f, "{}", StructSignature::of(db, s).name.display(f.db, f.edition()))?
1383 }
1384 CallableDefId::EnumVariantId(e) => {
1385 let loc = e.lookup(db);
1386 write!(f, "{}", loc.name.display(db, f.edition()))?
1387 }
1388 };
1389 f.end_location_link();
1390
1391 if !args.is_empty() {
1392 let generic_def_id = GenericDefId::from_callable(db, def);
1393 let generics = generics(db, generic_def_id);
1394 let ProvenanceSplit {
1395 parent_total: parent_len,
1396 has_self_param: self_param,
1397 non_impl_trait_type_params: type_,
1398 const_params: const_,
1399 impl_trait_type_params: impl_,
1400 lifetimes: lifetime,
1401 } = generics.provenance_split();
1402 let parameters = args.as_slice();
1403 debug_assert_eq!(
1404 parameters.len(),
1405 parent_len + self_param as usize + type_ + const_ + impl_ + lifetime
1406 );
1407 if parameters.len() - impl_ > 0 {
1409 let params_len = parameters.len();
1410 let parameters =
1412 generic_args_sans_defaults(f, Some(generic_def_id), parameters);
1413 assert!(params_len >= parameters.len());
1414 let defaults = params_len - parameters.len();
1415
1416 let parent_end = if parent_len > 0 {
1424 parent_len - defaults
1427 } else {
1428 parent_len
1429 };
1430 let fn_params_no_impl_or_defaults = parameters.len() - parent_end - impl_;
1431 let (parent_params, fn_params) = parameters.split_at(parent_end);
1432
1433 write!(f, "<")?;
1434 hir_fmt_generic_arguments(f, parent_params, None)?;
1435 if !parent_params.is_empty() && !fn_params.is_empty() {
1436 write!(f, ", ")?;
1437 }
1438 hir_fmt_generic_arguments(
1439 f,
1440 &fn_params[..fn_params_no_impl_or_defaults],
1441 None,
1442 )?;
1443 write!(f, ">")?;
1444 }
1445 }
1446 write!(f, "(")?;
1447 f.write_joined(sig.inputs(), ", ")?;
1448 write!(f, ")")?;
1449 let ret = sig.output();
1450 if !ret.is_unit() {
1451 write!(f, " -> ")?;
1452 ret.hir_fmt(f)?;
1453 }
1454 }
1455 TyKind::Adt(def, parameters) => {
1456 let def_id = def.def_id();
1457 f.start_location_link(def_id.into());
1458 match f.display_kind {
1459 DisplayKind::Diagnostics | DisplayKind::Test => {
1460 let name = match def_id {
1461 hir_def::AdtId::StructId(it) => {
1462 StructSignature::of(db, it).name.clone()
1463 }
1464 hir_def::AdtId::UnionId(it) => UnionSignature::of(db, it).name.clone(),
1465 hir_def::AdtId::EnumId(it) => EnumSignature::of(db, it).name.clone(),
1466 };
1467 write!(f, "{}", name.display(f.db, f.edition()))?;
1468 }
1469 DisplayKind::SourceCode { target_module_id: module_id, allow_opaque: _ } => {
1470 if let Some(path) = find_path::find_path(
1471 db,
1472 ItemInNs::Types(def_id.into()),
1473 module_id,
1474 PrefixKind::Plain,
1475 false,
1476 FindPathConfig {
1478 prefer_no_std: false,
1479 prefer_prelude: true,
1480 prefer_absolute: false,
1481 allow_unstable: true,
1482 },
1483 ) {
1484 write!(f, "{}", path.display(f.db, f.edition()))?;
1485 } else {
1486 return Err(HirDisplayError::DisplaySourceCodeError(
1487 DisplaySourceCodeError::PathNotFound,
1488 ));
1489 }
1490 }
1491 }
1492 f.end_location_link();
1493
1494 hir_fmt_generics(f, parameters.as_slice(), Some(def.def_id().into()), None)?;
1495 }
1496 TyKind::Alias(alias_ty @ AliasTy { kind: AliasTyKind::Projection { def_id }, .. }) => {
1497 write_projection(f, &alias_ty, trait_bounds_need_parens, def_id.0)?
1498 }
1499 TyKind::Foreign(alias) => {
1500 let type_alias = TypeAliasSignature::of(db, alias.0);
1501 f.start_location_link(alias.0.into());
1502 write!(f, "{}", type_alias.name.display(f.db, f.edition()))?;
1503 f.end_location_link();
1504 }
1505 TyKind::Alias(alias_ty @ AliasTy { kind: AliasTyKind::Opaque { def_id }, .. }) => {
1506 let opaque_ty_id = def_id.0;
1507 if !f.display_kind.allows_opaque() {
1508 return Err(HirDisplayError::DisplaySourceCodeError(
1509 DisplaySourceCodeError::OpaqueType,
1510 ));
1511 }
1512 let impl_trait_id = opaque_ty_id.loc(db);
1513 let data = impl_trait_id.predicates(db);
1514 let bounds = data
1515 .iter_instantiated_copied(interner, alias_ty.args.as_slice())
1516 .map(Unnormalized::skip_norm_wip)
1517 .collect::<Vec<_>>();
1518 let krate = match impl_trait_id {
1519 ImplTraitId::ReturnTypeImplTrait(func, _) => {
1520 func.krate(db)
1521 }
1523 ImplTraitId::TypeAliasImplTrait(alias, _) => alias.krate(db),
1524 };
1525 write_bounds_like_dyn_trait_with_prefix(
1526 f,
1527 "impl",
1528 Either::Left(*self),
1529 &bounds,
1530 SizedByDefault::Sized { anchor: krate },
1531 trait_bounds_need_parens,
1532 )?;
1533 }
1534 TyKind::Closure(id, substs) => {
1535 let id = id.0;
1536 if f.display_kind.is_source_code() {
1537 if !f.display_kind.allows_opaque() {
1538 return Err(HirDisplayError::DisplaySourceCodeError(
1539 DisplaySourceCodeError::OpaqueType,
1540 ));
1541 } else if f.closure_style != ClosureStyle::ImplFn {
1542 never!("Only `impl Fn` is valid for displaying closures in source code");
1543 }
1544 }
1545 match f.closure_style {
1546 ClosureStyle::Hide => return write!(f, "{TYPE_HINT_TRUNCATION}"),
1547 ClosureStyle::ClosureWithId => {
1548 return write!(
1549 f,
1550 "{{closure#{:?}}}",
1551 salsa::plumbing::AsId::as_id(&id).index()
1552 );
1553 }
1554 ClosureStyle::ClosureWithSubst => {
1555 write!(f, "{{closure#{:?}}}", salsa::plumbing::AsId::as_id(&id).index())?;
1556 return hir_fmt_generics(f, substs.as_slice(), None, None);
1557 }
1558 _ => (),
1559 }
1560 let sig = interner.signature_unclosure(substs.as_closure().sig(), Safety::Safe);
1561 let sig = sig.skip_binder();
1562 let kind = substs.as_closure().kind();
1563 match f.closure_style {
1564 ClosureStyle::ImplFn => write!(f, "impl {kind:?}(")?,
1565 ClosureStyle::RANotation => write!(f, "|")?,
1566 _ => unreachable!(),
1567 }
1568 if sig.inputs().is_empty() {
1569 } else if f.should_truncate() {
1570 write!(f, "{TYPE_HINT_TRUNCATION}")?;
1571 } else {
1572 f.write_joined(sig.inputs(), ", ")?;
1573 };
1574 match f.closure_style {
1575 ClosureStyle::ImplFn => write!(f, ")")?,
1576 ClosureStyle::RANotation => write!(f, "|")?,
1577 _ => unreachable!(),
1578 }
1579 if f.closure_style == ClosureStyle::RANotation || !sig.output().is_unit() {
1580 write!(f, " -> ")?;
1581 sig.output().hir_fmt(f)?;
1582 }
1583 }
1584 TyKind::CoroutineClosure(id, args) => {
1585 let id = id.0;
1586 let closure_kind = match id.loc(db).kind {
1587 HirClosureKind::CoroutineClosure(kind) => kind,
1588 kind => panic!("invalid kind for coroutine closure: {kind:?}"),
1589 };
1590 let closure_label = match closure_kind {
1591 CoroutineKind::Async => "async closure",
1592 CoroutineKind::Gen => "gen closure",
1593 CoroutineKind::AsyncGen => "async gen closure",
1594 };
1595 if f.display_kind.is_source_code() {
1596 if !f.display_kind.allows_opaque() {
1597 return Err(HirDisplayError::DisplaySourceCodeError(
1598 DisplaySourceCodeError::OpaqueType,
1599 ));
1600 } else if f.closure_style != ClosureStyle::ImplFn {
1601 never!("Only `impl Fn` is valid for displaying closures in source code");
1602 }
1603 }
1604 match f.closure_style {
1605 ClosureStyle::Hide => return write!(f, "{TYPE_HINT_TRUNCATION}"),
1606 ClosureStyle::ClosureWithId => {
1607 return write!(
1608 f,
1609 "{{{closure_label}#{:?}}}",
1610 salsa::plumbing::AsId::as_id(&id).index()
1611 );
1612 }
1613 ClosureStyle::ClosureWithSubst => {
1614 write!(
1615 f,
1616 "{{{closure_label}#{:?}}}",
1617 salsa::plumbing::AsId::as_id(&id).index()
1618 )?;
1619 return hir_fmt_generics(f, args.as_slice(), None, None);
1620 }
1621 _ => (),
1622 }
1623 let callable_kind = args.as_coroutine_closure().kind();
1624 let kind = match (closure_kind, callable_kind) {
1625 (CoroutineKind::Async, rustc_type_ir::ClosureKind::Fn) => "AsyncFn",
1626 (CoroutineKind::Async, rustc_type_ir::ClosureKind::FnMut) => "AsyncFnMut",
1627 (CoroutineKind::Async, rustc_type_ir::ClosureKind::FnOnce) => "AsyncFnOnce",
1628 (_, rustc_type_ir::ClosureKind::Fn) => "Fn",
1629 (_, rustc_type_ir::ClosureKind::FnMut) => "FnMut",
1630 (_, rustc_type_ir::ClosureKind::FnOnce) => "FnOnce",
1631 };
1632 let coroutine_sig = args.as_coroutine_closure().coroutine_closure_sig();
1633 let coroutine_sig = coroutine_sig.skip_binder();
1634 let coroutine_inputs = coroutine_sig.tupled_inputs_ty.tuple_fields();
1635 let coroutine_output = coroutine_sig.return_ty;
1636 match f.closure_style {
1637 ClosureStyle::ImplFn => write!(f, "impl {kind}(")?,
1638 ClosureStyle::RANotation => match closure_kind {
1639 CoroutineKind::Async => write!(f, "async |")?,
1640 CoroutineKind::Gen => write!(f, "gen |")?,
1641 CoroutineKind::AsyncGen => write!(f, "async gen |")?,
1642 },
1643 _ => unreachable!(),
1644 }
1645 if coroutine_inputs.is_empty() {
1646 } else if f.should_truncate() {
1647 write!(f, "{TYPE_HINT_TRUNCATION}")?;
1648 } else {
1649 f.write_joined(coroutine_inputs, ", ")?;
1650 };
1651 match f.closure_style {
1652 ClosureStyle::ImplFn => write!(f, ")")?,
1653 ClosureStyle::RANotation => write!(f, "|")?,
1654 _ => unreachable!(),
1655 }
1656 if f.closure_style == ClosureStyle::RANotation || !coroutine_output.is_unit() {
1657 write!(f, " -> ")?;
1658 coroutine_output.hir_fmt(f)?;
1659 }
1660 }
1661 TyKind::Placeholder(_) => write!(f, "{{placeholder}}")?,
1662 TyKind::Param(param) => {
1663 let generics = GenericParams::of(db, param.id.parent());
1666 let param_data = &generics[param.id.local_id()];
1667 match param_data {
1668 TypeOrConstParamData::TypeParamData(p) => match p.provenance {
1669 TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
1670 f.start_location_link_generic(param.id.into());
1671 write!(
1672 f,
1673 "{}",
1674 p.name
1675 .clone()
1676 .unwrap_or_else(Name::missing)
1677 .display(f.db, f.edition())
1678 )?;
1679 f.end_location_link();
1680 }
1681 TypeParamProvenance::ArgumentImplTrait => {
1682 let bounds = GenericPredicates::query_all(f.db, param.id.parent())
1683 .iter_identity()
1684 .map(Unnormalized::skip_norm_wip)
1685 .filter(|wc| match wc.kind().skip_binder() {
1686 ClauseKind::Trait(tr) => tr.self_ty() == *self,
1687 ClauseKind::Projection(proj) => proj.self_ty() == *self,
1688 ClauseKind::TypeOutlives(to) => to.0 == *self,
1689 _ => false,
1690 })
1691 .collect::<Vec<_>>();
1692 let krate = param.id.parent().module(db).krate(db);
1693 write_bounds_like_dyn_trait_with_prefix(
1694 f,
1695 "impl",
1696 Either::Left(*self),
1697 &bounds,
1698 SizedByDefault::Sized { anchor: krate },
1699 trait_bounds_need_parens,
1700 )?;
1701 }
1702 },
1703 TypeOrConstParamData::ConstParamData(p) => {
1704 f.start_location_link_generic(param.id.into());
1705 write!(f, "{}", p.name.display(f.db, f.edition()))?;
1706 f.end_location_link();
1707 }
1708 }
1709 }
1710 TyKind::Bound(BoundVarIndexKind::Bound(debruijn), ty) => {
1711 write!(f, "?{}.{}", debruijn.as_usize(), ty.var.as_usize())?
1712 }
1713 TyKind::Bound(BoundVarIndexKind::Canonical, ty) => {
1714 write!(f, "?c.{}", ty.var.as_usize())?
1715 }
1716 TyKind::Dynamic(bounds, region) => {
1717 let self_ty = interner.default_types().types.dyn_trait_dummy_self;
1718
1719 let mut bounds_to_display = SmallVec::<[_; 4]>::new();
1721 let mut auto_trait_bounds = SmallVec::<[_; 4]>::new();
1722 for bound in bounds.iter() {
1723 let clause = bound.with_self_ty(interner, self_ty);
1724 match bound.skip_binder() {
1725 ExistentialPredicate::Trait(_) | ExistentialPredicate::Projection(_) => {
1726 bounds_to_display.push(clause);
1727 }
1728 ExistentialPredicate::AutoTrait(_) => auto_trait_bounds.push(clause),
1729 }
1730 }
1731 bounds_to_display.append(&mut auto_trait_bounds);
1732
1733 if f.render_region(region) {
1734 bounds_to_display
1735 .push(rustc_type_ir::OutlivesPredicate(self_ty, region).upcast(interner));
1736 }
1737
1738 write_bounds_like_dyn_trait_with_prefix(
1739 f,
1740 "dyn",
1741 Either::Left(self_ty),
1742 &bounds_to_display,
1743 SizedByDefault::NotSized,
1744 trait_bounds_need_parens,
1745 )?;
1746 }
1747 TyKind::Error(_) => {
1748 if f.display_kind.is_source_code() {
1749 f.write_char('_')?;
1750 } else {
1751 write!(f, "{{unknown}}")?;
1752 }
1753 }
1754 TyKind::Infer(..) => write!(f, "_")?,
1755 TyKind::Coroutine(coroutine_id, subst) => {
1756 let kind = coroutine_id.0.loc(db).kind;
1757 let CoroutineArgsParts { resume_ty, yield_ty, return_ty, .. } =
1758 subst.split_coroutine_args();
1759 match kind {
1760 HirClosureKind::Coroutine { kind: CoroutineKind::Async, .. } => {
1761 let lang_items = f.lang_items();
1762 let future_trait = lang_items.Future;
1763 let output = lang_items.FutureOutput;
1764 write!(f, "impl ")?;
1765 if let Some(t) = future_trait {
1766 f.start_location_link(t.into());
1767 }
1768 write!(f, "Future")?;
1769 if future_trait.is_some() {
1770 f.end_location_link();
1771 }
1772 write!(f, "<")?;
1773 if let Some(t) = output {
1774 f.start_location_link(t.into());
1775 }
1776 write!(f, "Output")?;
1777 if output.is_some() {
1778 f.end_location_link();
1779 }
1780 write!(f, " = ")?;
1781 return_ty.hir_fmt(f)?;
1782 write!(f, ">")?;
1783 }
1784 HirClosureKind::Coroutine { kind: CoroutineKind::Gen, .. } => {
1785 let lang_items = f.lang_items();
1786 let iterator_trait = lang_items.Iterator;
1787 let item = lang_items.IteratorItem;
1788 write!(f, "impl ")?;
1789 if let Some(t) = iterator_trait {
1790 f.start_location_link(t.into());
1791 }
1792 write!(f, "Iterator")?;
1793 if iterator_trait.is_some() {
1794 f.end_location_link();
1795 }
1796 write!(f, "<")?;
1797 if let Some(t) = item {
1798 f.start_location_link(t.into());
1799 }
1800 write!(f, "Item")?;
1801 if item.is_some() {
1802 f.end_location_link();
1803 }
1804 write!(f, " = ")?;
1805 yield_ty.hir_fmt(f)?;
1806 write!(f, ">")?;
1807 }
1808 HirClosureKind::Coroutine { kind: CoroutineKind::AsyncGen, .. } => {
1809 let lang_items = f.lang_items();
1810 let async_iterator_trait = lang_items.AsyncIterator;
1811 let item = lang_items.AsyncIteratorItem;
1812 write!(f, "impl ")?;
1813 if let Some(t) = async_iterator_trait {
1814 f.start_location_link(t.into());
1815 }
1816 write!(f, "AsyncIterator")?;
1817 if async_iterator_trait.is_some() {
1818 f.end_location_link();
1819 }
1820 write!(f, "<")?;
1821 if let Some(t) = item {
1822 f.start_location_link(t.into());
1823 }
1824 write!(f, "Item")?;
1825 if item.is_some() {
1826 f.end_location_link();
1827 }
1828 write!(f, " = ")?;
1829 let item_ty = async_gen_item_ty_from_yield_ty(f.lang_items(), yield_ty)
1830 .unwrap_or(yield_ty);
1831 item_ty.hir_fmt(f)?;
1832 write!(f, ">")?;
1833 }
1834 HirClosureKind::OldCoroutine(..) => {
1835 if f.display_kind.is_source_code() {
1836 return Err(HirDisplayError::DisplaySourceCodeError(
1837 DisplaySourceCodeError::Coroutine,
1838 ));
1839 }
1840 write!(f, "|")?;
1841 resume_ty.hir_fmt(f)?;
1842 write!(f, "|")?;
1843
1844 write!(f, " yields ")?;
1845 yield_ty.hir_fmt(f)?;
1846
1847 write!(f, " -> ")?;
1848 return_ty.hir_fmt(f)?;
1849 }
1850 _ => panic!("invalid kind for coroutine: {kind:?}"),
1851 }
1852 }
1853 TyKind::CoroutineWitness(..) => write!(f, "{{coroutine witness}}")?,
1854 TyKind::Pat(_, _) => write!(f, "{{pat}}")?,
1855 TyKind::UnsafeBinder(_) => write!(f, "{{unsafe binder}}")?,
1856 TyKind::Alias(..) => write!(f, "{{alias}}")?,
1857 }
1858 Ok(())
1859 }
1860}
1861
1862fn hir_fmt_generics<'db>(
1863 f: &mut HirFormatter<'_, 'db>,
1864 parameters: &[GenericArg<'db>],
1865 generic_def: Option<hir_def::GenericDefId>,
1866 self_: Option<Ty<'db>>,
1867) -> Result {
1868 if parameters.is_empty() {
1869 return Ok(());
1870 }
1871
1872 let parameters_to_write = generic_args_sans_defaults(f, generic_def, parameters);
1873
1874 if !parameters_to_write.is_empty() {
1875 write!(f, "<")?;
1876 hir_fmt_generic_arguments(f, parameters_to_write, self_)?;
1877 write!(f, ">")?;
1878 }
1879
1880 Ok(())
1881}
1882
1883fn generic_args_sans_defaults<'ga, 'db>(
1884 f: &mut HirFormatter<'_, 'db>,
1885 generic_def: Option<hir_def::GenericDefId>,
1886 parameters: &'ga [GenericArg<'db>],
1887) -> &'ga [GenericArg<'db>] {
1888 if f.display_kind.is_source_code() || f.omit_verbose_types() {
1889 match generic_def.map(|generic_def_id| f.db.generic_defaults(generic_def_id)) {
1890 None => parameters,
1891 Some(default_parameters) => {
1892 let should_show = |arg: GenericArg<'db>, i: usize| match default_parameters.get(i) {
1893 None => true,
1894 Some(default_parameter) => {
1895 arg != default_parameter
1896 .instantiate(f.interner, ¶meters[..i])
1897 .skip_norm_wip()
1898 }
1899 };
1900 let mut default_from = 0;
1901 for (i, ¶meter) in parameters.iter().enumerate() {
1902 if should_show(parameter, i) {
1903 default_from = i + 1;
1904 }
1905 }
1906 ¶meters[0..default_from]
1907 }
1908 }
1909 } else {
1910 parameters
1911 }
1912}
1913
1914fn hir_fmt_generic_args<'db>(
1915 f: &mut HirFormatter<'_, 'db>,
1916 parameters: &[GenericArg<'db>],
1917 generic_def: Option<hir_def::GenericDefId>,
1918 self_: Option<Ty<'db>>,
1919) -> Result {
1920 if parameters.is_empty() {
1921 return Ok(());
1922 }
1923
1924 let parameters_to_write = generic_args_sans_defaults(f, generic_def, parameters);
1925
1926 if !parameters_to_write.is_empty() {
1927 write!(f, "<")?;
1928 hir_fmt_generic_arguments(f, parameters_to_write, self_)?;
1929 write!(f, ">")?;
1930 }
1931
1932 Ok(())
1933}
1934
1935fn hir_fmt_generic_arguments<'db>(
1936 f: &mut HirFormatter<'_, 'db>,
1937 parameters: &[GenericArg<'db>],
1938 self_: Option<Ty<'db>>,
1939) -> Result {
1940 let mut first = true;
1941 let lifetime_offset = parameters.iter().position(|arg| arg.region().is_some());
1942
1943 let (ty_or_const, lifetimes) = match lifetime_offset {
1944 Some(offset) => parameters.split_at(offset),
1945 None => (parameters, &[][..]),
1946 };
1947 for generic_arg in lifetimes.iter().chain(ty_or_const) {
1948 if !mem::take(&mut first) {
1949 write!(f, ", ")?;
1950 }
1951 match self_ {
1952 self_ @ Some(_) if generic_arg.ty() == self_ => write!(f, "Self")?,
1953 _ => generic_arg.hir_fmt(f)?,
1954 }
1955 }
1956 Ok(())
1957}
1958
1959fn hir_fmt_tys<'db>(
1960 f: &mut HirFormatter<'_, 'db>,
1961 tys: &[Ty<'db>],
1962 self_: Option<Ty<'db>>,
1963) -> Result {
1964 let mut first = true;
1965
1966 for ty in tys {
1967 if !mem::take(&mut first) {
1968 write!(f, ", ")?;
1969 }
1970 match self_ {
1971 Some(self_) if *ty == self_ => write!(f, "Self")?,
1972 _ => ty.hir_fmt(f)?,
1973 }
1974 }
1975 Ok(())
1976}
1977
1978impl<'db> HirDisplay<'db> for PolyFnSig<'db> {
1979 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
1980 let FnSig { inputs_and_output, fn_sig_kind } = self.skip_binder();
1981 if let Safety::Unsafe = fn_sig_kind.safety() {
1982 write!(f, "unsafe ")?;
1983 }
1984 let abi = self.abi();
1985 if !matches!(abi, ExternAbi::Rust) {
1986 f.write_str("extern \"")?;
1987 f.write_str(abi.as_str())?;
1988 f.write_str("\" ")?;
1989 }
1990 write!(f, "fn(")?;
1991 f.write_joined(inputs_and_output.inputs(), ", ")?;
1992 if fn_sig_kind.c_variadic() {
1993 if inputs_and_output.inputs().is_empty() {
1994 write!(f, "...")?;
1995 } else {
1996 write!(f, ", ...")?;
1997 }
1998 }
1999 write!(f, ")")?;
2000 let ret = inputs_and_output.output();
2001 if !ret.is_unit() {
2002 write!(f, " -> ")?;
2003 ret.hir_fmt(f)?;
2004 }
2005 Ok(())
2006 }
2007}
2008
2009impl<'db> HirDisplay<'db> for Term<'db> {
2010 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
2011 match self.kind() {
2012 TermKind::Ty(it) => it.hir_fmt(f),
2013 TermKind::Const(it) => it.hir_fmt(f),
2014 }
2015 }
2016}
2017
2018#[derive(Clone, Copy, PartialEq, Eq)]
2019pub enum SizedByDefault {
2020 NotSized,
2021 Sized { anchor: Crate },
2022}
2023
2024impl SizedByDefault {
2025 fn is_sized_trait(self, trait_: TraitId, interner: DbInterner<'_>) -> bool {
2026 match self {
2027 Self::NotSized => false,
2028 Self::Sized { .. } => {
2029 let sized_trait = interner.lang_items().Sized;
2030 Some(trait_) == sized_trait
2031 }
2032 }
2033 }
2034}
2035
2036pub fn write_bounds_like_dyn_trait_with_prefix<'db>(
2037 f: &mut HirFormatter<'_, 'db>,
2038 prefix: &str,
2039 this: Either<Ty<'db>, Region<'db>>,
2040 predicates: &[Clause<'db>],
2041 default_sized: SizedByDefault,
2042 needs_parens_if_multi: bool,
2043) -> Result {
2044 let needs_parens =
2045 needs_parens_if_multi && trait_bounds_need_parens(f, this, predicates, default_sized);
2046 if needs_parens {
2047 write!(f, "(")?;
2048 }
2049 write!(f, "{prefix}")?;
2050 if !predicates.is_empty()
2051 || predicates.is_empty() && matches!(default_sized, SizedByDefault::Sized { .. })
2052 {
2053 write!(f, " ")?;
2054 write_bounds_like_dyn_trait(f, this, predicates, default_sized)?;
2055 }
2056 if needs_parens {
2057 write!(f, ")")?;
2058 }
2059 Ok(())
2060}
2061
2062fn trait_bounds_need_parens<'db>(
2063 f: &mut HirFormatter<'_, 'db>,
2064 this: Either<Ty<'db>, Region<'db>>,
2065 predicates: &[Clause<'db>],
2066 default_sized: SizedByDefault,
2067) -> bool {
2068 let mut distinct_bounds = 0usize;
2070 let mut is_sized = false;
2071 for p in predicates {
2072 match p.kind().skip_binder() {
2073 ClauseKind::Trait(trait_ref) => {
2074 let trait_ = trait_ref.def_id().0;
2075 if default_sized.is_sized_trait(trait_, f.interner) {
2076 is_sized = true;
2077 if matches!(default_sized, SizedByDefault::Sized { .. }) {
2078 continue;
2080 }
2081 }
2082
2083 distinct_bounds += 1;
2084 }
2085 ClauseKind::TypeOutlives(to) if Either::Left(to.0) == this => distinct_bounds += 1,
2086 ClauseKind::RegionOutlives(lo) if Either::Right(lo.0) == this => distinct_bounds += 1,
2087 _ => {}
2088 }
2089 }
2090
2091 if let SizedByDefault::Sized { .. } = default_sized
2092 && !is_sized
2093 {
2094 distinct_bounds += 1;
2095 }
2096
2097 distinct_bounds > 1
2098}
2099
2100fn write_bounds_like_dyn_trait<'db>(
2101 f: &mut HirFormatter<'_, 'db>,
2102 this: Either<Ty<'db>, Region<'db>>,
2103 predicates: &[Clause<'db>],
2104 default_sized: SizedByDefault,
2105) -> Result {
2106 let mut first = true;
2113 let mut angle_open = false;
2114 let mut is_fn_trait = false;
2115 let mut is_sized = false;
2116 for p in predicates {
2117 match p.kind().skip_binder() {
2118 ClauseKind::Trait(trait_ref) => {
2119 let trait_ = trait_ref.def_id().0;
2120 if default_sized.is_sized_trait(trait_, f.interner) {
2121 is_sized = true;
2122 if matches!(default_sized, SizedByDefault::Sized { .. }) {
2123 continue;
2125 }
2126 }
2127 if !is_fn_trait {
2128 is_fn_trait = fn_traits(f.lang_items()).any(|it| it == trait_);
2129 }
2130 if !is_fn_trait && angle_open {
2131 write!(f, ">")?;
2132 angle_open = false;
2133 }
2134 if !first {
2135 write!(f, " + ")?;
2136 }
2137 f.start_location_link(trait_.into());
2141 write!(f, "{}", TraitSignature::of(f.db, trait_).name.display(f.db, f.edition()))?;
2142 f.end_location_link();
2143 if is_fn_trait {
2144 if let [_self, params @ ..] = trait_ref.trait_ref.args.as_slice()
2145 && let Some(args) = params.first().and_then(|it| it.ty()?.as_tuple())
2146 {
2147 write!(f, "(")?;
2148 hir_fmt_tys(f, args.as_slice(), Some(trait_ref.trait_ref.self_ty()))?;
2149 write!(f, ")")?;
2150 }
2151 } else {
2152 let params = generic_args_sans_defaults(
2153 f,
2154 Some(trait_.into()),
2155 trait_ref.trait_ref.args.as_slice(),
2156 );
2157 if let [_self, params @ ..] = params
2158 && !params.is_empty()
2159 {
2160 write!(f, "<")?;
2161 hir_fmt_generic_arguments(f, params, Some(trait_ref.trait_ref.self_ty()))?;
2162 angle_open = true;
2164 }
2165 }
2166 }
2167 ClauseKind::TypeOutlives(to) if Either::Left(to.0) == this => {
2168 if !is_fn_trait && angle_open {
2169 write!(f, ">")?;
2170 angle_open = false;
2171 }
2172 if !first {
2173 write!(f, " + ")?;
2174 }
2175 to.1.hir_fmt(f)?;
2176 }
2177 ClauseKind::RegionOutlives(lo) if Either::Right(lo.0) == this => {
2178 if !is_fn_trait && angle_open {
2179 write!(f, ">")?;
2180 angle_open = false;
2181 }
2182 if !first {
2183 write!(f, " + ")?;
2184 }
2185 lo.1.hir_fmt(f)?;
2186 }
2187 ClauseKind::Projection(projection) if is_fn_trait => {
2188 is_fn_trait = false;
2189 if !projection.term.as_type().is_some_and(|it| it.is_unit()) {
2190 write!(f, " -> ")?;
2191 projection.term.hir_fmt(f)?;
2192 }
2193 }
2194 ClauseKind::Projection(projection) => {
2195 let TermId::TypeAliasId(assoc_ty_id) = projection.def_id().0 else {
2196 continue;
2197 };
2198 if angle_open {
2201 write!(f, ", ")?;
2202 } else {
2203 write!(f, "<")?;
2204 angle_open = true;
2205 }
2206 let type_alias = TypeAliasSignature::of(f.db, assoc_ty_id);
2207 f.start_location_link(assoc_ty_id.into());
2208 write!(f, "{}", type_alias.name.display(f.db, f.edition()))?;
2209 f.end_location_link();
2210
2211 let own_args = projection.projection_term.own_args(f.interner);
2212 if !own_args.is_empty() {
2213 write!(f, "<")?;
2214 hir_fmt_generic_arguments(f, own_args, None)?;
2215 write!(f, ">")?;
2216 }
2217 write!(f, " = ")?;
2218 projection.term.hir_fmt(f)?;
2219 }
2220 _ => {}
2221 }
2222 first = false;
2223 }
2224 if angle_open {
2225 write!(f, ">")?;
2226 }
2227 if let SizedByDefault::Sized { anchor } = default_sized {
2228 let sized_trait = hir_def::lang_item::lang_items(f.db, anchor).Sized;
2229 if !is_sized {
2230 if !first {
2231 write!(f, " + ")?;
2232 }
2233 if let Some(sized_trait) = sized_trait {
2234 f.start_location_link(sized_trait.into());
2235 }
2236 write!(f, "?Sized")?;
2237 } else if first {
2238 if let Some(sized_trait) = sized_trait {
2239 f.start_location_link(sized_trait.into());
2240 }
2241 write!(f, "Sized")?;
2242 }
2243 if sized_trait.is_some() {
2244 f.end_location_link();
2245 }
2246 }
2247 Ok(())
2248}
2249
2250pub fn write_params_bounds<'db>(
2251 f: &mut HirFormatter<'_, 'db>,
2252 predicates: &[Clause<'db>],
2253) -> Result {
2254 let mut per_type = FxIndexMap::<_, Vec<_>>::default();
2256 for &predicate in predicates {
2257 let base_ty = match predicate.kind().skip_binder() {
2258 ClauseKind::Trait(clause) => Either::Left(clause.self_ty()),
2259 ClauseKind::RegionOutlives(clause) => Either::Right(clause.0),
2260 ClauseKind::TypeOutlives(clause) => Either::Left(clause.0),
2261 ClauseKind::Projection(clause) => Either::Left(clause.self_ty()),
2262 ClauseKind::ConstArgHasType(..)
2263 | ClauseKind::WellFormed(_)
2264 | ClauseKind::ConstEvaluatable(_)
2265 | ClauseKind::HostEffect(..)
2266 | ClauseKind::UnstableFeature(_) => continue,
2267 };
2268 per_type.entry(base_ty).or_default().push(predicate);
2269 }
2270
2271 for (base_ty, clauses) in per_type {
2272 f.write_str(" ")?;
2273 match base_ty {
2274 Either::Left(it) => it.hir_fmt(f)?,
2275 Either::Right(it) => it.hir_fmt(f)?,
2276 }
2277 f.write_str(": ")?;
2278 let default_sized = match base_ty {
2282 Either::Left(ty) if matches!(ty.kind(), TyKind::Param(_)) => {
2283 SizedByDefault::Sized { anchor: f.krate() }
2284 }
2285 _ => SizedByDefault::NotSized,
2286 };
2287 write_bounds_like_dyn_trait(f, base_ty, &clauses, default_sized)?;
2288 f.write_str(",\n")?;
2289 }
2290 Ok(())
2291}
2292
2293impl<'db> HirDisplay<'db> for TraitRef<'db> {
2294 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
2295 let trait_ = self.def_id.0;
2296 f.start_location_link(trait_.into());
2297 write!(f, "{}", TraitSignature::of(f.db, trait_).name.display(f.db, f.edition()))?;
2298 f.end_location_link();
2299 let substs = self.args.as_slice();
2300 hir_fmt_generic_args(f, &substs[1..], None, Some(self.self_ty()))
2301 }
2302}
2303
2304impl<'db> HirDisplay<'db> for TraitPredicate<'db> {
2305 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
2306 self.self_ty().hir_fmt(f)?;
2307 f.write_str(": ")?;
2308 match self.polarity {
2309 rustc_type_ir::PredicatePolarity::Positive => {}
2310 rustc_type_ir::PredicatePolarity::Negative => f.write_char('!')?,
2311 }
2312 let trait_ = self.def_id().0;
2313 f.start_location_link(trait_.into());
2314 write!(f, "{}", TraitSignature::of(f.db, trait_).name.display(f.db, f.edition()))?;
2315 f.end_location_link();
2316 let substs = &self.trait_ref.args[1..];
2317 hir_fmt_generic_args(f, substs, None, None)
2318 }
2319}
2320
2321impl<'db> HirDisplay<'db> for Region<'db> {
2322 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
2323 match self.kind() {
2324 RegionKind::ReEarlyParam(param) => {
2325 let generics = GenericParams::of(f.db, param.id.parent);
2326 let param_data = &generics[param.id.local_id];
2327 f.start_location_link_generic(param.id.into());
2328 write!(f, "{}", param_data.name.display(f.db, f.edition()))?;
2329 f.end_location_link();
2330 Ok(())
2331 }
2332 RegionKind::ReBound(BoundVarIndexKind::Bound(db), idx) => {
2333 write!(f, "'?{}.{}", db.as_u32(), idx.var.as_u32())
2334 }
2335 RegionKind::ReBound(BoundVarIndexKind::Canonical, idx) => {
2336 write!(f, "'?c.{}", idx.var.as_u32())
2337 }
2338 RegionKind::ReVar(_) => write!(f, "_"),
2339 RegionKind::ReStatic => write!(f, "'static"),
2340 RegionKind::ReError(..) => {
2341 if cfg!(test) {
2342 write!(f, "'?")
2343 } else {
2344 write!(f, "'_")
2345 }
2346 }
2347 RegionKind::ReErased => write!(f, "'<erased>"),
2348 RegionKind::RePlaceholder(_) => write!(f, "'<placeholder>"),
2349 RegionKind::ReLateParam(_) => write!(f, "'_"),
2350 }
2351 }
2352}
2353
2354pub fn write_visibility<'db>(
2355 module_id: ModuleId,
2356 vis: Visibility,
2357 f: &mut HirFormatter<'_, 'db>,
2358) -> Result {
2359 match vis {
2360 Visibility::Public => write!(f, "pub "),
2361 Visibility::PubCrate(_) => write!(f, "pub(crate) "),
2362 Visibility::Module(vis_id, _) => {
2363 let def_map = module_id.def_map(f.db);
2364 let root_module_id = def_map.root_module_id();
2365 if vis_id == module_id {
2366 Ok(())
2368 } else if root_module_id == vis_id && root_module_id.block(f.db).is_none() {
2369 write!(f, "pub(crate) ")
2370 } else if module_id.containing_module(f.db) == Some(vis_id)
2371 && !vis_id.is_block_module(f.db)
2372 {
2373 write!(f, "pub(super) ")
2374 } else {
2375 write!(f, "pub(in ...) ")
2376 }
2377 }
2378 }
2379}
2380
2381pub trait HirDisplayWithExpressionStore<'db> {
2382 fn hir_fmt(
2383 &self,
2384 f: &mut HirFormatter<'_, 'db>,
2385 owner: ExpressionStoreOwnerId,
2386 store: &ExpressionStore,
2387 ) -> Result;
2388}
2389
2390impl<'db, T: ?Sized + HirDisplayWithExpressionStore<'db>> HirDisplayWithExpressionStore<'db>
2391 for &'_ T
2392{
2393 fn hir_fmt(
2394 &self,
2395 f: &mut HirFormatter<'_, 'db>,
2396 owner: ExpressionStoreOwnerId,
2397 store: &ExpressionStore,
2398 ) -> Result {
2399 T::hir_fmt(&**self, f, owner, store)
2400 }
2401}
2402
2403pub fn hir_display_with_store<'a, 'db, T: HirDisplayWithExpressionStore<'db> + 'a>(
2404 value: T,
2405 owner: ExpressionStoreOwnerId,
2406 store: &'a ExpressionStore,
2407) -> impl HirDisplay<'db> + 'a {
2408 ExpressionStoreAdapter(value, owner, store)
2409}
2410
2411struct ExpressionStoreAdapter<'a, T>(T, ExpressionStoreOwnerId, &'a ExpressionStore);
2412
2413impl<'a, T> ExpressionStoreAdapter<'a, T> {
2414 fn wrap(
2415 owner: ExpressionStoreOwnerId,
2416 store: &'a ExpressionStore,
2417 ) -> impl Fn(T) -> ExpressionStoreAdapter<'a, T> {
2418 move |value| ExpressionStoreAdapter(value, owner, store)
2419 }
2420}
2421
2422impl<'db, T: HirDisplayWithExpressionStore<'db>> HirDisplay<'db> for ExpressionStoreAdapter<'_, T> {
2423 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
2424 T::hir_fmt(&self.0, f, self.1, self.2)
2425 }
2426}
2427impl<'db> HirDisplayWithExpressionStore<'db> for LifetimeRefId {
2428 fn hir_fmt(
2429 &self,
2430 f: &mut HirFormatter<'_, 'db>,
2431 _owner: ExpressionStoreOwnerId,
2432 store: &ExpressionStore,
2433 ) -> Result {
2434 match &store[*self] {
2435 LifetimeRef::Named(name) => write!(f, "{}", name.display(f.db, f.edition())),
2436 LifetimeRef::Static => write!(f, "'static"),
2437 LifetimeRef::Placeholder => write!(f, "'_"),
2438 LifetimeRef::Error => write!(f, "'{{error}}"),
2439 &LifetimeRef::Param(lifetime_param_id) => {
2440 let generic_params = GenericParams::of(f.db, lifetime_param_id.parent);
2441 write!(
2442 f,
2443 "{}",
2444 generic_params[lifetime_param_id.local_id].name.display(f.db, f.edition())
2445 )
2446 }
2447 }
2448 }
2449}
2450
2451impl<'db> HirDisplayWithExpressionStore<'db> for TypeRefId {
2452 fn hir_fmt(
2453 &self,
2454 f: &mut HirFormatter<'_, 'db>,
2455 owner: ExpressionStoreOwnerId,
2456 store: &ExpressionStore,
2457 ) -> Result {
2458 match &store[*self] {
2459 TypeRef::Never => write!(f, "!")?,
2460 TypeRef::TypeParam(param) => {
2461 let generic_params = GenericParams::of(f.db, param.parent());
2462 match generic_params[param.local_id()].name() {
2463 Some(name) => write!(f, "{}", name.display(f.db, f.edition()))?,
2464 None => {
2465 write!(f, "impl ")?;
2466 f.write_joined(
2467 generic_params
2468 .where_predicates()
2469 .iter()
2470 .filter_map(|it| match it {
2471 WherePredicate::TypeBound { lifetimes: _, target, bound }
2472 if matches!(
2473 store[*target],
2474 TypeRef::TypeParam(t) if t == *param
2475 ) =>
2476 {
2477 Some(bound)
2478 }
2479 _ => None,
2480 })
2481 .map(ExpressionStoreAdapter::wrap(owner, store)),
2482 " + ",
2483 )?;
2484 }
2485 }
2486 }
2487 TypeRef::Placeholder => write!(f, "_")?,
2488 TypeRef::Tuple(elems) => {
2489 write!(f, "(")?;
2490 f.write_joined(elems.iter().map(ExpressionStoreAdapter::wrap(owner, store)), ", ")?;
2491 if elems.len() == 1 {
2492 write!(f, ",")?;
2493 }
2494 write!(f, ")")?;
2495 }
2496 TypeRef::Path(path) => path.hir_fmt(f, owner, store)?,
2497 TypeRef::RawPtr(inner, mutability) => {
2498 let mutability = match mutability {
2499 hir_def::type_ref::Mutability::Shared => "*const ",
2500 hir_def::type_ref::Mutability::Mut => "*mut ",
2501 };
2502 write!(f, "{mutability}")?;
2503 inner.hir_fmt(f, owner, store)?;
2504 }
2505 TypeRef::Reference(ref_) => {
2506 let mutability = match ref_.mutability {
2507 hir_def::type_ref::Mutability::Shared => "",
2508 hir_def::type_ref::Mutability::Mut => "mut ",
2509 };
2510 write!(f, "&")?;
2511 if let Some(lifetime) = &ref_.lifetime {
2512 lifetime.hir_fmt(f, owner, store)?;
2513 write!(f, " ")?;
2514 }
2515 write!(f, "{mutability}")?;
2516 ref_.ty.hir_fmt(f, owner, store)?;
2517 }
2518 TypeRef::Array(array) => {
2519 write!(f, "[")?;
2520 array.ty.hir_fmt(f, owner, store)?;
2521 write!(f, "; ")?;
2522 array.len.hir_fmt(f, owner, store)?;
2523 write!(f, "]")?;
2524 }
2525 TypeRef::Slice(inner) => {
2526 write!(f, "[")?;
2527 inner.hir_fmt(f, owner, store)?;
2528 write!(f, "]")?;
2529 }
2530 TypeRef::Fn(fn_) => {
2531 if let Some(binder) = &fn_.binder {
2532 let edition = f.edition();
2533 write!(
2534 f,
2535 "for<{}> ",
2536 binder.iter().map(|it| it.display(f.db, edition)).format(", ")
2537 )?;
2538 }
2539 if fn_.is_unsafe {
2540 write!(f, "unsafe ")?;
2541 }
2542 if fn_.abi != ExternAbi::Rust {
2543 f.write_str("extern \"")?;
2544 f.write_str(fn_.abi.as_str())?;
2545 f.write_str("\" ")?;
2546 }
2547 write!(f, "fn(")?;
2548 if let Some(((_, return_type), function_parameters)) = fn_.params.split_last() {
2549 for index in 0..function_parameters.len() {
2550 let (param_name, param_type) = &function_parameters[index];
2551 if let Some(name) = param_name {
2552 write!(f, "{}: ", name.display(f.db, f.edition()))?;
2553 }
2554
2555 param_type.hir_fmt(f, owner, store)?;
2556
2557 if index != function_parameters.len() - 1 {
2558 write!(f, ", ")?;
2559 }
2560 }
2561 if fn_.is_varargs {
2562 write!(f, "{}...", if fn_.params.len() == 1 { "" } else { ", " })?;
2563 }
2564 write!(f, ")")?;
2565 match &store[*return_type] {
2566 TypeRef::Tuple(tup) if tup.is_empty() => {}
2567 _ => {
2568 write!(f, " -> ")?;
2569 return_type.hir_fmt(f, owner, store)?;
2570 }
2571 }
2572 }
2573 }
2574 TypeRef::ImplTrait(bounds) => {
2575 write!(f, "impl ")?;
2576 f.write_joined(
2577 bounds.iter().map(ExpressionStoreAdapter::wrap(owner, store)),
2578 " + ",
2579 )?;
2580 }
2581 TypeRef::DynTrait(bounds) => {
2582 write!(f, "dyn ")?;
2583 f.write_joined(
2584 bounds.iter().map(ExpressionStoreAdapter::wrap(owner, store)),
2585 " + ",
2586 )?;
2587 }
2588 TypeRef::PatternType(ty, pat) => {
2589 ty.hir_fmt(f, owner, store)?;
2590 write!(f, " is ")?;
2591 pat.hir_fmt(f, owner, store)?;
2592 }
2593 TypeRef::Error => write!(f, "{{error}}")?,
2594 }
2595 Ok(())
2596 }
2597}
2598
2599impl<'db> HirDisplayWithExpressionStore<'db> for ConstRef {
2600 fn hir_fmt(
2601 &self,
2602 f: &mut HirFormatter<'_, 'db>,
2603 _owner: ExpressionStoreOwnerId,
2604 _store: &ExpressionStore,
2605 ) -> Result {
2606 write!(f, "{{const}}")?;
2608
2609 Ok(())
2610 }
2611}
2612
2613impl<'db> HirDisplayWithExpressionStore<'db> for PatId {
2614 fn hir_fmt(
2615 &self,
2616 f: &mut HirFormatter<'_, 'db>,
2617 owner: ExpressionStoreOwnerId,
2618 store: &ExpressionStore,
2619 ) -> Result {
2620 write!(
2621 f,
2622 "{}",
2623 hir_def::expr_store::pretty::print_pat_hir(
2624 f.db,
2625 store,
2626 owner,
2627 *self,
2628 false,
2629 f.edition()
2630 )
2631 )?;
2632 Ok(())
2633 }
2634}
2635
2636impl<'db> HirDisplayWithExpressionStore<'db> for TypeBound {
2637 fn hir_fmt(
2638 &self,
2639 f: &mut HirFormatter<'_, 'db>,
2640 owner: ExpressionStoreOwnerId,
2641 store: &ExpressionStore,
2642 ) -> Result {
2643 match self {
2644 &TypeBound::Path(path, modifier) => {
2645 match modifier {
2646 TraitBoundModifier::None => (),
2647 TraitBoundModifier::Maybe => write!(f, "?")?,
2648 }
2649 store[path].hir_fmt(f, owner, store)
2650 }
2651 TypeBound::Lifetime(lifetime) => lifetime.hir_fmt(f, owner, store),
2652 TypeBound::ForLifetime(lifetimes, path) => {
2653 let edition = f.edition();
2654 write!(
2655 f,
2656 "for<{}> ",
2657 lifetimes.iter().map(|it| it.display(f.db, edition)).format(", ")
2658 )?;
2659 store[*path].hir_fmt(f, owner, store)
2660 }
2661 TypeBound::Use(args) => {
2662 write!(f, "use<")?;
2663 let edition = f.edition();
2664 let last = args.len().saturating_sub(1);
2665 for (idx, arg) in args.iter().enumerate() {
2666 match arg {
2667 UseArgRef::Lifetime(lt) => lt.hir_fmt(f, owner, store)?,
2668 UseArgRef::Name(n) => write!(f, "{}", n.display(f.db, edition))?,
2669 }
2670 if idx != last {
2671 write!(f, ", ")?;
2672 }
2673 }
2674 write!(f, "> ")
2675 }
2676 TypeBound::Error => write!(f, "{{error}}"),
2677 }
2678 }
2679}
2680
2681impl<'db> HirDisplayWithExpressionStore<'db> for Path {
2682 fn hir_fmt(
2683 &self,
2684 f: &mut HirFormatter<'_, 'db>,
2685 owner: ExpressionStoreOwnerId,
2686 store: &ExpressionStore,
2687 ) -> Result {
2688 match (self.type_anchor(), self.kind()) {
2689 (Some(anchor), _) => {
2690 write!(f, "<")?;
2691 anchor.hir_fmt(f, owner, store)?;
2692 write!(f, ">")?;
2693 }
2694 (_, PathKind::Plain) => {}
2695 (_, PathKind::Abs) => {}
2696 (_, PathKind::Crate) => write!(f, "crate")?,
2697 (_, &PathKind::SELF) => write!(f, "self")?,
2698 (_, PathKind::Super(n)) => {
2699 for i in 0..*n {
2700 if i > 0 {
2701 write!(f, "::")?;
2702 }
2703 write!(f, "super")?;
2704 }
2705 }
2706 (_, PathKind::DollarCrate(id)) => {
2707 let crate_data = id.extra_data(f.db);
2711 let name = crate_data
2712 .display_name
2713 .as_ref()
2714 .map(|name| (*name.canonical_name()).clone())
2715 .unwrap_or(sym::dollar_crate);
2716 write!(f, "{name}")?
2717 }
2718 }
2719
2720 let trait_self_ty = self.segments().iter().find_map(|seg| {
2729 let generic_args = seg.args_and_bindings?;
2730 generic_args.has_self_type.then(|| &generic_args.args[0])
2731 });
2732 if let Some(ty) = trait_self_ty {
2733 write!(f, "<")?;
2734 ty.hir_fmt(f, owner, store)?;
2735 write!(f, " as ")?;
2736 }
2738
2739 for (seg_idx, segment) in self.segments().iter().enumerate() {
2740 if !matches!(self.kind(), PathKind::Plain) || seg_idx > 0 {
2741 write!(f, "::")?;
2742 }
2743 write!(f, "{}", segment.name.display(f.db, f.edition()))?;
2744 if let Some(generic_args) = segment.args_and_bindings {
2745 match generic_args.parenthesized {
2748 hir_def::expr_store::path::GenericArgsParentheses::ReturnTypeNotation => {
2749 write!(f, "(..)")?;
2750 }
2751 hir_def::expr_store::path::GenericArgsParentheses::ParenSugar => {
2752 let tuple = match generic_args.args[0] {
2755 hir_def::expr_store::path::GenericArg::Type(ty) => match &store[ty] {
2756 TypeRef::Tuple(it) => Some(it),
2757 _ => None,
2758 },
2759 _ => None,
2760 };
2761 if let Some(v) = tuple {
2762 if v.len() == 1 {
2763 write!(f, "(")?;
2764 v[0].hir_fmt(f, owner, store)?;
2765 write!(f, ")")?;
2766 } else {
2767 generic_args.args[0].hir_fmt(f, owner, store)?;
2768 }
2769 }
2770 if let Some(ret) = generic_args.bindings[0].type_ref
2771 && !matches!(&store[ret], TypeRef::Tuple(v) if v.is_empty())
2772 {
2773 write!(f, " -> ")?;
2774 ret.hir_fmt(f, owner, store)?;
2775 }
2776 }
2777 hir_def::expr_store::path::GenericArgsParentheses::No => {
2778 let mut first = true;
2779 for arg in &generic_args.args[generic_args.has_self_type as usize..] {
2781 if first {
2782 first = false;
2783 write!(f, "<")?;
2784 } else {
2785 write!(f, ", ")?;
2786 }
2787 arg.hir_fmt(f, owner, store)?;
2788 }
2789 for binding in generic_args.bindings.iter() {
2790 if first {
2791 first = false;
2792 write!(f, "<")?;
2793 } else {
2794 write!(f, ", ")?;
2795 }
2796 write!(f, "{}", binding.name.display(f.db, f.edition()))?;
2797 match &binding.type_ref {
2798 Some(ty) => {
2799 write!(f, " = ")?;
2800 ty.hir_fmt(f, owner, store)?
2801 }
2802 None => {
2803 write!(f, ": ")?;
2804 f.write_joined(
2805 binding
2806 .bounds
2807 .iter()
2808 .map(ExpressionStoreAdapter::wrap(owner, store)),
2809 " + ",
2810 )?;
2811 }
2812 }
2813 }
2814
2815 if !first {
2818 write!(f, ">")?;
2819 }
2820
2821 if generic_args.has_self_type {
2823 write!(f, ">")?;
2824 }
2825 }
2826 }
2827 }
2828 }
2829
2830 Ok(())
2831 }
2832}
2833
2834impl<'db> HirDisplayWithExpressionStore<'db> for hir_def::expr_store::path::GenericArg {
2835 fn hir_fmt(
2836 &self,
2837 f: &mut HirFormatter<'_, 'db>,
2838 owner: ExpressionStoreOwnerId,
2839 store: &ExpressionStore,
2840 ) -> Result {
2841 match self {
2842 hir_def::expr_store::path::GenericArg::Type(ty) => ty.hir_fmt(f, owner, store),
2843 hir_def::expr_store::path::GenericArg::Const(_c) => {
2844 write!(f, "<expr>")
2846 }
2847 hir_def::expr_store::path::GenericArg::Lifetime(lifetime) => {
2848 lifetime.hir_fmt(f, owner, store)
2849 }
2850 }
2851 }
2852}