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::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
525#[derive(Clone, Copy)]
526pub enum DisplayKind {
527 Diagnostics,
531 SourceCode { target_module_id: ModuleId, allow_opaque: bool },
534 Test,
536}
537
538impl DisplayKind {
539 fn is_source_code(self) -> bool {
540 matches!(self, Self::SourceCode { .. })
541 }
542
543 fn allows_opaque(self) -> bool {
544 match self {
545 Self::SourceCode { allow_opaque, .. } => allow_opaque,
546 _ => true,
547 }
548 }
549}
550
551#[derive(Debug)]
552pub enum DisplaySourceCodeError {
553 PathNotFound,
554 Coroutine,
555 OpaqueType,
556 Cycle,
557}
558
559pub enum HirDisplayError {
560 DisplaySourceCodeError(DisplaySourceCodeError),
562 FmtError,
564}
565impl From<fmt::Error> for HirDisplayError {
566 fn from(_: fmt::Error) -> Self {
567 Self::FmtError
568 }
569}
570
571pub struct HirDisplayWrapper<'a, 'db, T> {
572 db: &'db dyn HirDatabase,
573 t: &'a T,
574 max_size: Option<usize>,
575 limited_size: Option<usize>,
576 omit_verbose_types: bool,
577 closure_style: ClosureStyle,
578 display_kind: DisplayKind,
579 display_target: DisplayTarget,
580 show_container_bounds: bool,
581 render_private_fields: bool,
582 display_lifetimes: DisplayLifetime,
583}
584
585#[derive(Debug, PartialEq, Eq, Clone, Copy)]
586pub enum ClosureStyle {
587 ImplFn,
590 RANotation,
592 ClosureWithId,
594 ClosureWithSubst,
596 Hide,
598}
599
600impl<'db, T: HirDisplay<'db>> HirDisplayWrapper<'_, 'db, T> {
601 pub fn write_to<F: HirWrite>(&self, f: &mut F) -> Result {
602 let krate = self.display_target.krate;
603 let interner = DbInterner::new_with(self.db, krate);
604 self.t.hir_fmt(&mut HirFormatter {
605 db: self.db,
606 interner,
607 fmt: f,
608 buf: String::with_capacity(self.max_size.unwrap_or(20)),
609 curr_size: 0,
610 max_size: self.max_size,
611 entity_limit: self.limited_size,
612 omit_verbose_types: self.omit_verbose_types,
613 display_kind: self.display_kind,
614 display_target: self.display_target,
615 closure_style: self.closure_style,
616 show_container_bounds: self.show_container_bounds,
617 render_private_fields: self.render_private_fields,
618 display_lifetimes: self.display_lifetimes,
619 currently_formatting_bounds: Default::default(),
620 trait_bounds_need_parens: false,
621 })
622 }
623
624 pub fn with_closure_style(mut self, c: ClosureStyle) -> Self {
625 self.closure_style = c;
626 self
627 }
628
629 pub fn with_lifetime_display(mut self, l: DisplayLifetime) -> Self {
630 self.display_lifetimes = l;
631 self
632 }
633
634 pub fn with_private_fields(mut self, render: bool) -> Self {
635 self.render_private_fields = render;
636 self
637 }
638}
639
640impl<'db, T> fmt::Display for HirDisplayWrapper<'_, 'db, T>
641where
642 T: HirDisplay<'db>,
643{
644 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
645 match self.write_to(f) {
646 Ok(()) => Ok(()),
647 Err(HirDisplayError::FmtError) => Err(fmt::Error),
648 Err(HirDisplayError::DisplaySourceCodeError(_)) => {
649 panic!(
651 "HirDisplay::hir_fmt failed with DisplaySourceCodeError when calling Display::fmt!"
652 )
653 }
654 }
655 }
656}
657
658const TYPE_HINT_TRUNCATION: &str = "…";
659
660impl<'db, T: HirDisplay<'db>> HirDisplay<'db> for &T {
661 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
662 HirDisplay::hir_fmt(*self, f)
663 }
664}
665
666impl<'db, T: HirDisplay<'db> + Internable> HirDisplay<'db> for Interned<T> {
667 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
668 HirDisplay::hir_fmt(&**self, f)
669 }
670}
671
672fn write_projection<'db>(
673 f: &mut HirFormatter<'_, 'db>,
674 alias: &AliasTy<'db>,
675 needs_parens_if_multi: bool,
676 def_id: TypeAliasId,
677) -> Result {
678 f.format_bounds_with(*alias, |f| {
679 if f.should_truncate() {
680 return write!(f, "{TYPE_HINT_TRUNCATION}");
681 }
682 let trait_ref = alias.trait_ref(f.interner);
683 let self_ty = trait_ref.self_ty();
684
685 if !f.display_kind.is_source_code()
689 && let TyKind::Param(param) = self_ty.kind()
690 {
691 let bounds = GenericPredicates::query_all(f.db, param.id.parent())
694 .iter_identity()
695 .map(Unnormalized::skip_norm_wip)
696 .filter(|wc| {
697 let ty = match wc.kind().skip_binder() {
698 ClauseKind::Trait(tr) => tr.self_ty(),
699 ClauseKind::TypeOutlives(t) => t.0,
700 _ => return false,
701 };
702 let TyKind::Alias(a) = ty.kind() else {
703 return false;
704 };
705 a == *alias
706 })
707 .collect::<Vec<_>>();
708 if !bounds.is_empty() {
709 return write_bounds_like_dyn_trait_with_prefix(
710 f,
711 "impl",
712 Either::Left(Ty::new_alias(f.interner, *alias)),
713 &bounds,
714 SizedByDefault::NotSized,
715 needs_parens_if_multi,
716 );
717 }
718 }
719
720 write!(f, "<")?;
721 self_ty.hir_fmt(f)?;
722 write!(f, " as ")?;
723 trait_ref.hir_fmt(f)?;
724 write!(f, ">::{}", TypeAliasSignature::of(f.db, def_id).name.display(f.db, f.edition()))?;
725 let proj_params = &alias.args.as_slice()[trait_ref.args.len()..];
726 hir_fmt_generics(f, proj_params, None, None)
727 })
728}
729
730impl<'db> HirDisplay<'db> for GenericArg<'db> {
731 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
732 match self.kind() {
733 GenericArgKind::Type(ty) => ty.hir_fmt(f),
734 GenericArgKind::Lifetime(lt) => lt.hir_fmt(f),
735 GenericArgKind::Const(c) => c.hir_fmt(f),
736 }
737 }
738}
739
740impl<'db> HirDisplay<'db> for Allocation<'db> {
741 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
742 render_const_scalar(f, &self.memory, &self.memory_map, self.ty)
743 }
744}
745
746impl<'db> HirDisplay<'db> for Const<'db> {
747 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
748 match self.kind() {
749 ConstKind::Placeholder(_) => write!(f, "<placeholder>"),
750 ConstKind::Bound(BoundVarIndexKind::Bound(db), bound_const) => {
751 write!(f, "?{}.{}", db.as_u32(), bound_const.var.as_u32())
752 }
753 ConstKind::Bound(BoundVarIndexKind::Canonical, bound_const) => {
754 write!(f, "?c.{}", bound_const.var.as_u32())
755 }
756 ConstKind::Infer(..) => write!(f, "#c#"),
757 ConstKind::Param(param) => {
758 let generics = GenericParams::of(f.db, param.id.parent());
759 let param_data = &generics[param.id.local_id()];
760 f.start_location_link_generic(param.id.into());
761 write!(f, "{}", param_data.name().unwrap().display(f.db, f.edition()))?;
762 f.end_location_link();
763 Ok(())
764 }
765 ConstKind::Value(value) => render_const_scalar_from_valtree(f, value.ty, value.value),
766 ConstKind::Unevaluated(unev) => {
767 let c = unev.def.0;
768 let generic_def = match c {
769 GeneralConstId::ConstId(id) => {
770 match &ConstSignature::of(f.db, id).name {
771 Some(name) => {
772 f.start_location_link(id.into());
773 write!(f, "{}", name.display(f.db, f.edition()))?;
774 f.end_location_link();
775 }
776 None => f.write_str("_")?,
777 }
778 Some(id.into())
779 }
780 GeneralConstId::StaticId(id) => {
781 let name = &StaticSignature::of(f.db, id).name;
782 f.start_location_link(id.into());
783 write!(f, "{}", name.display(f.db, f.edition()))?;
784 f.end_location_link();
785 Some(id.into())
786 }
787 GeneralConstId::AnonConstId(_) => {
788 f.write_str(if f.display_kind.is_source_code() { "_" } else { "{const}" })?;
789 None
790 }
791 };
792 if let Some(generic_def) = generic_def {
793 hir_fmt_generics(f, unev.args.as_slice(), Some(generic_def), None)?;
794 }
795 Ok(())
796 }
797 ConstKind::Error(..) => f.write_char('_'),
798 ConstKind::Expr(..) => write!(f, "<const-expr>"),
799 }
800 }
801}
802
803fn render_const_scalar<'db>(
804 f: &mut HirFormatter<'_, 'db>,
805 b: &[u8],
806 memory_map: &MemoryMap<'db>,
807 ty: Ty<'db>,
808) -> Result {
809 let param_env = ParamEnv::empty(f.interner);
810 let infcx = f.interner.infer_ctxt().build(TypingMode::PostAnalysis);
811 let ty = infcx.at(&ObligationCause::dummy(), param_env).deeply_normalize(ty).unwrap_or(ty);
812 render_const_scalar_inner(f, b, memory_map, ty, param_env)
813}
814
815fn render_const_scalar_inner<'db>(
816 f: &mut HirFormatter<'_, 'db>,
817 b: &[u8],
818 memory_map: &MemoryMap<'db>,
819 ty: Ty<'db>,
820 param_env: ParamEnv<'db>,
821) -> Result {
822 use TyKind;
823 let param_env = ParamEnvAndCrate { param_env, krate: f.krate() };
824 match ty.kind() {
825 TyKind::Bool => write!(f, "{}", b[0] != 0),
826 TyKind::Char => {
827 let it = u128::from_le_bytes(pad16(b, false)) as u32;
828 let Ok(c) = char::try_from(it) else {
829 return f.write_str("<unicode-error>");
830 };
831 write!(f, "{c:?}")
832 }
833 TyKind::Int(_) => {
834 let it = i128::from_le_bytes(pad16(b, true));
835 write!(f, "{it}")
836 }
837 TyKind::Uint(_) => {
838 let it = u128::from_le_bytes(pad16(b, false));
839 write!(f, "{it}")
840 }
841 TyKind::Float(fl) => match fl {
842 FloatTy::F16 => {
843 let it = f16::from_bits(u16::from_le_bytes(b.try_into().unwrap()).into());
845 let s = it.to_string();
846 if s.strip_prefix('-').unwrap_or(&s).chars().all(|c| c.is_ascii_digit()) {
847 write!(f, "{s}.0")
849 } else {
850 write!(f, "{s}")
851 }
852 }
853 FloatTy::F32 => {
854 let it = f32::from_le_bytes(b.try_into().unwrap());
855 write!(f, "{it:?}")
856 }
857 FloatTy::F64 => {
858 let it = f64::from_le_bytes(b.try_into().unwrap());
859 write!(f, "{it:?}")
860 }
861 FloatTy::F128 => {
862 let it = f128::from_bits(u128::from_le_bytes(b.try_into().unwrap()));
864 let s = it.to_string();
865 if s.strip_prefix('-').unwrap_or(&s).chars().all(|c| c.is_ascii_digit()) {
866 write!(f, "{s}.0")
868 } else {
869 write!(f, "{s}")
870 }
871 }
872 },
873 TyKind::Ref(_, t, _) => match t.kind() {
874 TyKind::Str => {
875 let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap());
876 let size = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap());
877 let Some(bytes) = memory_map.get(addr, size) else {
878 return f.write_str("<ref-data-not-available>");
879 };
880 let s = std::str::from_utf8(bytes).unwrap_or("<utf8-error>");
881 write!(f, "{s:?}")
882 }
883 TyKind::Slice(ty) => {
884 let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap());
885 let count = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap());
886 let Ok(layout) = f.db.layout_of_ty(ty.store(), param_env.store()) else {
887 return f.write_str("<layout-error>");
888 };
889 let size_one = layout.size.bytes_usize();
890 let Some(bytes) = memory_map.get(addr, size_one * count) else {
891 return f.write_str("<ref-data-not-available>");
892 };
893 let expected_len = count * size_one;
894 if bytes.len() < expected_len {
895 never!(
896 "Memory map size is too small. Expected {expected_len}, got {}",
897 bytes.len(),
898 );
899 return f.write_str("<layout-error>");
900 }
901 f.write_str("&[")?;
902 let mut first = true;
903 for i in 0..count {
904 if first {
905 first = false;
906 } else {
907 f.write_str(", ")?;
908 }
909 let offset = size_one * i;
910 render_const_scalar(f, &bytes[offset..offset + size_one], memory_map, ty)?;
911 }
912 f.write_str("]")
913 }
914 TyKind::Dynamic(_, _) => {
915 let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap());
916 let ty_id = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap());
917 let Ok(t) = memory_map.vtable_ty(ty_id) else {
918 return f.write_str("<ty-missing-in-vtable-map>");
919 };
920 let Ok(layout) = f.db.layout_of_ty(t.store(), param_env.store()) else {
921 return f.write_str("<layout-error>");
922 };
923 let size = layout.size.bytes_usize();
924 let Some(bytes) = memory_map.get(addr, size) else {
925 return f.write_str("<ref-data-not-available>");
926 };
927 f.write_str("&")?;
928 render_const_scalar(f, bytes, memory_map, t)
929 }
930 TyKind::Adt(adt, _) if b.len() == 2 * size_of::<usize>() => match adt.def_id() {
931 hir_def::AdtId::StructId(s) => {
932 let data = StructSignature::of(f.db, s);
933 write!(f, "&{}", data.name.display(f.db, f.edition()))?;
934 Ok(())
935 }
936 _ => f.write_str("<unsized-enum-or-union>"),
937 },
938 _ => {
939 let addr = usize::from_le_bytes(match b.try_into() {
940 Ok(b) => b,
941 Err(_) => {
942 never!(
943 "tried rendering ty {:?} in const ref with incorrect byte count {}",
944 t,
945 b.len()
946 );
947 return f.write_str("<layout-error>");
948 }
949 });
950 let Ok(layout) = f.db.layout_of_ty(t.store(), param_env.store()) else {
951 return f.write_str("<layout-error>");
952 };
953 let size = layout.size.bytes_usize();
954 let Some(bytes) = memory_map.get(addr, size) else {
955 return f.write_str("<ref-data-not-available>");
956 };
957 f.write_str("&")?;
958 render_const_scalar(f, bytes, memory_map, t)
959 }
960 },
961 TyKind::Tuple(tys) => {
962 let Ok(layout) = f.db.layout_of_ty(ty.store(), param_env.store()) else {
963 return f.write_str("<layout-error>");
964 };
965 f.write_str("(")?;
966 let mut first = true;
967 for (id, ty) in tys.iter().enumerate() {
968 if first {
969 first = false;
970 } else {
971 f.write_str(", ")?;
972 }
973 let offset = layout.fields.offset(id).bytes_usize();
974 let Ok(layout) = f.db.layout_of_ty(ty.store(), param_env.store()) else {
975 f.write_str("<layout-error>")?;
976 continue;
977 };
978 let size = layout.size.bytes_usize();
979 render_const_scalar(f, &b[offset..offset + size], memory_map, ty)?;
980 }
981 f.write_str(")")
982 }
983 TyKind::Adt(def, args) => {
984 let def = def.def_id();
985 let Ok(layout) = f.db.layout_of_adt(def, args.store(), param_env.store()) else {
986 return f.write_str("<layout-error>");
987 };
988 match def {
989 hir_def::AdtId::StructId(s) => {
990 let data = StructSignature::of(f.db, s);
991 write!(f, "{}", data.name.display(f.db, f.edition()))?;
992 let field_types = f.db.field_types(s.into());
993 render_variant_after_name(
994 s.fields(f.db),
995 f,
996 field_types,
997 f.db.trait_environment(def.into()),
998 &layout,
999 args,
1000 b,
1001 memory_map,
1002 )
1003 }
1004 hir_def::AdtId::UnionId(u) => {
1005 write!(f, "{}", UnionSignature::of(f.db, u).name.display(f.db, f.edition()))
1006 }
1007 hir_def::AdtId::EnumId(e) => {
1008 let Ok(target_data_layout) = f.db.target_data_layout(f.krate()) else {
1009 return f.write_str("<target-layout-not-available>");
1010 };
1011 let Some((var_id, var_layout)) =
1012 detect_variant_from_bytes(&layout, f.db, target_data_layout, b, e)
1013 else {
1014 return f.write_str("<failed-to-detect-variant>");
1015 };
1016 let loc = var_id.lookup(f.db);
1017 write!(f, "{}", loc.name.display(f.db, f.edition()))?;
1018 let field_types = f.db.field_types(var_id.into());
1019 render_variant_after_name(
1020 var_id.fields(f.db),
1021 f,
1022 field_types,
1023 f.db.trait_environment(def.into()),
1024 var_layout,
1025 args,
1026 b,
1027 memory_map,
1028 )
1029 }
1030 }
1031 }
1032 TyKind::FnDef(..) => ty.hir_fmt(f),
1033 TyKind::FnPtr(_, _) | TyKind::RawPtr(_, _) => {
1034 let it = u128::from_le_bytes(pad16(b, false));
1035 write!(f, "{it:#X} as ")?;
1036 ty.hir_fmt(f)
1037 }
1038 TyKind::Array(ty, len) => {
1039 let Some(len) = consteval::try_const_usize(f.db, len) else {
1040 return f.write_str("<unknown-array-len>");
1041 };
1042 let Ok(layout) = f.db.layout_of_ty(ty.store(), param_env.store()) else {
1043 return f.write_str("<layout-error>");
1044 };
1045 let size_one = layout.size.bytes_usize();
1046 f.write_str("[")?;
1047 let mut first = true;
1048 for i in 0..len as usize {
1049 if first {
1050 first = false;
1051 } else {
1052 f.write_str(", ")?;
1053 }
1054 let offset = size_one * i;
1055 render_const_scalar(f, &b[offset..offset + size_one], memory_map, ty)?;
1056 }
1057 f.write_str("]")
1058 }
1059 TyKind::Never => f.write_str("!"),
1060 TyKind::Closure(_, _) => f.write_str("<closure>"),
1061 TyKind::Coroutine(_, _) => f.write_str("<coroutine>"),
1062 TyKind::CoroutineWitness(_, _) => f.write_str("<coroutine-witness>"),
1063 TyKind::CoroutineClosure(_, _) => f.write_str("<coroutine-closure>"),
1064 TyKind::UnsafeBinder(_) => f.write_str("<unsafe-binder>"),
1065 TyKind::Foreign(_) => f.write_str("<extern-type>"),
1067 TyKind::Pat(_, _) => f.write_str("<pat>"),
1068 TyKind::Error(..)
1069 | TyKind::Placeholder(_)
1070 | TyKind::Alias(..)
1071 | TyKind::Param(_)
1072 | TyKind::Bound(_, _)
1073 | TyKind::Infer(_) => f.write_str("<placeholder-or-unknown-type>"),
1074 TyKind::Slice(_) | TyKind::Str | TyKind::Dynamic(_, _) => f.write_str("<unsized-value>"),
1076 }
1077}
1078
1079fn render_const_scalar_from_valtree<'db>(
1080 f: &mut HirFormatter<'_, 'db>,
1081 ty: Ty<'db>,
1082 valtree: ValTree<'db>,
1083) -> Result {
1084 let param_env = ParamEnv::empty(f.interner);
1085 let infcx = f.interner.infer_ctxt().build(TypingMode::PostAnalysis);
1086 let ty = infcx.at(&ObligationCause::dummy(), param_env).deeply_normalize(ty).unwrap_or(ty);
1087 render_const_scalar_from_valtree_inner(f, ty, valtree, param_env)
1088}
1089
1090fn render_const_scalar_from_valtree_inner<'db>(
1091 f: &mut HirFormatter<'_, 'db>,
1092 ty: Ty<'db>,
1093 valtree: ValTree<'db>,
1094 _param_env: ParamEnv<'db>,
1095) -> Result {
1096 use TyKind;
1097 match ty.kind() {
1098 TyKind::Bool => write!(f, "{}", valtree.inner().to_leaf().try_to_bool().unwrap()),
1099 TyKind::Char => {
1100 let it = valtree.inner().to_leaf().to_u32();
1101 let Ok(c) = char::try_from(it) else {
1102 return f.write_str("<unicode-error>");
1103 };
1104 write!(f, "{c:?}")
1105 }
1106 TyKind::Int(_) => {
1107 let it = valtree.inner().to_leaf().to_int_unchecked();
1108 write!(f, "{it}")
1109 }
1110 TyKind::Uint(_) => {
1111 let it = valtree.inner().to_leaf().to_uint_unchecked();
1112 write!(f, "{it}")
1113 }
1114 TyKind::Float(fl) => match fl {
1115 FloatTy::F16 => {
1116 let it = f16::from_bits(valtree.inner().to_leaf().to_u16() as u128);
1118 let s = it.to_string();
1119 if s.strip_prefix('-').unwrap_or(&s).chars().all(|c| c.is_ascii_digit()) {
1120 write!(f, "{s}.0")
1122 } else {
1123 write!(f, "{s}")
1124 }
1125 }
1126 FloatTy::F32 => {
1127 let it = f32::from_bits(valtree.inner().to_leaf().to_u32());
1128 write!(f, "{it:?}")
1129 }
1130 FloatTy::F64 => {
1131 let it = f64::from_bits(valtree.inner().to_leaf().to_u64());
1132 write!(f, "{it:?}")
1133 }
1134 FloatTy::F128 => {
1135 let it = f128::from_bits(valtree.inner().to_leaf().to_u128());
1137 let s = it.to_string();
1138 if s.strip_prefix('-').unwrap_or(&s).chars().all(|c| c.is_ascii_digit()) {
1139 write!(f, "{s}.0")
1141 } else {
1142 write!(f, "{s}")
1143 }
1144 }
1145 },
1146 TyKind::Ref(_, inner_ty, _) => {
1147 render_const_scalar_from_valtree_inner(f, inner_ty, valtree, _param_env)
1148 }
1149 TyKind::Str => {
1150 let bytes = valtree
1151 .inner()
1152 .to_branch()
1153 .iter()
1154 .map(|konst| match konst.kind() {
1155 ConstKind::Value(value) => Some(value.value.inner().to_leaf().to_u8()),
1156 _ => None,
1157 })
1158 .collect::<Option<Vec<_>>>();
1159 let Some(bytes) = bytes else { return f.write_str("<invalid-str>") };
1160 let s = std::str::from_utf8(&bytes).unwrap_or("<utf8-error>");
1161 write!(f, "{s:?}")
1162 }
1163 TyKind::Slice(inner_ty) | TyKind::Array(inner_ty, _) => {
1164 let mut first = true;
1165 write!(f, "[")?;
1166 for item in valtree.inner().to_branch() {
1167 if !first {
1168 write!(f, ", ")?;
1169 } else {
1170 first = false;
1171 }
1172 let ConstKind::Value(value) = item.kind() else {
1173 return f.write_str("<invalid-const>");
1174 };
1175 render_const_scalar_from_valtree_inner(f, inner_ty, value.value, _param_env)?;
1176 }
1177 write!(f, "]")
1178 }
1179 TyKind::Tuple(tys) => {
1180 let mut first = true;
1181 write!(f, "(")?;
1182 for (inner_ty, item) in std::iter::zip(tys, valtree.inner().to_branch()) {
1183 if !first {
1184 write!(f, ", ")?;
1185 } else {
1186 first = false;
1187 }
1188 let ConstKind::Value(value) = item.kind() else {
1189 return f.write_str("<invalid-const>");
1190 };
1191 render_const_scalar_from_valtree_inner(f, inner_ty, value.value, _param_env)?;
1192 }
1193 write!(f, ")")
1194 }
1195 TyKind::Adt(..) => {
1196 f.write_str("<adt>")
1198 }
1199 TyKind::FnDef(..) => ty.hir_fmt(f),
1200 TyKind::FnPtr(_, _) | TyKind::RawPtr(_, _) => {
1201 let it = valtree.inner().to_leaf().to_uint_unchecked();
1202 write!(f, "{it:#X} as ")?;
1203 ty.hir_fmt(f)
1204 }
1205 TyKind::Never => f.write_str("!"),
1206 TyKind::Closure(_, _) => f.write_str("<closure>"),
1207 TyKind::Coroutine(_, _) => f.write_str("<coroutine>"),
1208 TyKind::CoroutineWitness(_, _) => f.write_str("<coroutine-witness>"),
1209 TyKind::CoroutineClosure(_, _) => f.write_str("<coroutine-closure>"),
1210 TyKind::UnsafeBinder(_) => f.write_str("<unsafe-binder>"),
1211 TyKind::Foreign(_) => f.write_str("<extern-type>"),
1213 TyKind::Pat(_, _) => f.write_str("<pat>"),
1214 TyKind::Error(..)
1215 | TyKind::Placeholder(_)
1216 | TyKind::Alias(..)
1217 | TyKind::Param(_)
1218 | TyKind::Bound(_, _)
1219 | TyKind::Infer(_) => f.write_str("<placeholder-or-unknown-type>"),
1220 TyKind::Dynamic(_, _) => f.write_str("<dyn-trait>"),
1221 }
1222}
1223
1224fn render_variant_after_name<'db>(
1225 data: &VariantFields,
1226 f: &mut HirFormatter<'_, 'db>,
1227 field_types: &'db ArenaMap<LocalFieldId, FieldType>,
1228 param_env: ParamEnv<'db>,
1229 layout: &Layout,
1230 args: GenericArgs<'db>,
1231 b: &[u8],
1232 memory_map: &MemoryMap<'db>,
1233) -> Result {
1234 let param_env = ParamEnvAndCrate { param_env, krate: f.krate() };
1235 match data.shape {
1236 FieldsShape::Record | FieldsShape::Tuple => {
1237 let render_field = |f: &mut HirFormatter<'_, 'db>, id: LocalFieldId| {
1238 let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize();
1239 let ty = field_types[id].ty().instantiate(f.interner, args).skip_norm_wip();
1240 let Ok(layout) = f.db.layout_of_ty(ty.store(), param_env.store()) else {
1241 return f.write_str("<layout-error>");
1242 };
1243 let size = layout.size.bytes_usize();
1244 render_const_scalar(f, &b[offset..offset + size], memory_map, ty)
1245 };
1246 let mut it = data.fields().iter();
1247 if matches!(data.shape, FieldsShape::Record) {
1248 write!(f, " {{")?;
1249 if let Some((id, data)) = it.next() {
1250 write!(f, " {}: ", data.name.display(f.db, f.edition()))?;
1251 render_field(f, id)?;
1252 }
1253 for (id, data) in it {
1254 write!(f, ", {}: ", data.name.display(f.db, f.edition()))?;
1255 render_field(f, id)?;
1256 }
1257 write!(f, " }}")?;
1258 } else {
1259 let mut it = it.map(|it| it.0);
1260 write!(f, "(")?;
1261 if let Some(id) = it.next() {
1262 render_field(f, id)?;
1263 }
1264 for id in it {
1265 write!(f, ", ")?;
1266 render_field(f, id)?;
1267 }
1268 write!(f, ")")?;
1269 }
1270 Ok(())
1271 }
1272 FieldsShape::Unit => Ok(()),
1273 }
1274}
1275
1276impl<'db> HirDisplay<'db> for Ty<'db> {
1277 fn hir_fmt(&self, f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>) -> Result {
1278 let interner = f.interner;
1279 if f.should_truncate() {
1280 return write!(f, "{TYPE_HINT_TRUNCATION}");
1281 }
1282
1283 let trait_bounds_need_parens = mem::replace(&mut f.trait_bounds_need_parens, false);
1284 match self.kind() {
1285 TyKind::Never => write!(f, "!")?,
1286 TyKind::Str => write!(f, "str")?,
1287 TyKind::Bool => write!(f, "bool")?,
1288 TyKind::Char => write!(f, "char")?,
1289 TyKind::Float(t) => write!(f, "{}", primitive::float_ty_to_string(t))?,
1290 TyKind::Int(t) => write!(f, "{}", primitive::int_ty_to_string(t))?,
1291 TyKind::Uint(t) => write!(f, "{}", primitive::uint_ty_to_string(t))?,
1292 TyKind::Slice(t) => {
1293 write!(f, "[")?;
1294 t.hir_fmt(f)?;
1295 write!(f, "]")?;
1296 }
1297 TyKind::Array(t, c) => {
1298 write!(f, "[")?;
1299 t.hir_fmt(f)?;
1300 write!(f, "; ")?;
1301 c.hir_fmt(f)?;
1302 write!(f, "]")?;
1303 }
1304 TyKind::Ref(l, t, m) => {
1305 f.write_char('&')?;
1306 if f.render_region(l) {
1307 l.hir_fmt(f)?;
1308 f.write_char(' ')?;
1309 }
1310 match m {
1311 rustc_ast_ir::Mutability::Not => (),
1312 rustc_ast_ir::Mutability::Mut => f.write_str("mut ")?,
1313 }
1314
1315 f.trait_bounds_need_parens = true;
1316 t.hir_fmt(f)?;
1317 f.trait_bounds_need_parens = false;
1318 }
1319 TyKind::RawPtr(t, m) => {
1320 write!(
1321 f,
1322 "*{}",
1323 match m {
1324 rustc_ast_ir::Mutability::Not => "const ",
1325 rustc_ast_ir::Mutability::Mut => "mut ",
1326 }
1327 )?;
1328
1329 f.trait_bounds_need_parens = true;
1330 t.hir_fmt(f)?;
1331 f.trait_bounds_need_parens = false;
1332 }
1333 TyKind::Tuple(tys) => {
1334 if tys.len() == 1 {
1335 write!(f, "(")?;
1336 tys.as_slice()[0].hir_fmt(f)?;
1337 write!(f, ",)")?;
1338 } else {
1339 write!(f, "(")?;
1340 f.write_joined(tys.as_slice(), ", ")?;
1341 write!(f, ")")?;
1342 }
1343 }
1344 TyKind::FnPtr(sig, header) => {
1345 let sig = sig.with(header);
1346 sig.hir_fmt(f)?;
1347 }
1348 TyKind::FnDef(def, args) => {
1349 let def = def.0;
1350 let sig =
1351 db.callable_item_signature(def).instantiate(interner, args).skip_norm_wip();
1352
1353 if f.display_kind.is_source_code() {
1354 return sig.hir_fmt(f);
1357 }
1358 if let Safety::Unsafe = sig.safety() {
1359 write!(f, "unsafe ")?;
1360 }
1361 if !sig.abi().is_rustic_abi() {
1362 f.write_str("extern \"")?;
1363 f.write_str(sig.abi().as_str())?;
1364 f.write_str("\" ")?;
1365 }
1366
1367 let sig = sig.skip_binder();
1368 write!(f, "fn ")?;
1369 f.start_location_link(def.into());
1370 match def {
1371 CallableDefId::FunctionId(ff) => write!(
1372 f,
1373 "{}",
1374 FunctionSignature::of(db, ff).name.display(f.db, f.edition())
1375 )?,
1376 CallableDefId::StructId(s) => {
1377 write!(f, "{}", StructSignature::of(db, s).name.display(f.db, f.edition()))?
1378 }
1379 CallableDefId::EnumVariantId(e) => {
1380 let loc = e.lookup(db);
1381 write!(f, "{}", loc.name.display(db, f.edition()))?
1382 }
1383 };
1384 f.end_location_link();
1385
1386 if !args.is_empty() {
1387 let generic_def_id = GenericDefId::from_callable(db, def);
1388 let generics = generics(db, generic_def_id);
1389 let ProvenanceSplit {
1390 parent_total: parent_len,
1391 has_self_param: self_param,
1392 non_impl_trait_type_params: type_,
1393 const_params: const_,
1394 impl_trait_type_params: impl_,
1395 lifetimes: lifetime,
1396 } = generics.provenance_split();
1397 let parameters = args.as_slice();
1398 debug_assert_eq!(
1399 parameters.len(),
1400 parent_len + self_param as usize + type_ + const_ + impl_ + lifetime
1401 );
1402 if parameters.len() - impl_ > 0 {
1404 let params_len = parameters.len();
1405 let parameters =
1407 generic_args_sans_defaults(f, Some(generic_def_id), parameters);
1408 assert!(params_len >= parameters.len());
1409 let defaults = params_len - parameters.len();
1410
1411 let parent_end = if parent_len > 0 {
1419 parent_len - defaults
1422 } else {
1423 parent_len
1424 };
1425 let fn_params_no_impl_or_defaults = parameters.len() - parent_end - impl_;
1426 let (parent_params, fn_params) = parameters.split_at(parent_end);
1427
1428 write!(f, "<")?;
1429 hir_fmt_generic_arguments(f, parent_params, None)?;
1430 if !parent_params.is_empty() && !fn_params.is_empty() {
1431 write!(f, ", ")?;
1432 }
1433 hir_fmt_generic_arguments(
1434 f,
1435 &fn_params[..fn_params_no_impl_or_defaults],
1436 None,
1437 )?;
1438 write!(f, ">")?;
1439 }
1440 }
1441 write!(f, "(")?;
1442 f.write_joined(sig.inputs(), ", ")?;
1443 write!(f, ")")?;
1444 let ret = sig.output();
1445 if !ret.is_unit() {
1446 write!(f, " -> ")?;
1447 ret.hir_fmt(f)?;
1448 }
1449 }
1450 TyKind::Adt(def, parameters) => {
1451 let def_id = def.def_id();
1452 f.start_location_link(def_id.into());
1453 match f.display_kind {
1454 DisplayKind::Diagnostics | DisplayKind::Test => {
1455 let name = match def_id {
1456 hir_def::AdtId::StructId(it) => {
1457 StructSignature::of(db, it).name.clone()
1458 }
1459 hir_def::AdtId::UnionId(it) => UnionSignature::of(db, it).name.clone(),
1460 hir_def::AdtId::EnumId(it) => EnumSignature::of(db, it).name.clone(),
1461 };
1462 write!(f, "{}", name.display(f.db, f.edition()))?;
1463 }
1464 DisplayKind::SourceCode { target_module_id: module_id, allow_opaque: _ } => {
1465 if let Some(path) = find_path::find_path(
1466 db,
1467 ItemInNs::Types(def_id.into()),
1468 module_id,
1469 PrefixKind::Plain,
1470 false,
1471 FindPathConfig {
1473 prefer_no_std: false,
1474 prefer_prelude: true,
1475 prefer_absolute: false,
1476 allow_unstable: true,
1477 },
1478 ) {
1479 write!(f, "{}", path.display(f.db, f.edition()))?;
1480 } else {
1481 return Err(HirDisplayError::DisplaySourceCodeError(
1482 DisplaySourceCodeError::PathNotFound,
1483 ));
1484 }
1485 }
1486 }
1487 f.end_location_link();
1488
1489 hir_fmt_generics(f, parameters.as_slice(), Some(def.def_id().into()), None)?;
1490 }
1491 TyKind::Alias(alias_ty @ AliasTy { kind: AliasTyKind::Projection { def_id }, .. }) => {
1492 write_projection(f, &alias_ty, trait_bounds_need_parens, def_id.0)?
1493 }
1494 TyKind::Foreign(alias) => {
1495 let type_alias = TypeAliasSignature::of(db, alias.0);
1496 f.start_location_link(alias.0.into());
1497 write!(f, "{}", type_alias.name.display(f.db, f.edition()))?;
1498 f.end_location_link();
1499 }
1500 TyKind::Alias(alias_ty @ AliasTy { kind: AliasTyKind::Opaque { def_id }, .. }) => {
1501 let opaque_ty_id = def_id.0;
1502 if !f.display_kind.allows_opaque() {
1503 return Err(HirDisplayError::DisplaySourceCodeError(
1504 DisplaySourceCodeError::OpaqueType,
1505 ));
1506 }
1507 let impl_trait_id = opaque_ty_id.loc(db);
1508 let data = impl_trait_id.predicates(db);
1509 let bounds = data
1510 .iter_instantiated_copied(interner, alias_ty.args.as_slice())
1511 .map(Unnormalized::skip_norm_wip)
1512 .collect::<Vec<_>>();
1513 let krate = match impl_trait_id {
1514 ImplTraitId::ReturnTypeImplTrait(func, _) => {
1515 func.krate(db)
1516 }
1518 ImplTraitId::TypeAliasImplTrait(alias, _) => alias.krate(db),
1519 };
1520 write_bounds_like_dyn_trait_with_prefix(
1521 f,
1522 "impl",
1523 Either::Left(*self),
1524 &bounds,
1525 SizedByDefault::Sized { anchor: krate },
1526 trait_bounds_need_parens,
1527 )?;
1528 }
1529 TyKind::Closure(id, substs) => {
1530 let id = id.0;
1531 if f.display_kind.is_source_code() {
1532 if !f.display_kind.allows_opaque() {
1533 return Err(HirDisplayError::DisplaySourceCodeError(
1534 DisplaySourceCodeError::OpaqueType,
1535 ));
1536 } else if f.closure_style != ClosureStyle::ImplFn {
1537 never!("Only `impl Fn` is valid for displaying closures in source code");
1538 }
1539 }
1540 match f.closure_style {
1541 ClosureStyle::Hide => return write!(f, "{TYPE_HINT_TRUNCATION}"),
1542 ClosureStyle::ClosureWithId => {
1543 return write!(
1544 f,
1545 "{{closure#{:?}}}",
1546 salsa::plumbing::AsId::as_id(&id).index()
1547 );
1548 }
1549 ClosureStyle::ClosureWithSubst => {
1550 write!(f, "{{closure#{:?}}}", salsa::plumbing::AsId::as_id(&id).index())?;
1551 return hir_fmt_generics(f, substs.as_slice(), None, None);
1552 }
1553 _ => (),
1554 }
1555 let sig = interner.signature_unclosure(substs.as_closure().sig(), Safety::Safe);
1556 let sig = sig.skip_binder();
1557 let kind = substs.as_closure().kind();
1558 match f.closure_style {
1559 ClosureStyle::ImplFn => write!(f, "impl {kind:?}(")?,
1560 ClosureStyle::RANotation => write!(f, "|")?,
1561 _ => unreachable!(),
1562 }
1563 if sig.inputs().is_empty() {
1564 } else if f.should_truncate() {
1565 write!(f, "{TYPE_HINT_TRUNCATION}")?;
1566 } else {
1567 f.write_joined(sig.inputs(), ", ")?;
1568 };
1569 match f.closure_style {
1570 ClosureStyle::ImplFn => write!(f, ")")?,
1571 ClosureStyle::RANotation => write!(f, "|")?,
1572 _ => unreachable!(),
1573 }
1574 if f.closure_style == ClosureStyle::RANotation || !sig.output().is_unit() {
1575 write!(f, " -> ")?;
1576 sig.output().hir_fmt(f)?;
1577 }
1578 }
1579 TyKind::CoroutineClosure(id, args) => {
1580 let id = id.0;
1581 let closure_kind = match id.loc(db).kind {
1582 HirClosureKind::CoroutineClosure(kind) => kind,
1583 kind => panic!("invalid kind for coroutine closure: {kind:?}"),
1584 };
1585 let closure_label = match closure_kind {
1586 CoroutineKind::Async => "async closure",
1587 CoroutineKind::Gen => "gen closure",
1588 CoroutineKind::AsyncGen => "async gen closure",
1589 };
1590 if f.display_kind.is_source_code() {
1591 if !f.display_kind.allows_opaque() {
1592 return Err(HirDisplayError::DisplaySourceCodeError(
1593 DisplaySourceCodeError::OpaqueType,
1594 ));
1595 } else if f.closure_style != ClosureStyle::ImplFn {
1596 never!("Only `impl Fn` is valid for displaying closures in source code");
1597 }
1598 }
1599 match f.closure_style {
1600 ClosureStyle::Hide => return write!(f, "{TYPE_HINT_TRUNCATION}"),
1601 ClosureStyle::ClosureWithId => {
1602 return write!(
1603 f,
1604 "{{{closure_label}#{:?}}}",
1605 salsa::plumbing::AsId::as_id(&id).index()
1606 );
1607 }
1608 ClosureStyle::ClosureWithSubst => {
1609 write!(
1610 f,
1611 "{{{closure_label}#{:?}}}",
1612 salsa::plumbing::AsId::as_id(&id).index()
1613 )?;
1614 return hir_fmt_generics(f, args.as_slice(), None, None);
1615 }
1616 _ => (),
1617 }
1618 let callable_kind = args.as_coroutine_closure().kind();
1619 let kind = match (closure_kind, callable_kind) {
1620 (CoroutineKind::Async, rustc_type_ir::ClosureKind::Fn) => "AsyncFn",
1621 (CoroutineKind::Async, rustc_type_ir::ClosureKind::FnMut) => "AsyncFnMut",
1622 (CoroutineKind::Async, rustc_type_ir::ClosureKind::FnOnce) => "AsyncFnOnce",
1623 (_, rustc_type_ir::ClosureKind::Fn) => "Fn",
1624 (_, rustc_type_ir::ClosureKind::FnMut) => "FnMut",
1625 (_, rustc_type_ir::ClosureKind::FnOnce) => "FnOnce",
1626 };
1627 let coroutine_sig = args.as_coroutine_closure().coroutine_closure_sig();
1628 let coroutine_sig = coroutine_sig.skip_binder();
1629 let coroutine_inputs = coroutine_sig.tupled_inputs_ty.tuple_fields();
1630 let coroutine_output = coroutine_sig.return_ty;
1631 match f.closure_style {
1632 ClosureStyle::ImplFn => write!(f, "impl {kind}(")?,
1633 ClosureStyle::RANotation => match closure_kind {
1634 CoroutineKind::Async => write!(f, "async |")?,
1635 CoroutineKind::Gen => write!(f, "gen |")?,
1636 CoroutineKind::AsyncGen => write!(f, "async gen |")?,
1637 },
1638 _ => unreachable!(),
1639 }
1640 if coroutine_inputs.is_empty() {
1641 } else if f.should_truncate() {
1642 write!(f, "{TYPE_HINT_TRUNCATION}")?;
1643 } else {
1644 f.write_joined(coroutine_inputs, ", ")?;
1645 };
1646 match f.closure_style {
1647 ClosureStyle::ImplFn => write!(f, ")")?,
1648 ClosureStyle::RANotation => write!(f, "|")?,
1649 _ => unreachable!(),
1650 }
1651 if f.closure_style == ClosureStyle::RANotation || !coroutine_output.is_unit() {
1652 write!(f, " -> ")?;
1653 coroutine_output.hir_fmt(f)?;
1654 }
1655 }
1656 TyKind::Placeholder(_) => write!(f, "{{placeholder}}")?,
1657 TyKind::Param(param) => {
1658 let generics = GenericParams::of(db, param.id.parent());
1661 let param_data = &generics[param.id.local_id()];
1662 match param_data {
1663 TypeOrConstParamData::TypeParamData(p) => match p.provenance {
1664 TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
1665 f.start_location_link_generic(param.id.into());
1666 write!(
1667 f,
1668 "{}",
1669 p.name
1670 .clone()
1671 .unwrap_or_else(Name::missing)
1672 .display(f.db, f.edition())
1673 )?;
1674 f.end_location_link();
1675 }
1676 TypeParamProvenance::ArgumentImplTrait => {
1677 let bounds = GenericPredicates::query_all(f.db, param.id.parent())
1678 .iter_identity()
1679 .map(Unnormalized::skip_norm_wip)
1680 .filter(|wc| match wc.kind().skip_binder() {
1681 ClauseKind::Trait(tr) => tr.self_ty() == *self,
1682 ClauseKind::Projection(proj) => proj.self_ty() == *self,
1683 ClauseKind::TypeOutlives(to) => to.0 == *self,
1684 _ => false,
1685 })
1686 .collect::<Vec<_>>();
1687 let krate = param.id.parent().module(db).krate(db);
1688 write_bounds_like_dyn_trait_with_prefix(
1689 f,
1690 "impl",
1691 Either::Left(*self),
1692 &bounds,
1693 SizedByDefault::Sized { anchor: krate },
1694 trait_bounds_need_parens,
1695 )?;
1696 }
1697 },
1698 TypeOrConstParamData::ConstParamData(p) => {
1699 f.start_location_link_generic(param.id.into());
1700 write!(f, "{}", p.name.display(f.db, f.edition()))?;
1701 f.end_location_link();
1702 }
1703 }
1704 }
1705 TyKind::Bound(BoundVarIndexKind::Bound(debruijn), ty) => {
1706 write!(f, "?{}.{}", debruijn.as_usize(), ty.var.as_usize())?
1707 }
1708 TyKind::Bound(BoundVarIndexKind::Canonical, ty) => {
1709 write!(f, "?c.{}", ty.var.as_usize())?
1710 }
1711 TyKind::Dynamic(bounds, region) => {
1712 let mut bounds_to_display = SmallVec::<[_; 4]>::new();
1714 let mut auto_trait_bounds = SmallVec::<[_; 4]>::new();
1715 for bound in bounds.iter() {
1716 let clause = bound.with_self_ty(interner, *self);
1717 match bound.skip_binder() {
1718 ExistentialPredicate::Trait(_) | ExistentialPredicate::Projection(_) => {
1719 bounds_to_display.push(clause);
1720 }
1721 ExistentialPredicate::AutoTrait(_) => auto_trait_bounds.push(clause),
1722 }
1723 }
1724 bounds_to_display.append(&mut auto_trait_bounds);
1725
1726 if f.render_region(region) {
1727 bounds_to_display
1728 .push(rustc_type_ir::OutlivesPredicate(*self, region).upcast(interner));
1729 }
1730
1731 write_bounds_like_dyn_trait_with_prefix(
1732 f,
1733 "dyn",
1734 Either::Left(*self),
1735 &bounds_to_display,
1736 SizedByDefault::NotSized,
1737 trait_bounds_need_parens,
1738 )?;
1739 }
1740 TyKind::Error(_) => {
1741 if f.display_kind.is_source_code() {
1742 f.write_char('_')?;
1743 } else {
1744 write!(f, "{{unknown}}")?;
1745 }
1746 }
1747 TyKind::Infer(..) => write!(f, "_")?,
1748 TyKind::Coroutine(coroutine_id, subst) => {
1749 let kind = coroutine_id.0.loc(db).kind;
1750 let CoroutineArgsParts { resume_ty, yield_ty, return_ty, .. } =
1751 subst.split_coroutine_args();
1752 match kind {
1753 HirClosureKind::Coroutine { kind: CoroutineKind::Async, .. } => {
1754 let lang_items = f.lang_items();
1755 let future_trait = lang_items.Future;
1756 let output = lang_items.FutureOutput;
1757 write!(f, "impl ")?;
1758 if let Some(t) = future_trait {
1759 f.start_location_link(t.into());
1760 }
1761 write!(f, "Future")?;
1762 if future_trait.is_some() {
1763 f.end_location_link();
1764 }
1765 write!(f, "<")?;
1766 if let Some(t) = output {
1767 f.start_location_link(t.into());
1768 }
1769 write!(f, "Output")?;
1770 if output.is_some() {
1771 f.end_location_link();
1772 }
1773 write!(f, " = ")?;
1774 return_ty.hir_fmt(f)?;
1775 write!(f, ">")?;
1776 }
1777 HirClosureKind::Coroutine { kind: CoroutineKind::Gen, .. } => {
1778 let lang_items = f.lang_items();
1779 let iterator_trait = lang_items.Iterator;
1780 let item = lang_items.IteratorItem;
1781 write!(f, "impl ")?;
1782 if let Some(t) = iterator_trait {
1783 f.start_location_link(t.into());
1784 }
1785 write!(f, "Iterator")?;
1786 if iterator_trait.is_some() {
1787 f.end_location_link();
1788 }
1789 write!(f, "<")?;
1790 if let Some(t) = item {
1791 f.start_location_link(t.into());
1792 }
1793 write!(f, "Item")?;
1794 if item.is_some() {
1795 f.end_location_link();
1796 }
1797 write!(f, " = ")?;
1798 yield_ty.hir_fmt(f)?;
1799 write!(f, ">")?;
1800 }
1801 HirClosureKind::Coroutine { kind: CoroutineKind::AsyncGen, .. } => {
1802 let lang_items = f.lang_items();
1803 let async_iterator_trait = lang_items.AsyncIterator;
1804 let item = lang_items.AsyncIteratorItem;
1805 write!(f, "impl ")?;
1806 if let Some(t) = async_iterator_trait {
1807 f.start_location_link(t.into());
1808 }
1809 write!(f, "AsyncIterator")?;
1810 if async_iterator_trait.is_some() {
1811 f.end_location_link();
1812 }
1813 write!(f, "<")?;
1814 if let Some(t) = item {
1815 f.start_location_link(t.into());
1816 }
1817 write!(f, "Item")?;
1818 if item.is_some() {
1819 f.end_location_link();
1820 }
1821 write!(f, " = ")?;
1822 let item_ty = async_gen_item_ty_from_yield_ty(f.lang_items(), yield_ty)
1823 .unwrap_or(yield_ty);
1824 item_ty.hir_fmt(f)?;
1825 write!(f, ">")?;
1826 }
1827 HirClosureKind::OldCoroutine(..) => {
1828 if f.display_kind.is_source_code() {
1829 return Err(HirDisplayError::DisplaySourceCodeError(
1830 DisplaySourceCodeError::Coroutine,
1831 ));
1832 }
1833 write!(f, "|")?;
1834 resume_ty.hir_fmt(f)?;
1835 write!(f, "|")?;
1836
1837 write!(f, " yields ")?;
1838 yield_ty.hir_fmt(f)?;
1839
1840 write!(f, " -> ")?;
1841 return_ty.hir_fmt(f)?;
1842 }
1843 _ => panic!("invalid kind for coroutine: {kind:?}"),
1844 }
1845 }
1846 TyKind::CoroutineWitness(..) => write!(f, "{{coroutine witness}}")?,
1847 TyKind::Pat(_, _) => write!(f, "{{pat}}")?,
1848 TyKind::UnsafeBinder(_) => write!(f, "{{unsafe binder}}")?,
1849 TyKind::Alias(..) => write!(f, "{{alias}}")?,
1850 }
1851 Ok(())
1852 }
1853}
1854
1855fn hir_fmt_generics<'db>(
1856 f: &mut HirFormatter<'_, 'db>,
1857 parameters: &[GenericArg<'db>],
1858 generic_def: Option<hir_def::GenericDefId>,
1859 self_: Option<Ty<'db>>,
1860) -> Result {
1861 if parameters.is_empty() {
1862 return Ok(());
1863 }
1864
1865 let parameters_to_write = generic_args_sans_defaults(f, generic_def, parameters);
1866
1867 if !parameters_to_write.is_empty() {
1868 write!(f, "<")?;
1869 hir_fmt_generic_arguments(f, parameters_to_write, self_)?;
1870 write!(f, ">")?;
1871 }
1872
1873 Ok(())
1874}
1875
1876fn generic_args_sans_defaults<'ga, 'db>(
1877 f: &mut HirFormatter<'_, 'db>,
1878 generic_def: Option<hir_def::GenericDefId>,
1879 parameters: &'ga [GenericArg<'db>],
1880) -> &'ga [GenericArg<'db>] {
1881 if f.display_kind.is_source_code() || f.omit_verbose_types() {
1882 match generic_def.map(|generic_def_id| f.db.generic_defaults(generic_def_id)) {
1883 None => parameters,
1884 Some(default_parameters) => {
1885 let should_show = |arg: GenericArg<'db>, i: usize| match default_parameters.get(i) {
1886 None => true,
1887 Some(default_parameter) => {
1888 arg != default_parameter
1889 .instantiate(f.interner, ¶meters[..i])
1890 .skip_norm_wip()
1891 }
1892 };
1893 let mut default_from = 0;
1894 for (i, ¶meter) in parameters.iter().enumerate() {
1895 if should_show(parameter, i) {
1896 default_from = i + 1;
1897 }
1898 }
1899 ¶meters[0..default_from]
1900 }
1901 }
1902 } else {
1903 parameters
1904 }
1905}
1906
1907fn hir_fmt_generic_args<'db>(
1908 f: &mut HirFormatter<'_, 'db>,
1909 parameters: &[GenericArg<'db>],
1910 generic_def: Option<hir_def::GenericDefId>,
1911 self_: Option<Ty<'db>>,
1912) -> Result {
1913 if parameters.is_empty() {
1914 return Ok(());
1915 }
1916
1917 let parameters_to_write = generic_args_sans_defaults(f, generic_def, parameters);
1918
1919 if !parameters_to_write.is_empty() {
1920 write!(f, "<")?;
1921 hir_fmt_generic_arguments(f, parameters_to_write, self_)?;
1922 write!(f, ">")?;
1923 }
1924
1925 Ok(())
1926}
1927
1928fn hir_fmt_generic_arguments<'db>(
1929 f: &mut HirFormatter<'_, 'db>,
1930 parameters: &[GenericArg<'db>],
1931 self_: Option<Ty<'db>>,
1932) -> Result {
1933 let mut first = true;
1934 let lifetime_offset = parameters.iter().position(|arg| arg.region().is_some());
1935
1936 let (ty_or_const, lifetimes) = match lifetime_offset {
1937 Some(offset) => parameters.split_at(offset),
1938 None => (parameters, &[][..]),
1939 };
1940 for generic_arg in lifetimes.iter().chain(ty_or_const) {
1941 if !mem::take(&mut first) {
1942 write!(f, ", ")?;
1943 }
1944 match self_ {
1945 self_ @ Some(_) if generic_arg.ty() == self_ => write!(f, "Self")?,
1946 _ => generic_arg.hir_fmt(f)?,
1947 }
1948 }
1949 Ok(())
1950}
1951
1952fn hir_fmt_tys<'db>(
1953 f: &mut HirFormatter<'_, 'db>,
1954 tys: &[Ty<'db>],
1955 self_: Option<Ty<'db>>,
1956) -> Result {
1957 let mut first = true;
1958
1959 for ty in tys {
1960 if !mem::take(&mut first) {
1961 write!(f, ", ")?;
1962 }
1963 match self_ {
1964 Some(self_) if *ty == self_ => write!(f, "Self")?,
1965 _ => ty.hir_fmt(f)?,
1966 }
1967 }
1968 Ok(())
1969}
1970
1971impl<'db> HirDisplay<'db> for PolyFnSig<'db> {
1972 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
1973 let FnSig { inputs_and_output, fn_sig_kind } = self.skip_binder();
1974 if let Safety::Unsafe = fn_sig_kind.safety() {
1975 write!(f, "unsafe ")?;
1976 }
1977 write!(f, "fn(")?;
1984 f.write_joined(inputs_and_output.inputs(), ", ")?;
1985 if fn_sig_kind.c_variadic() {
1986 if inputs_and_output.inputs().is_empty() {
1987 write!(f, "...")?;
1988 } else {
1989 write!(f, ", ...")?;
1990 }
1991 }
1992 write!(f, ")")?;
1993 let ret = inputs_and_output.output();
1994 if !ret.is_unit() {
1995 write!(f, " -> ")?;
1996 ret.hir_fmt(f)?;
1997 }
1998 Ok(())
1999 }
2000}
2001
2002impl<'db> HirDisplay<'db> for Term<'db> {
2003 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
2004 match self.kind() {
2005 TermKind::Ty(it) => it.hir_fmt(f),
2006 TermKind::Const(it) => it.hir_fmt(f),
2007 }
2008 }
2009}
2010
2011#[derive(Clone, Copy, PartialEq, Eq)]
2012pub enum SizedByDefault {
2013 NotSized,
2014 Sized { anchor: Crate },
2015}
2016
2017impl SizedByDefault {
2018 fn is_sized_trait(self, trait_: TraitId, interner: DbInterner<'_>) -> bool {
2019 match self {
2020 Self::NotSized => false,
2021 Self::Sized { .. } => {
2022 let sized_trait = interner.lang_items().Sized;
2023 Some(trait_) == sized_trait
2024 }
2025 }
2026 }
2027}
2028
2029pub fn write_bounds_like_dyn_trait_with_prefix<'db>(
2030 f: &mut HirFormatter<'_, 'db>,
2031 prefix: &str,
2032 this: Either<Ty<'db>, Region<'db>>,
2033 predicates: &[Clause<'db>],
2034 default_sized: SizedByDefault,
2035 needs_parens_if_multi: bool,
2036) -> Result {
2037 let needs_parens =
2038 needs_parens_if_multi && trait_bounds_need_parens(f, this, predicates, default_sized);
2039 if needs_parens {
2040 write!(f, "(")?;
2041 }
2042 write!(f, "{prefix}")?;
2043 if !predicates.is_empty()
2044 || predicates.is_empty() && matches!(default_sized, SizedByDefault::Sized { .. })
2045 {
2046 write!(f, " ")?;
2047 write_bounds_like_dyn_trait(f, this, predicates, default_sized)?;
2048 }
2049 if needs_parens {
2050 write!(f, ")")?;
2051 }
2052 Ok(())
2053}
2054
2055fn trait_bounds_need_parens<'db>(
2056 f: &mut HirFormatter<'_, 'db>,
2057 this: Either<Ty<'db>, Region<'db>>,
2058 predicates: &[Clause<'db>],
2059 default_sized: SizedByDefault,
2060) -> bool {
2061 let mut distinct_bounds = 0usize;
2063 let mut is_sized = false;
2064 for p in predicates {
2065 match p.kind().skip_binder() {
2066 ClauseKind::Trait(trait_ref) => {
2067 let trait_ = trait_ref.def_id().0;
2068 if default_sized.is_sized_trait(trait_, f.interner) {
2069 is_sized = true;
2070 if matches!(default_sized, SizedByDefault::Sized { .. }) {
2071 continue;
2073 }
2074 }
2075
2076 distinct_bounds += 1;
2077 }
2078 ClauseKind::TypeOutlives(to) if Either::Left(to.0) == this => distinct_bounds += 1,
2079 ClauseKind::RegionOutlives(lo) if Either::Right(lo.0) == this => distinct_bounds += 1,
2080 _ => {}
2081 }
2082 }
2083
2084 if let SizedByDefault::Sized { .. } = default_sized
2085 && !is_sized
2086 {
2087 distinct_bounds += 1;
2088 }
2089
2090 distinct_bounds > 1
2091}
2092
2093fn write_bounds_like_dyn_trait<'db>(
2094 f: &mut HirFormatter<'_, 'db>,
2095 this: Either<Ty<'db>, Region<'db>>,
2096 predicates: &[Clause<'db>],
2097 default_sized: SizedByDefault,
2098) -> Result {
2099 let mut first = true;
2106 let mut angle_open = false;
2107 let mut is_fn_trait = false;
2108 let mut is_sized = false;
2109 for p in predicates {
2110 match p.kind().skip_binder() {
2111 ClauseKind::Trait(trait_ref) => {
2112 let trait_ = trait_ref.def_id().0;
2113 if default_sized.is_sized_trait(trait_, f.interner) {
2114 is_sized = true;
2115 if matches!(default_sized, SizedByDefault::Sized { .. }) {
2116 continue;
2118 }
2119 }
2120 if !is_fn_trait {
2121 is_fn_trait = fn_traits(f.lang_items()).any(|it| it == trait_);
2122 }
2123 if !is_fn_trait && angle_open {
2124 write!(f, ">")?;
2125 angle_open = false;
2126 }
2127 if !first {
2128 write!(f, " + ")?;
2129 }
2130 f.start_location_link(trait_.into());
2134 write!(f, "{}", TraitSignature::of(f.db, trait_).name.display(f.db, f.edition()))?;
2135 f.end_location_link();
2136 if is_fn_trait {
2137 if let [_self, params @ ..] = trait_ref.trait_ref.args.as_slice()
2138 && let Some(args) = params.first().and_then(|it| it.ty()?.as_tuple())
2139 {
2140 write!(f, "(")?;
2141 hir_fmt_tys(f, args.as_slice(), Some(trait_ref.trait_ref.self_ty()))?;
2142 write!(f, ")")?;
2143 }
2144 } else {
2145 let params = generic_args_sans_defaults(
2146 f,
2147 Some(trait_.into()),
2148 trait_ref.trait_ref.args.as_slice(),
2149 );
2150 if let [_self, params @ ..] = params
2151 && !params.is_empty()
2152 {
2153 write!(f, "<")?;
2154 hir_fmt_generic_arguments(f, params, Some(trait_ref.trait_ref.self_ty()))?;
2155 angle_open = true;
2157 }
2158 }
2159 }
2160 ClauseKind::TypeOutlives(to) if Either::Left(to.0) == this => {
2161 if !is_fn_trait && angle_open {
2162 write!(f, ">")?;
2163 angle_open = false;
2164 }
2165 if !first {
2166 write!(f, " + ")?;
2167 }
2168 to.1.hir_fmt(f)?;
2169 }
2170 ClauseKind::RegionOutlives(lo) if Either::Right(lo.0) == this => {
2171 if !is_fn_trait && angle_open {
2172 write!(f, ">")?;
2173 angle_open = false;
2174 }
2175 if !first {
2176 write!(f, " + ")?;
2177 }
2178 lo.1.hir_fmt(f)?;
2179 }
2180 ClauseKind::Projection(projection) if is_fn_trait => {
2181 is_fn_trait = false;
2182 if !projection.term.as_type().is_some_and(|it| it.is_unit()) {
2183 write!(f, " -> ")?;
2184 projection.term.hir_fmt(f)?;
2185 }
2186 }
2187 ClauseKind::Projection(projection) => {
2188 let TermId::TypeAliasId(assoc_ty_id) = projection.def_id().0 else {
2189 continue;
2190 };
2191 if angle_open {
2194 write!(f, ", ")?;
2195 } else {
2196 write!(f, "<")?;
2197 angle_open = true;
2198 }
2199 let type_alias = TypeAliasSignature::of(f.db, assoc_ty_id);
2200 f.start_location_link(assoc_ty_id.into());
2201 write!(f, "{}", type_alias.name.display(f.db, f.edition()))?;
2202 f.end_location_link();
2203
2204 let own_args = projection.projection_term.own_args(f.interner);
2205 if !own_args.is_empty() {
2206 write!(f, "<")?;
2207 hir_fmt_generic_arguments(f, own_args, None)?;
2208 write!(f, ">")?;
2209 }
2210 write!(f, " = ")?;
2211 projection.term.hir_fmt(f)?;
2212 }
2213 _ => {}
2214 }
2215 first = false;
2216 }
2217 if angle_open {
2218 write!(f, ">")?;
2219 }
2220 if let SizedByDefault::Sized { anchor } = default_sized {
2221 let sized_trait = hir_def::lang_item::lang_items(f.db, anchor).Sized;
2222 if !is_sized {
2223 if !first {
2224 write!(f, " + ")?;
2225 }
2226 if let Some(sized_trait) = sized_trait {
2227 f.start_location_link(sized_trait.into());
2228 }
2229 write!(f, "?Sized")?;
2230 } else if first {
2231 if let Some(sized_trait) = sized_trait {
2232 f.start_location_link(sized_trait.into());
2233 }
2234 write!(f, "Sized")?;
2235 }
2236 if sized_trait.is_some() {
2237 f.end_location_link();
2238 }
2239 }
2240 Ok(())
2241}
2242
2243pub fn write_params_bounds<'db>(
2244 f: &mut HirFormatter<'_, 'db>,
2245 predicates: &[Clause<'db>],
2246) -> Result {
2247 let mut per_type = FxIndexMap::<_, Vec<_>>::default();
2249 for &predicate in predicates {
2250 let base_ty = match predicate.kind().skip_binder() {
2251 ClauseKind::Trait(clause) => Either::Left(clause.self_ty()),
2252 ClauseKind::RegionOutlives(clause) => Either::Right(clause.0),
2253 ClauseKind::TypeOutlives(clause) => Either::Left(clause.0),
2254 ClauseKind::Projection(clause) => Either::Left(clause.self_ty()),
2255 ClauseKind::ConstArgHasType(..)
2256 | ClauseKind::WellFormed(_)
2257 | ClauseKind::ConstEvaluatable(_)
2258 | ClauseKind::HostEffect(..)
2259 | ClauseKind::UnstableFeature(_) => continue,
2260 };
2261 per_type.entry(base_ty).or_default().push(predicate);
2262 }
2263
2264 for (base_ty, clauses) in per_type {
2265 f.write_str(" ")?;
2266 match base_ty {
2267 Either::Left(it) => it.hir_fmt(f)?,
2268 Either::Right(it) => it.hir_fmt(f)?,
2269 }
2270 f.write_str(": ")?;
2271 let default_sized = match base_ty {
2275 Either::Left(ty) if matches!(ty.kind(), TyKind::Param(_)) => {
2276 SizedByDefault::Sized { anchor: f.krate() }
2277 }
2278 _ => SizedByDefault::NotSized,
2279 };
2280 write_bounds_like_dyn_trait(f, base_ty, &clauses, default_sized)?;
2281 f.write_str(",\n")?;
2282 }
2283 Ok(())
2284}
2285
2286impl<'db> HirDisplay<'db> for TraitRef<'db> {
2287 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
2288 let trait_ = self.def_id.0;
2289 f.start_location_link(trait_.into());
2290 write!(f, "{}", TraitSignature::of(f.db, trait_).name.display(f.db, f.edition()))?;
2291 f.end_location_link();
2292 let substs = self.args.as_slice();
2293 hir_fmt_generic_args(f, &substs[1..], None, Some(self.self_ty()))
2294 }
2295}
2296
2297impl<'db> HirDisplay<'db> for TraitPredicate<'db> {
2298 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
2299 self.self_ty().hir_fmt(f)?;
2300 f.write_str(": ")?;
2301 match self.polarity {
2302 rustc_type_ir::PredicatePolarity::Positive => {}
2303 rustc_type_ir::PredicatePolarity::Negative => f.write_char('!')?,
2304 }
2305 let trait_ = self.def_id().0;
2306 f.start_location_link(trait_.into());
2307 write!(f, "{}", TraitSignature::of(f.db, trait_).name.display(f.db, f.edition()))?;
2308 f.end_location_link();
2309 let substs = &self.trait_ref.args[1..];
2310 hir_fmt_generic_args(f, substs, None, None)
2311 }
2312}
2313
2314impl<'db> HirDisplay<'db> for Region<'db> {
2315 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
2316 match self.kind() {
2317 RegionKind::ReEarlyParam(param) => {
2318 let generics = GenericParams::of(f.db, param.id.parent);
2319 let param_data = &generics[param.id.local_id];
2320 f.start_location_link_generic(param.id.into());
2321 write!(f, "{}", param_data.name.display(f.db, f.edition()))?;
2322 f.end_location_link();
2323 Ok(())
2324 }
2325 RegionKind::ReBound(BoundVarIndexKind::Bound(db), idx) => {
2326 write!(f, "'?{}.{}", db.as_u32(), idx.var.as_u32())
2327 }
2328 RegionKind::ReBound(BoundVarIndexKind::Canonical, idx) => {
2329 write!(f, "'?c.{}", idx.var.as_u32())
2330 }
2331 RegionKind::ReVar(_) => write!(f, "_"),
2332 RegionKind::ReStatic => write!(f, "'static"),
2333 RegionKind::ReError(..) => {
2334 if cfg!(test) {
2335 write!(f, "'?")
2336 } else {
2337 write!(f, "'_")
2338 }
2339 }
2340 RegionKind::ReErased => write!(f, "'<erased>"),
2341 RegionKind::RePlaceholder(_) => write!(f, "'<placeholder>"),
2342 RegionKind::ReLateParam(_) => write!(f, "'_"),
2343 }
2344 }
2345}
2346
2347pub fn write_visibility<'db>(
2348 module_id: ModuleId,
2349 vis: Visibility,
2350 f: &mut HirFormatter<'_, 'db>,
2351) -> Result {
2352 match vis {
2353 Visibility::Public => write!(f, "pub "),
2354 Visibility::PubCrate(_) => write!(f, "pub(crate) "),
2355 Visibility::Module(vis_id, _) => {
2356 let def_map = module_id.def_map(f.db);
2357 let root_module_id = def_map.root_module_id();
2358 if vis_id == module_id {
2359 Ok(())
2361 } else if root_module_id == vis_id && root_module_id.block(f.db).is_none() {
2362 write!(f, "pub(crate) ")
2363 } else if module_id.containing_module(f.db) == Some(vis_id)
2364 && !vis_id.is_block_module(f.db)
2365 {
2366 write!(f, "pub(super) ")
2367 } else {
2368 write!(f, "pub(in ...) ")
2369 }
2370 }
2371 }
2372}
2373
2374pub trait HirDisplayWithExpressionStore<'db> {
2375 fn hir_fmt(
2376 &self,
2377 f: &mut HirFormatter<'_, 'db>,
2378 owner: ExpressionStoreOwnerId,
2379 store: &ExpressionStore,
2380 ) -> Result;
2381}
2382
2383impl<'db, T: ?Sized + HirDisplayWithExpressionStore<'db>> HirDisplayWithExpressionStore<'db>
2384 for &'_ T
2385{
2386 fn hir_fmt(
2387 &self,
2388 f: &mut HirFormatter<'_, 'db>,
2389 owner: ExpressionStoreOwnerId,
2390 store: &ExpressionStore,
2391 ) -> Result {
2392 T::hir_fmt(&**self, f, owner, store)
2393 }
2394}
2395
2396pub fn hir_display_with_store<'a, 'db, T: HirDisplayWithExpressionStore<'db> + 'a>(
2397 value: T,
2398 owner: ExpressionStoreOwnerId,
2399 store: &'a ExpressionStore,
2400) -> impl HirDisplay<'db> + 'a {
2401 ExpressionStoreAdapter(value, owner, store)
2402}
2403
2404struct ExpressionStoreAdapter<'a, T>(T, ExpressionStoreOwnerId, &'a ExpressionStore);
2405
2406impl<'a, T> ExpressionStoreAdapter<'a, T> {
2407 fn wrap(
2408 owner: ExpressionStoreOwnerId,
2409 store: &'a ExpressionStore,
2410 ) -> impl Fn(T) -> ExpressionStoreAdapter<'a, T> {
2411 move |value| ExpressionStoreAdapter(value, owner, store)
2412 }
2413}
2414
2415impl<'db, T: HirDisplayWithExpressionStore<'db>> HirDisplay<'db> for ExpressionStoreAdapter<'_, T> {
2416 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
2417 T::hir_fmt(&self.0, f, self.1, self.2)
2418 }
2419}
2420impl<'db> HirDisplayWithExpressionStore<'db> for LifetimeRefId {
2421 fn hir_fmt(
2422 &self,
2423 f: &mut HirFormatter<'_, 'db>,
2424 _owner: ExpressionStoreOwnerId,
2425 store: &ExpressionStore,
2426 ) -> Result {
2427 match &store[*self] {
2428 LifetimeRef::Named(name) => write!(f, "{}", name.display(f.db, f.edition())),
2429 LifetimeRef::Static => write!(f, "'static"),
2430 LifetimeRef::Placeholder => write!(f, "'_"),
2431 LifetimeRef::Error => write!(f, "'{{error}}"),
2432 &LifetimeRef::Param(lifetime_param_id) => {
2433 let generic_params = GenericParams::of(f.db, lifetime_param_id.parent);
2434 write!(
2435 f,
2436 "{}",
2437 generic_params[lifetime_param_id.local_id].name.display(f.db, f.edition())
2438 )
2439 }
2440 }
2441 }
2442}
2443
2444impl<'db> HirDisplayWithExpressionStore<'db> for TypeRefId {
2445 fn hir_fmt(
2446 &self,
2447 f: &mut HirFormatter<'_, 'db>,
2448 owner: ExpressionStoreOwnerId,
2449 store: &ExpressionStore,
2450 ) -> Result {
2451 match &store[*self] {
2452 TypeRef::Never => write!(f, "!")?,
2453 TypeRef::TypeParam(param) => {
2454 let generic_params = GenericParams::of(f.db, param.parent());
2455 match generic_params[param.local_id()].name() {
2456 Some(name) => write!(f, "{}", name.display(f.db, f.edition()))?,
2457 None => {
2458 write!(f, "impl ")?;
2459 f.write_joined(
2460 generic_params
2461 .where_predicates()
2462 .iter()
2463 .filter_map(|it| match it {
2464 WherePredicate::TypeBound { lifetimes: _, target, bound }
2465 if matches!(
2466 store[*target],
2467 TypeRef::TypeParam(t) if t == *param
2468 ) =>
2469 {
2470 Some(bound)
2471 }
2472 _ => None,
2473 })
2474 .map(ExpressionStoreAdapter::wrap(owner, store)),
2475 " + ",
2476 )?;
2477 }
2478 }
2479 }
2480 TypeRef::Placeholder => write!(f, "_")?,
2481 TypeRef::Tuple(elems) => {
2482 write!(f, "(")?;
2483 f.write_joined(elems.iter().map(ExpressionStoreAdapter::wrap(owner, store)), ", ")?;
2484 if elems.len() == 1 {
2485 write!(f, ",")?;
2486 }
2487 write!(f, ")")?;
2488 }
2489 TypeRef::Path(path) => path.hir_fmt(f, owner, store)?,
2490 TypeRef::RawPtr(inner, mutability) => {
2491 let mutability = match mutability {
2492 hir_def::type_ref::Mutability::Shared => "*const ",
2493 hir_def::type_ref::Mutability::Mut => "*mut ",
2494 };
2495 write!(f, "{mutability}")?;
2496 inner.hir_fmt(f, owner, store)?;
2497 }
2498 TypeRef::Reference(ref_) => {
2499 let mutability = match ref_.mutability {
2500 hir_def::type_ref::Mutability::Shared => "",
2501 hir_def::type_ref::Mutability::Mut => "mut ",
2502 };
2503 write!(f, "&")?;
2504 if let Some(lifetime) = &ref_.lifetime {
2505 lifetime.hir_fmt(f, owner, store)?;
2506 write!(f, " ")?;
2507 }
2508 write!(f, "{mutability}")?;
2509 ref_.ty.hir_fmt(f, owner, store)?;
2510 }
2511 TypeRef::Array(array) => {
2512 write!(f, "[")?;
2513 array.ty.hir_fmt(f, owner, store)?;
2514 write!(f, "; ")?;
2515 array.len.hir_fmt(f, owner, store)?;
2516 write!(f, "]")?;
2517 }
2518 TypeRef::Slice(inner) => {
2519 write!(f, "[")?;
2520 inner.hir_fmt(f, owner, store)?;
2521 write!(f, "]")?;
2522 }
2523 TypeRef::Fn(fn_) => {
2524 if let Some(binder) = &fn_.binder {
2525 let edition = f.edition();
2526 write!(
2527 f,
2528 "for<{}> ",
2529 binder.iter().map(|it| it.display(f.db, edition)).format(", ")
2530 )?;
2531 }
2532 if fn_.is_unsafe {
2533 write!(f, "unsafe ")?;
2534 }
2535 if fn_.abi != ExternAbi::Rust {
2536 f.write_str("extern \"")?;
2537 f.write_str(fn_.abi.as_str())?;
2538 f.write_str("\" ")?;
2539 }
2540 write!(f, "fn(")?;
2541 if let Some(((_, return_type), function_parameters)) = fn_.params.split_last() {
2542 for index in 0..function_parameters.len() {
2543 let (param_name, param_type) = &function_parameters[index];
2544 if let Some(name) = param_name {
2545 write!(f, "{}: ", name.display(f.db, f.edition()))?;
2546 }
2547
2548 param_type.hir_fmt(f, owner, store)?;
2549
2550 if index != function_parameters.len() - 1 {
2551 write!(f, ", ")?;
2552 }
2553 }
2554 if fn_.is_varargs {
2555 write!(f, "{}...", if fn_.params.len() == 1 { "" } else { ", " })?;
2556 }
2557 write!(f, ")")?;
2558 match &store[*return_type] {
2559 TypeRef::Tuple(tup) if tup.is_empty() => {}
2560 _ => {
2561 write!(f, " -> ")?;
2562 return_type.hir_fmt(f, owner, store)?;
2563 }
2564 }
2565 }
2566 }
2567 TypeRef::ImplTrait(bounds) => {
2568 write!(f, "impl ")?;
2569 f.write_joined(
2570 bounds.iter().map(ExpressionStoreAdapter::wrap(owner, store)),
2571 " + ",
2572 )?;
2573 }
2574 TypeRef::DynTrait(bounds) => {
2575 write!(f, "dyn ")?;
2576 f.write_joined(
2577 bounds.iter().map(ExpressionStoreAdapter::wrap(owner, store)),
2578 " + ",
2579 )?;
2580 }
2581 TypeRef::PatternType(ty, pat) => {
2582 ty.hir_fmt(f, owner, store)?;
2583 write!(f, " is ")?;
2584 pat.hir_fmt(f, owner, store)?;
2585 }
2586 TypeRef::Error => write!(f, "{{error}}")?,
2587 }
2588 Ok(())
2589 }
2590}
2591
2592impl<'db> HirDisplayWithExpressionStore<'db> for ConstRef {
2593 fn hir_fmt(
2594 &self,
2595 f: &mut HirFormatter<'_, 'db>,
2596 _owner: ExpressionStoreOwnerId,
2597 _store: &ExpressionStore,
2598 ) -> Result {
2599 write!(f, "{{const}}")?;
2601
2602 Ok(())
2603 }
2604}
2605
2606impl<'db> HirDisplayWithExpressionStore<'db> for PatId {
2607 fn hir_fmt(
2608 &self,
2609 f: &mut HirFormatter<'_, 'db>,
2610 owner: ExpressionStoreOwnerId,
2611 store: &ExpressionStore,
2612 ) -> Result {
2613 write!(
2614 f,
2615 "{}",
2616 hir_def::expr_store::pretty::print_pat_hir(
2617 f.db,
2618 store,
2619 owner,
2620 *self,
2621 false,
2622 f.edition()
2623 )
2624 )?;
2625 Ok(())
2626 }
2627}
2628
2629impl<'db> HirDisplayWithExpressionStore<'db> for TypeBound {
2630 fn hir_fmt(
2631 &self,
2632 f: &mut HirFormatter<'_, 'db>,
2633 owner: ExpressionStoreOwnerId,
2634 store: &ExpressionStore,
2635 ) -> Result {
2636 match self {
2637 &TypeBound::Path(path, modifier) => {
2638 match modifier {
2639 TraitBoundModifier::None => (),
2640 TraitBoundModifier::Maybe => write!(f, "?")?,
2641 }
2642 store[path].hir_fmt(f, owner, store)
2643 }
2644 TypeBound::Lifetime(lifetime) => lifetime.hir_fmt(f, owner, store),
2645 TypeBound::ForLifetime(lifetimes, path) => {
2646 let edition = f.edition();
2647 write!(
2648 f,
2649 "for<{}> ",
2650 lifetimes.iter().map(|it| it.display(f.db, edition)).format(", ")
2651 )?;
2652 store[*path].hir_fmt(f, owner, store)
2653 }
2654 TypeBound::Use(args) => {
2655 write!(f, "use<")?;
2656 let edition = f.edition();
2657 let last = args.len().saturating_sub(1);
2658 for (idx, arg) in args.iter().enumerate() {
2659 match arg {
2660 UseArgRef::Lifetime(lt) => lt.hir_fmt(f, owner, store)?,
2661 UseArgRef::Name(n) => write!(f, "{}", n.display(f.db, edition))?,
2662 }
2663 if idx != last {
2664 write!(f, ", ")?;
2665 }
2666 }
2667 write!(f, "> ")
2668 }
2669 TypeBound::Error => write!(f, "{{error}}"),
2670 }
2671 }
2672}
2673
2674impl<'db> HirDisplayWithExpressionStore<'db> for Path {
2675 fn hir_fmt(
2676 &self,
2677 f: &mut HirFormatter<'_, 'db>,
2678 owner: ExpressionStoreOwnerId,
2679 store: &ExpressionStore,
2680 ) -> Result {
2681 match (self.type_anchor(), self.kind()) {
2682 (Some(anchor), _) => {
2683 write!(f, "<")?;
2684 anchor.hir_fmt(f, owner, store)?;
2685 write!(f, ">")?;
2686 }
2687 (_, PathKind::Plain) => {}
2688 (_, PathKind::Abs) => {}
2689 (_, PathKind::Crate) => write!(f, "crate")?,
2690 (_, &PathKind::SELF) => write!(f, "self")?,
2691 (_, PathKind::Super(n)) => {
2692 for i in 0..*n {
2693 if i > 0 {
2694 write!(f, "::")?;
2695 }
2696 write!(f, "super")?;
2697 }
2698 }
2699 (_, PathKind::DollarCrate(id)) => {
2700 let crate_data = id.extra_data(f.db);
2704 let name = crate_data
2705 .display_name
2706 .as_ref()
2707 .map(|name| (*name.canonical_name()).clone())
2708 .unwrap_or(sym::dollar_crate);
2709 write!(f, "{name}")?
2710 }
2711 }
2712
2713 let trait_self_ty = self.segments().iter().find_map(|seg| {
2722 let generic_args = seg.args_and_bindings?;
2723 generic_args.has_self_type.then(|| &generic_args.args[0])
2724 });
2725 if let Some(ty) = trait_self_ty {
2726 write!(f, "<")?;
2727 ty.hir_fmt(f, owner, store)?;
2728 write!(f, " as ")?;
2729 }
2731
2732 for (seg_idx, segment) in self.segments().iter().enumerate() {
2733 if !matches!(self.kind(), PathKind::Plain) || seg_idx > 0 {
2734 write!(f, "::")?;
2735 }
2736 write!(f, "{}", segment.name.display(f.db, f.edition()))?;
2737 if let Some(generic_args) = segment.args_and_bindings {
2738 match generic_args.parenthesized {
2741 hir_def::expr_store::path::GenericArgsParentheses::ReturnTypeNotation => {
2742 write!(f, "(..)")?;
2743 }
2744 hir_def::expr_store::path::GenericArgsParentheses::ParenSugar => {
2745 let tuple = match generic_args.args[0] {
2748 hir_def::expr_store::path::GenericArg::Type(ty) => match &store[ty] {
2749 TypeRef::Tuple(it) => Some(it),
2750 _ => None,
2751 },
2752 _ => None,
2753 };
2754 if let Some(v) = tuple {
2755 if v.len() == 1 {
2756 write!(f, "(")?;
2757 v[0].hir_fmt(f, owner, store)?;
2758 write!(f, ")")?;
2759 } else {
2760 generic_args.args[0].hir_fmt(f, owner, store)?;
2761 }
2762 }
2763 if let Some(ret) = generic_args.bindings[0].type_ref
2764 && !matches!(&store[ret], TypeRef::Tuple(v) if v.is_empty())
2765 {
2766 write!(f, " -> ")?;
2767 ret.hir_fmt(f, owner, store)?;
2768 }
2769 }
2770 hir_def::expr_store::path::GenericArgsParentheses::No => {
2771 let mut first = true;
2772 for arg in &generic_args.args[generic_args.has_self_type as usize..] {
2774 if first {
2775 first = false;
2776 write!(f, "<")?;
2777 } else {
2778 write!(f, ", ")?;
2779 }
2780 arg.hir_fmt(f, owner, store)?;
2781 }
2782 for binding in generic_args.bindings.iter() {
2783 if first {
2784 first = false;
2785 write!(f, "<")?;
2786 } else {
2787 write!(f, ", ")?;
2788 }
2789 write!(f, "{}", binding.name.display(f.db, f.edition()))?;
2790 match &binding.type_ref {
2791 Some(ty) => {
2792 write!(f, " = ")?;
2793 ty.hir_fmt(f, owner, store)?
2794 }
2795 None => {
2796 write!(f, ": ")?;
2797 f.write_joined(
2798 binding
2799 .bounds
2800 .iter()
2801 .map(ExpressionStoreAdapter::wrap(owner, store)),
2802 " + ",
2803 )?;
2804 }
2805 }
2806 }
2807
2808 if !first {
2811 write!(f, ">")?;
2812 }
2813
2814 if generic_args.has_self_type {
2816 write!(f, ">")?;
2817 }
2818 }
2819 }
2820 }
2821 }
2822
2823 Ok(())
2824 }
2825}
2826
2827impl<'db> HirDisplayWithExpressionStore<'db> for hir_def::expr_store::path::GenericArg {
2828 fn hir_fmt(
2829 &self,
2830 f: &mut HirFormatter<'_, 'db>,
2831 owner: ExpressionStoreOwnerId,
2832 store: &ExpressionStore,
2833 ) -> Result {
2834 match self {
2835 hir_def::expr_store::path::GenericArg::Type(ty) => ty.hir_fmt(f, owner, store),
2836 hir_def::expr_store::path::GenericArg::Const(_c) => {
2837 write!(f, "<expr>")
2839 }
2840 hir_def::expr_store::path::GenericArg::Lifetime(lifetime) => {
2841 lifetime.hir_fmt(f, owner, store)
2842 }
2843 }
2844 }
2845}