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