Skip to main content

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