Skip to main content

hir_ide/
display.rs

1//! The `HirDisplay` trait, which serves two purposes: Turning various bits from
2//! HIR back into source code, and just displaying them for debugging/testing
3//! purposes.
4
5use 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
109// String will ignore link metadata
110impl HirWrite for String {}
111
112// `core::Formatter` will ignore metadata
113impl HirWrite for fmt::Formatter<'_> {}
114
115pub struct HirFormatter<'a, 'db> {
116    /// The database handle
117    pub db: &'db dyn HirDatabase,
118    pub interner: DbInterner<'db>,
119    /// The sink to write into
120    fmt: &'a mut dyn HirWrite,
121    /// A buffer to intercept writes with, this allows us to track the overall size of the formatted output.
122    buf: String,
123    /// The current size of the formatted output.
124    curr_size: usize,
125    /// Size from which we should truncate the output.
126    max_size: Option<usize>,
127    /// When rendering something that has a concept of "children" (like fields in a struct), this limits
128    /// how many should be rendered.
129    pub entity_limit: Option<usize>,
130    /// When rendering functions, whether to show the constraint from the container
131    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    /// We can have recursive bounds like the following case:
139    /// ```ignore
140    /// where
141    ///     T: Foo,
142    ///     T::FooAssoc: Baz<<T::FooAssoc as Bar>::BarAssoc> + Bar
143    /// ```
144    /// So, record the projection types met while formatting bounds and
145    /// prevent recursing into their bounds to avoid infinite loops.
146    currently_formatting_bounds: FxHashSet<AliasTy<'db>>,
147    /// Whether formatting `impl Trait1 + Trait2` or `dyn Trait1 + Trait2` needs parentheses around it,
148    /// for example when formatting `&(impl Trait1 + Trait2)`.
149    trait_bounds_need_parens: bool,
150}
151
152// FIXME: To consider, ref and dyn trait lifetimes can be omitted if they are `'_`, path args should
153// not be when in signatures
154// So this enum does not encode this well enough
155// Also 'static can be omitted for ref and dyn trait lifetimes in static/const item types
156// FIXME: Also named lifetimes may be rendered in places where their name is not in scope?
157#[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    /// Returns a `Display`able type that is human-readable.
238    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    /// Returns a `Display`able type that is human-readable.
272    /// Use this for showing types to the user (e.g. diagnostics)
273    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    /// Returns a `Display`able type that is human-readable and tries to be succinct.
297    /// Use this for showing types to the user where space is constrained (e.g. doc popups)
298    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    /// Returns a `Display`able type that is human-readable and tries to limit the number of items inside.
323    /// Use this for showing definitions which may contain too many items, like `trait`, `struct`, `enum`
324    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    /// Returns a String representation of `self` that can be inserted into the given module.
349    /// Use this when generating code (e.g. assists)
350    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    /// Returns a String representation of `self` for test purposes
384    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    /// Returns a String representation of `self` that shows the constraint from
408    /// the container for functions
409    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            // Abbreviate multiple omitted types with a single ellipsis.
461            if self.should_truncate() {
462                return write!(self, "{TYPE_HINT_TRUNCATION}");
463            }
464
465            e.hir_fmt(self)?;
466        }
467        Ok(())
468    }
469
470    /// This allows using the `write!` macro directly with a `HirFormatter`.
471    pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result {
472        // We write to a buffer first to track output size
473        self.buf.clear();
474        fmt::write(&mut self.buf, args)?;
475        self.curr_size += self.buf.len();
476
477        // Then we write to the internal formatter from the buffer
478        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    /// Display types for inlays, doc popups, autocompletion, etc...
532    /// Showing `{unknown}` or not qualifying paths is fine here.
533    /// There's no reason for this to fail.
534    Diagnostics,
535    /// Display types for inserting them in source files.
536    /// The generated code should compile, so paths need to be qualified.
537    SourceCode { target_module_id: ModuleId, allow_opaque: bool },
538    /// Only for test purpose to keep real types
539    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    /// Errors that can occur when generating source code
565    DisplaySourceCodeError(DisplaySourceCodeError),
566    /// `FmtError` is required to be compatible with std::fmt::Display
567    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    /// `impl FnX(i32, i32) -> i32`, where `FnX` is the most special trait between `Fn`, `FnMut`, `FnOnce` that the
592    /// closure implements. This is the default.
593    ImplFn,
594    /// `|i32, i32| -> i32`
595    RANotation,
596    /// `{closure#14825}`, useful for some diagnostics (like type mismatch) and internal usage.
597    ClosureWithId,
598    /// `{closure#14825}<i32, ()>`, useful for internal usage.
599    ClosureWithSubst,
600    /// `…`, which is the `TYPE_HINT_TRUNCATION`
601    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                // This should never happen
654                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 we are projection on a type parameter, check if the projection target has bounds
690        // itself, if so, we render them directly as `impl Bound` instead of the less useful
691        // `<Param as Trait>::Assoc`
692        if !f.display_kind.is_source_code()
693            && let TyKind::Param(param) = self_ty.kind()
694        {
695            // FIXME: We shouldn't use `param.id`, it should be removed. We should know the
696            // `GenericDefId` from the formatted type (store it inside the `HirFormatter`).
697            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                // FIXME(#17451): Replace with builtins once they are stabilised.
848                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                    // Match Rust debug formatting
852                    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                // FIXME(#17451): Replace with builtins once they are stabilised.
867                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                    // Match Rust debug formatting
871                    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        // The below arms are unreachable, since const eval will bail out before here.
1070        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        // The below arms are unreachable, since we handled them in ref case.
1079        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                // FIXME(#17451): Replace with builtins once they are stabilised.
1121                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                    // Match Rust debug formatting
1125                    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                // FIXME(#17451): Replace with builtins once they are stabilised.
1140                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                    // Match Rust debug formatting
1144                    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            // FIXME: ADTs, requires `adt_const_params`.
1201            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        // The below arms are unreachable, since const eval will bail out before here.
1216        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                    // `FnDef` is anonymous and there's no surface syntax for it. Show it as a
1359                    // function pointer type.
1360                    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                    // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
1407                    if parameters.len() - impl_ > 0 {
1408                        let params_len = parameters.len();
1409                        // `parameters` are in the order of fn's params (including impl traits), fn's lifetimes
1410                        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                        // Normally, functions cannot have default parameters, but they can,
1416                        // for function-like things such as struct names or enum variants.
1417                        // The former cannot have defaults but does have parents,
1418                        // but the latter cannot have parents but can have defaults.
1419                        //
1420                        // However, it's also true that *traits* can have defaults too.
1421                        // In this case, there can be no function params.
1422                        let parent_end = if parent_len > 0 {
1423                            // If `parent_len` > 0, then there cannot be defaults on the function
1424                            // and all defaults must come from the parent.
1425                            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                            // FIXME: no_std Cfg?
1476                            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                        // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
1521                    }
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                // FIXME: We should not access `param.id`, it should be removed, and we should know the
1663                // parent from the formatted type.
1664                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                // We want to put auto traits after principal traits, regardless of their written order.
1719                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, &parameters[..i])
1896                            .skip_norm_wip()
1897                    }
1898                };
1899                let mut default_from = 0;
1900                for (i, &parameter) in parameters.iter().enumerate() {
1901                    if should_show(parameter, i) {
1902                        default_from = i + 1;
1903                    }
1904                }
1905                &parameters[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    // This needs to be kept in sync with `write_bounds_like_dyn_trait()`.
2068    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                        // Don't print +Sized, but rather +?Sized if absent.
2078                        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    // Note: This code is written to produce nice results (i.e.
2106    // corresponding to surface Rust) for types that can occur in
2107    // actual Rust. It will have weird results if the predicates
2108    // aren't as expected (i.e. self types = $0, projection
2109    // predicates for a certain trait come after the Implemented
2110    // predicate for that trait).
2111    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                        // Don't print +Sized, but rather +?Sized if absent.
2123                        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                // We assume that the self type is ^0.0 (i.e. the
2137                // existential) here, which is the only thing that's
2138                // possible in actual Rust, and hence don't print it
2139                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                        // there might be assoc type bindings, so we leave the angle brackets open
2162                        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                // in types in actual Rust, these will always come
2198                // after the corresponding Implemented predicate
2199                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    // Use an FxIndexMap to keep user's order, as far as possible.
2254    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        // Rudimentary approximation: type params are `Sized` by default, everything else not.
2278        // FIXME: This is not correct, really. But I'm not sure how we can from the ty representation
2279        // to extract the default sizedness, and if it's possible at all.
2280        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                // pub(self) or omitted
2366                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        // FIXME
2606        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                // Resolve `$crate` to the crate's display name.
2707                // FIXME: should use the dependency name instead if available, but that depends on
2708                // the crate invoking `HirDisplay`
2709                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        // Convert trait's `Self` bound back to the surface syntax. Note there is no associated
2720        // trait, so there can only be one path segment that `has_self_type`. The `Self` type
2721        // itself can contain further qualified path through, which will be handled by recursive
2722        // `hir_fmt`s.
2723        //
2724        // `trait_mod::Trait<Self = type_mod::Type, Args>::Assoc`
2725        // =>
2726        // `<type_mod::Type as trait_mod::Trait<Args>>::Assoc`
2727        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            // Now format the path of the trait...
2736        }
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                // We should be in type context, so format as `Foo<Bar>` instead of `Foo::<Bar>`.
2745                // Do we actually format expressions?
2746                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                        // First argument will be a tuple, which already includes the parentheses.
2752                        // If the tuple only contains 1 item, write it manually to avoid the trailing `,`.
2753                        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                        // Skip the `Self` bound if exists. It's handled outside the loop.
2779                        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                        // There may be no generic arguments to print, in case of a trait having only a
2815                        // single `Self` bound which is converted to `<Ty as Trait>::Assoc`.
2816                        if !first {
2817                            write!(f, ">")?;
2818                        }
2819
2820                        // Current position: `<Ty as Trait<Args>|`
2821                        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, "{}", c.display(f.db, f.edition()))
2844                write!(f, "<expr>")
2845            }
2846            hir_def::expr_store::path::GenericArg::Lifetime(lifetime) => {
2847                lifetime.hir_fmt(f, owner, store)
2848            }
2849        }
2850    }
2851}