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