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