Skip to main content

hir/
display.rs

1//! HirDisplay implementations for various hir types.
2
3use either::Either;
4use hir_def::{
5    AdtId, BuiltinDeriveImplId, DefWithBodyId, ExpressionStoreOwnerId, FunctionId, GenericDefId,
6    ImplId, ItemContainerId,
7    builtin_derive::BuiltinDeriveImplMethod,
8    expr_store::{Body, ExpressionStore},
9    hir::generics::{GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate},
10    item_tree::FieldsShape,
11    layout::ExternAbi,
12    signatures::{
13        ConstSignature, FunctionSignature, ImplSignature, StaticFlags, StaticSignature, TraitFlags,
14        TraitSignature, TypeAliasSignature,
15    },
16    type_ref::{TypeBound, TypeRef, TypeRefId},
17    visibility::Visibility,
18};
19use hir_expand::name::Name;
20use hir_ty::{
21    GenericPredicates,
22    db::HirDatabase,
23    display::{
24        HirDisplay, HirDisplayWithExpressionStore, HirFormatter, Result, SizedByDefault,
25        hir_display_with_store, write_bounds_like_dyn_trait_with_prefix, write_params_bounds,
26        write_visibility,
27    },
28    next_solver::{ClauseKind, Unnormalized},
29};
30use itertools::Itertools;
31use rustc_type_ir::inherent::IntoKind as _;
32
33use crate::{
34    Adt, AnyFunctionId, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Crate, Enum,
35    EnumVariant, ExternCrateDecl, Field, Function, GenericParam, HasCrate, HasVisibility, Impl,
36    LifetimeParam, Macro, Module, SelfParam, Static, Struct, StructKind, Trait, TraitPredicate,
37    TraitRef, TupleField, Type, TypeAlias, TypeOrConstParam, TypeParam, Union,
38};
39
40fn write_builtin_derive_impl_method<'db>(
41    f: &mut HirFormatter<'_, 'db>,
42    impl_: BuiltinDeriveImplId,
43    method: BuiltinDeriveImplMethod,
44) -> Result {
45    let db = f.db;
46    let loc = impl_.loc(db);
47    let adt_params = GenericParams::of(db, loc.adt.into());
48
49    if f.show_container_bounds() && !adt_params.is_empty() {
50        f.write_str("impl")?;
51        write_generic_params(loc.adt.into(), f)?;
52        f.write_char(' ')?;
53        let trait_id = loc.trait_.get_id(f.lang_items());
54        if let Some(trait_id) = trait_id {
55            f.start_location_link(trait_id.into());
56        }
57        write!(f, "{}", Name::new_symbol_root(loc.trait_.name()).display(db, f.edition()))?;
58        if trait_id.is_some() {
59            f.end_location_link();
60        }
61        f.write_str(" for ")?;
62        f.start_location_link(loc.adt.into());
63        write!(f, "{}", Adt::from(loc.adt).name(db).display(db, f.edition()))?;
64        f.end_location_link();
65        write_generic_args(loc.adt.into(), f)?;
66        f.write_char('\n')?;
67    }
68
69    let Some(trait_method) = method.trait_method(db, impl_) else {
70        return write!(f, "fn {}(…)", method.name());
71    };
72    let has_written_where = write_function(f, trait_method)?;
73
74    if f.show_container_bounds() && !adt_params.is_empty() {
75        if !has_written_where {
76            f.write_str("\nwhere")?
77        }
78        write!(f, "\n    // Bounds from impl:")?;
79
80        let predicates =
81            hir_ty::builtin_derive::predicates(db, impl_).explicit_predicates().skip_binder();
82        write_params_bounds(f, &Vec::from_iter(predicates))?;
83    }
84
85    Ok(())
86}
87
88impl<'db> HirDisplay<'db> for Function {
89    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
90        let id = match self.id {
91            AnyFunctionId::FunctionId(id) => id,
92            AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } => {
93                return write_builtin_derive_impl_method(f, impl_, method);
94            }
95        };
96
97        let db = f.db;
98        let container = id.loc(db).container;
99
100        // Write container (trait or impl)
101        let container_params = match container {
102            ItemContainerId::TraitId(trait_) => {
103                let (params, params_store) = GenericParams::with_store(f.db, trait_.into());
104                if f.show_container_bounds() && !params.is_empty() {
105                    write_trait_header(trait_.into(), f)?;
106                    f.write_char('\n')?;
107                    has_disaplayable_predicates(f.db, params, params_store).then_some((
108                        params,
109                        trait_.into(),
110                        params_store,
111                    ))
112                } else {
113                    None
114                }
115            }
116            ItemContainerId::ImplId(impl_) => {
117                let (params, params_store) = GenericParams::with_store(f.db, impl_.into());
118                if f.show_container_bounds() && !params.is_empty() {
119                    write_impl_header(impl_, f)?;
120                    f.write_char('\n')?;
121                    has_disaplayable_predicates(f.db, params, params_store).then_some((
122                        params,
123                        impl_.into(),
124                        params_store,
125                    ))
126                } else {
127                    None
128                }
129            }
130            _ => None,
131        };
132
133        // Write signature of the function
134
135        let has_written_where = write_function(f, id)?;
136        if let Some((container_params, owner, container_params_store)) = container_params {
137            if !has_written_where {
138                f.write_str("\nwhere")?;
139            }
140            let container_name = match container {
141                ItemContainerId::TraitId(_) => "trait",
142                ItemContainerId::ImplId(_) => "impl",
143                _ => unreachable!(),
144            };
145            write!(f, "\n    // Bounds from {container_name}:",)?;
146            write_where_predicates(
147                container_params,
148                ExpressionStoreOwnerId::Signature(owner),
149                container_params_store,
150                f,
151            )?;
152        }
153        Ok(())
154    }
155}
156
157fn write_function<'db>(f: &mut HirFormatter<'_, 'db>, func_id: FunctionId) -> Result<bool> {
158    let db = f.db;
159    let func = Function::from(func_id);
160    let data = FunctionSignature::of(db, func_id);
161
162    let mut module = func.module(db);
163    // Block-local impls are "hoisted" to the nearest (non-block) module.
164    if let ItemContainerId::ImplId(_) = func_id.loc(db).container {
165        module = module.nearest_non_block_module(db);
166    }
167    let module_id = module.id;
168
169    write_visibility(module_id, func.visibility(db), f)?;
170
171    if data.is_default() {
172        f.write_str("default ")?;
173    }
174    if data.is_const() {
175        f.write_str("const ")?;
176    }
177    if data.is_async() {
178        f.write_str("async ")?;
179    }
180    if data.is_gen() {
181        f.write_str("gen ")?;
182    }
183    // FIXME: This will show `unsafe` for functions that are `#[target_feature]` but not unsafe
184    // (they are conditionally unsafe to call). We probably should show something else.
185    if func.is_unsafe_to_call(db, None, f.edition()) {
186        f.write_str("unsafe ")?;
187    }
188    if data.abi != ExternAbi::Rust {
189        write!(f, "extern \"{}\" ", data.abi.as_str())?;
190    }
191    write!(f, "fn {}", data.name.display(f.db, f.edition()))?;
192
193    write_generic_params(GenericDefId::FunctionId(func_id), f)?;
194
195    let too_long_param = data.params.len() > 4;
196    f.write_char('(')?;
197
198    if too_long_param {
199        f.write_str("\n    ")?;
200    }
201
202    let mut first = true;
203    let mut skip_self = 0;
204    if let Some(self_param) = func.self_param(db) {
205        self_param.hir_fmt(f)?;
206        first = false;
207        skip_self = 1;
208    }
209
210    let comma = if too_long_param { ",\n    " } else { ", " };
211    // FIXME: Use resolved `param.ty` once we no longer discard lifetimes
212    let body = Body::of(db, func_id.into());
213    let owner = DefWithBodyId::FunctionId(func_id).into();
214    for (type_ref, param) in data.params.iter().zip(func.assoc_fn_params(db)).skip(skip_self) {
215        if !first {
216            f.write_str(comma)?;
217        } else {
218            first = false;
219        }
220
221        let pat_id = body.params[param.idx - body.self_param.is_some() as usize].user_written;
222        let pat_str = body.pretty_print_pat(db, owner, pat_id, true, f.edition());
223        f.write_str(&pat_str)?;
224
225        f.write_str(": ")?;
226        type_ref.hir_fmt(f, owner, &data.store)?;
227    }
228
229    if data.is_varargs() {
230        if !first {
231            f.write_str(comma)?;
232        }
233        f.write_str("...")?;
234    }
235
236    if too_long_param {
237        f.write_char('\n')?;
238    }
239    f.write_char(')')?;
240
241    // `FunctionData::ret_type` will be `::core::future::Future<Output = ...>` for async fns.
242    // Use ugly pattern match to strip the Future trait.
243    // Better way?
244    let ret_type = if !data.is_async() && !data.is_gen() {
245        data.ret_type
246    } else if let Some(ret_type) = data.ret_type {
247        match &data.store[ret_type] {
248            TypeRef::ImplTrait(bounds) => match &bounds[0] {
249                &TypeBound::Path(path, _) => Some(
250                    *data.store[path]
251                        .segments()
252                        .iter()
253                        .last()
254                        .unwrap()
255                        .args_and_bindings
256                        .unwrap()
257                        .bindings[0]
258                        .type_ref
259                        .as_ref()
260                        .unwrap(),
261                ),
262                _ => None,
263            },
264            _ => None,
265        }
266    } else {
267        None
268    };
269
270    if let Some(ret_type) = ret_type {
271        match &data.store[ret_type] {
272            TypeRef::Tuple(tup) if tup.is_empty() => {}
273            _ => {
274                f.write_str(" -> ")?;
275                ret_type.hir_fmt(f, owner, &data.store)?;
276            }
277        }
278    }
279
280    // Write where clauses
281    let has_written_where = write_where_clause(GenericDefId::FunctionId(func_id), f)?;
282    Ok(has_written_where)
283}
284
285fn write_impl_header<'db>(impl_: ImplId, f: &mut HirFormatter<'_, 'db>) -> Result {
286    let db = f.db;
287
288    f.write_str("impl")?;
289    let def_id = GenericDefId::ImplId(impl_);
290    write_generic_params(def_id, f)?;
291
292    let impl_data = ImplSignature::of(db, impl_);
293    if let Some(target_trait) = &impl_data.target_trait {
294        f.write_char(' ')?;
295        hir_display_with_store(&impl_data.store[target_trait.path], impl_.into(), &impl_data.store)
296            .hir_fmt(f)?;
297        f.write_str(" for")?;
298    }
299
300    f.write_char(' ')?;
301    Impl::from(impl_).self_ty(db).hir_fmt(f)?;
302
303    Ok(())
304}
305
306impl<'db> HirDisplay<'db> for SelfParam {
307    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
308        let func = match self.func.id {
309            AnyFunctionId::FunctionId(id) => id,
310            AnyFunctionId::BuiltinDeriveImplMethod { method, .. } => match method {
311                BuiltinDeriveImplMethod::clone
312                | BuiltinDeriveImplMethod::fmt
313                | BuiltinDeriveImplMethod::hash
314                | BuiltinDeriveImplMethod::cmp
315                | BuiltinDeriveImplMethod::partial_cmp
316                | BuiltinDeriveImplMethod::eq => return f.write_str("&self"),
317                BuiltinDeriveImplMethod::default => {
318                    unreachable!("this trait method does not have a self param")
319                }
320            },
321        };
322        let data = FunctionSignature::of(f.db, func);
323        let param = *data.params.first().unwrap();
324        let owner = ExpressionStoreOwnerId::Body(func.into());
325        match &data.store[param] {
326            TypeRef::Path(p) if p.is_self_type() => f.write_str("self"),
327            TypeRef::Reference(ref_) if matches!(&data.store[ref_.ty], TypeRef::Path(p) if p.is_self_type()) =>
328            {
329                f.write_char('&')?;
330                if let Some(lifetime) = &ref_.lifetime {
331                    lifetime.hir_fmt(f, owner, &data.store)?;
332                    f.write_char(' ')?;
333                }
334                if let hir_def::type_ref::Mutability::Mut = ref_.mutability {
335                    f.write_str("mut ")?;
336                }
337                f.write_str("self")
338            }
339            _ => {
340                f.write_str("self: ")?;
341                param.hir_fmt(f, owner, &data.store)
342            }
343        }
344    }
345}
346
347impl<'db> HirDisplay<'db> for Adt {
348    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
349        match self {
350            Adt::Struct(it) => it.hir_fmt(f),
351            Adt::Union(it) => it.hir_fmt(f),
352            Adt::Enum(it) => it.hir_fmt(f),
353        }
354    }
355}
356
357impl<'db> HirDisplay<'db> for Struct {
358    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
359        let module_id = self.module(f.db).id;
360        // FIXME: Render repr if its set explicitly?
361        write_visibility(module_id, self.visibility(f.db), f)?;
362        f.write_str("struct ")?;
363        write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?;
364        let def_id = GenericDefId::AdtId(AdtId::StructId(self.id));
365        write_generic_params(def_id, f)?;
366
367        match self.kind(f.db) {
368            StructKind::Tuple => {
369                f.write_char('(')?;
370                let (fields, hidden_fields) = visible_fields(self.fields(f.db), f);
371                let mut it = fields.iter().peekable();
372
373                while let Some(field) = it.next() {
374                    write_visibility(module_id, field.visibility(f.db), f)?;
375                    field.ty(f.db).hir_fmt(f)?;
376                    if it.peek().is_some() || hidden_fields {
377                        f.write_str(", ")?;
378                    }
379                }
380                if hidden_fields {
381                    f.write_str("/* … */")?;
382                }
383
384                f.write_char(')')?;
385                write_where_clause(def_id, f)?;
386            }
387            StructKind::Record => {
388                let has_where_clause = write_where_clause(def_id, f)?;
389                if let Some(limit) = f.entity_limit {
390                    let (fields, hidden_fields) = visible_fields(self.fields(f.db), f);
391                    write_fields(&fields, hidden_fields, has_where_clause, limit, false, f)?;
392                }
393            }
394            StructKind::Unit => _ = write_where_clause(def_id, f)?,
395        }
396
397        Ok(())
398    }
399}
400
401impl<'db> HirDisplay<'db> for Enum {
402    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
403        write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
404        f.write_str("enum ")?;
405        write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?;
406        let def_id = GenericDefId::AdtId(AdtId::EnumId(self.id));
407        write_generic_params(def_id, f)?;
408
409        let has_where_clause = write_where_clause(def_id, f)?;
410        if let Some(limit) = f.entity_limit {
411            write_variants(&self.variants(f.db), has_where_clause, limit, f)?;
412        }
413
414        Ok(())
415    }
416}
417
418impl<'db> HirDisplay<'db> for Union {
419    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
420        write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
421        f.write_str("union ")?;
422        write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?;
423        let def_id = GenericDefId::AdtId(AdtId::UnionId(self.id));
424        write_generic_params(def_id, f)?;
425
426        let has_where_clause = write_where_clause(def_id, f)?;
427        if let Some(limit) = f.entity_limit {
428            let (fields, hidden_fields) = visible_fields(self.fields(f.db), f);
429            write_fields(&fields, hidden_fields, has_where_clause, limit, false, f)?;
430        }
431        Ok(())
432    }
433}
434
435fn visible_fields<'db>(fields: Vec<Field>, f: &mut HirFormatter<'_, 'db>) -> (Vec<Field>, bool) {
436    if f.render_private_fields() {
437        return (fields, false);
438    }
439
440    let mut hidden_fields = false;
441    let fields = fields
442        .into_iter()
443        .filter(|field| {
444            let is_public = field.visibility(f.db) == Visibility::Public;
445            hidden_fields |= !is_public;
446            is_public
447        })
448        .collect();
449    (fields, hidden_fields)
450}
451
452fn write_fields<'db>(
453    fields: &[Field],
454    hidden_fields: bool,
455    has_where_clause: bool,
456    limit: usize,
457    in_line: bool,
458    f: &mut HirFormatter<'_, 'db>,
459) -> Result {
460    let count = fields.len().min(limit);
461    let (indent, separator) = if in_line { ("", ' ') } else { ("    ", '\n') };
462    f.write_char(if !has_where_clause { ' ' } else { separator })?;
463    if count == 0 {
464        f.write_str(if fields.is_empty() && !hidden_fields { "{}" } else { "{ /* … */ }" })?;
465    } else {
466        f.write_char('{')?;
467
468        if !fields.is_empty() {
469            f.write_char(separator)?;
470            for field in &fields[..count] {
471                f.write_str(indent)?;
472                field.hir_fmt(f)?;
473                write!(f, ",{separator}")?;
474            }
475
476            if fields.len() > count || hidden_fields {
477                write!(f, "{indent}/* … */{separator}")?;
478            }
479        }
480
481        f.write_str("}")?;
482    }
483
484    Ok(())
485}
486
487fn write_variants<'db>(
488    variants: &[EnumVariant],
489    has_where_clause: bool,
490    limit: usize,
491    f: &mut HirFormatter<'_, 'db>,
492) -> Result {
493    let count = variants.len().min(limit);
494    f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
495    if count == 0 {
496        let variants = if variants.is_empty() { "{}" } else { "{ /* … */ }" };
497        f.write_str(variants)?;
498    } else {
499        f.write_str("{\n")?;
500        for variant in &variants[..count] {
501            write!(f, "    {}", variant.name(f.db).display(f.db, f.edition()))?;
502            match variant.kind(f.db) {
503                StructKind::Tuple => {
504                    let fields_str =
505                        if variant.fields(f.db).is_empty() { "()" } else { "( /* … */ )" };
506                    f.write_str(fields_str)?;
507                }
508                StructKind::Record => {
509                    let fields_str =
510                        if variant.fields(f.db).is_empty() { " {}" } else { " { /* … */ }" };
511                    f.write_str(fields_str)?;
512                }
513                StructKind::Unit => {}
514            }
515            f.write_str(",\n")?;
516        }
517
518        if variants.len() > count {
519            f.write_str("    /* … */\n")?;
520        }
521        f.write_str("}")?;
522    }
523
524    Ok(())
525}
526
527impl<'db> HirDisplay<'db> for Field {
528    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
529        write_visibility(self.parent.module(f.db).id, self.visibility(f.db), f)?;
530        write!(f, "{}: ", self.name(f.db).display(f.db, f.edition()))?;
531        self.ty(f.db).hir_fmt(f)
532    }
533}
534
535impl<'db> HirDisplay<'db> for TupleField<'db> {
536    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
537        write!(f, "pub {}: ", self.name().display(f.db, f.edition()))?;
538        self.ty(f.db).hir_fmt(f)
539    }
540}
541
542impl<'db> HirDisplay<'db> for EnumVariant {
543    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
544        write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?;
545        let data = self.id.fields(f.db);
546        match data.shape {
547            FieldsShape::Unit => {}
548            FieldsShape::Tuple => {
549                f.write_char('(')?;
550                let mut first = true;
551                for (_, field) in data.fields().iter() {
552                    if first {
553                        first = false;
554                    } else {
555                        f.write_str(", ")?;
556                    }
557                    // Enum variant fields must be pub.
558                    field.type_ref.hir_fmt(
559                        f,
560                        ExpressionStoreOwnerId::VariantFields(self.id.into()),
561                        &data.store,
562                    )?;
563                }
564                f.write_char(')')?;
565            }
566            FieldsShape::Record => {
567                if let Some(limit) = f.entity_limit {
568                    let (fields, hidden_fields) = visible_fields(self.fields(f.db), f);
569                    write_fields(&fields, hidden_fields, false, limit, true, f)?;
570                }
571            }
572        }
573        Ok(())
574    }
575}
576
577impl<'db> HirDisplay<'db> for Type<'db> {
578    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
579        self.ty.skip_binder().hir_fmt(f)
580    }
581}
582
583impl<'db> HirDisplay<'db> for ExternCrateDecl {
584    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
585        write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
586        f.write_str("extern crate ")?;
587        write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?;
588        if let Some(alias) = self.alias(f.db) {
589            write!(f, " as {}", alias.display(f.edition()))?;
590        }
591        Ok(())
592    }
593}
594
595impl<'db> HirDisplay<'db> for GenericParam {
596    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
597        match self {
598            GenericParam::TypeParam(it) => it.hir_fmt(f),
599            GenericParam::ConstParam(it) => it.hir_fmt(f),
600            GenericParam::LifetimeParam(it) => it.hir_fmt(f),
601        }
602    }
603}
604
605impl<'db> HirDisplay<'db> for TypeOrConstParam {
606    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
607        match self.split(f.db) {
608            either::Either::Left(it) => it.hir_fmt(f),
609            either::Either::Right(it) => it.hir_fmt(f),
610        }
611    }
612}
613
614impl<'db> HirDisplay<'db> for TypeParam {
615    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
616        let params = GenericParams::of(f.db, self.id.parent());
617        let param_data = &params[self.id.local_id()];
618        let krate = self.id.parent().krate(f.db).id;
619        let ty = self.ty(f.db).ty.skip_binder();
620        let predicates = GenericPredicates::query_all(f.db, self.id.parent());
621        let predicates = predicates
622            .iter_identity()
623            .map(Unnormalized::skip_norm_wip)
624            .filter(|wc| match wc.kind().skip_binder() {
625                ClauseKind::Trait(tr) => tr.self_ty() == ty,
626                ClauseKind::Projection(proj) => proj.self_ty() == ty,
627                ClauseKind::TypeOutlives(to) => to.0 == ty,
628                _ => false,
629            })
630            .collect::<Vec<_>>();
631
632        match param_data {
633            TypeOrConstParamData::TypeParamData(p) => match p.provenance {
634                TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
635                    write!(f, "{}", p.name.clone().unwrap().display(f.db, f.edition()))?
636                }
637                TypeParamProvenance::ArgumentImplTrait => {
638                    return write_bounds_like_dyn_trait_with_prefix(
639                        f,
640                        "impl",
641                        Either::Left(ty),
642                        &predicates,
643                        SizedByDefault::Sized { anchor: krate },
644                        false,
645                    );
646                }
647            },
648            TypeOrConstParamData::ConstParamData(p) => {
649                write!(f, "{}", p.name.display(f.db, f.edition()))?;
650            }
651        }
652
653        if f.omit_verbose_types() {
654            return Ok(());
655        }
656
657        let sized_trait = f.lang_items().Sized;
658        let has_only_sized_bound =
659            predicates.iter().all(move |pred| match pred.kind().skip_binder() {
660                ClauseKind::Trait(it) => Some(it.def_id().0) == sized_trait,
661                _ => false,
662            });
663        let has_only_not_sized_bound = predicates.is_empty();
664        if !has_only_sized_bound || has_only_not_sized_bound {
665            let default_sized = SizedByDefault::Sized { anchor: krate };
666            write_bounds_like_dyn_trait_with_prefix(
667                f,
668                ":",
669                Either::Left(ty),
670                &predicates,
671                default_sized,
672                false,
673            )?;
674        }
675        Ok(())
676    }
677}
678
679impl<'db> HirDisplay<'db> for LifetimeParam {
680    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
681        write!(f, "{}", self.name(f.db).display(f.db, f.edition()))
682    }
683}
684
685impl<'db> HirDisplay<'db> for ConstParam {
686    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
687        write!(f, "const {}: ", self.name(f.db).display(f.db, f.edition()))?;
688        self.ty(f.db).hir_fmt(f)
689    }
690}
691
692fn write_generic_params<'db>(def: GenericDefId, f: &mut HirFormatter<'_, 'db>) -> Result {
693    write_generic_params_or_args(def, f, true)
694}
695
696fn write_generic_args<'db>(def: GenericDefId, f: &mut HirFormatter<'_, 'db>) -> Result {
697    write_generic_params_or_args(def, f, false)
698}
699
700fn write_generic_params_or_args<'db>(
701    def: GenericDefId,
702    f: &mut HirFormatter<'_, 'db>,
703    include_defaults: bool,
704) -> Result {
705    let (params, store) = GenericParams::with_store(f.db, def);
706    let owner = def.into();
707    if params.iter_lt().next().is_none()
708        && params.iter_type_or_consts().all(|it| it.1.const_param().is_none())
709        && params
710            .iter_type_or_consts()
711            .filter_map(|it| it.1.type_param())
712            .all(|param| !matches!(param.provenance, TypeParamProvenance::TypeParamList))
713    {
714        return Ok(());
715    }
716    f.write_char('<')?;
717
718    let mut first = true;
719    let mut delim = |f: &mut HirFormatter<'_, 'db>| {
720        if first {
721            first = false;
722            Ok(())
723        } else {
724            f.write_str(", ")
725        }
726    };
727    for (_, lifetime) in params.iter_lt() {
728        delim(f)?;
729        write!(f, "{}", lifetime.name.display(f.db, f.edition()))?;
730    }
731    for (_, ty) in params.iter_type_or_consts() {
732        if let Some(name) = &ty.name() {
733            match ty {
734                TypeOrConstParamData::TypeParamData(ty) => {
735                    if ty.provenance != TypeParamProvenance::TypeParamList {
736                        continue;
737                    }
738                    delim(f)?;
739                    write!(f, "{}", name.display(f.db, f.edition()))?;
740                    if include_defaults && let Some(default) = &ty.default {
741                        f.write_str(" = ")?;
742                        default.hir_fmt(f, owner, store)?;
743                    }
744                }
745                TypeOrConstParamData::ConstParamData(c) => {
746                    delim(f)?;
747                    write!(f, "const {}: ", name.display(f.db, f.edition()))?;
748                    c.ty.hir_fmt(f, owner, store)?;
749
750                    if include_defaults && let Some(default) = &c.default {
751                        f.write_str(" = ")?;
752                        default.hir_fmt(f, owner, store)?;
753                    }
754                }
755            }
756        }
757    }
758
759    f.write_char('>')?;
760    Ok(())
761}
762
763fn write_where_clause<'db>(def: GenericDefId, f: &mut HirFormatter<'_, 'db>) -> Result<bool> {
764    let (params, store) = GenericParams::with_store(f.db, def);
765    if !has_disaplayable_predicates(f.db, params, store) {
766        return Ok(false);
767    }
768
769    f.write_str("\nwhere")?;
770    write_where_predicates(params, def.into(), store, f)?;
771
772    Ok(true)
773}
774
775fn has_disaplayable_predicates(
776    db: &dyn HirDatabase,
777    params: &GenericParams,
778    store: &ExpressionStore,
779) -> bool {
780    params.where_predicates().iter().any(|pred| {
781        !matches!(
782            pred,
783            WherePredicate::TypeBound { target, .. }
784            if  matches!(store[*target],
785                TypeRef::TypeParam(id) if GenericParams::of(db,id.parent())[id.local_id()].name().is_none()
786            )
787        )
788    })
789}
790
791fn write_where_predicates<'db>(
792    params: &GenericParams,
793    owner: ExpressionStoreOwnerId,
794    store: &ExpressionStore,
795    f: &mut HirFormatter<'_, 'db>,
796) -> Result {
797    use WherePredicate::*;
798
799    // unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`.
800    let is_unnamed_type_target = |target: TypeRefId| {
801        matches!(store[target],
802            TypeRef::TypeParam(id) if GenericParams::of(f.db,id.parent())[id.local_id()].name().is_none()
803        )
804    };
805
806    let check_same_target = |pred1: &WherePredicate, pred2: &WherePredicate| match (pred1, pred2) {
807        (TypeBound { target: t1, .. }, TypeBound { target: t2, .. }) => t1 == t2,
808        (Lifetime { target: t1, .. }, Lifetime { target: t2, .. }) => t1 == t2,
809        _ => false,
810    };
811
812    let mut iter = params.where_predicates().iter().peekable();
813    while let Some(pred) = iter.next() {
814        if matches!(pred, TypeBound { target, .. } if is_unnamed_type_target(*target)) {
815            continue;
816        }
817
818        f.write_str("\n    ")?;
819        match pred {
820            TypeBound { lifetimes, target, bound } => {
821                if let Some(lifetimes) = lifetimes {
822                    let lifetimes =
823                        lifetimes.iter().map(|it| it.display(f.db, f.edition())).join(", ");
824                    write!(f, "for<{lifetimes}> ")?;
825                }
826                target.hir_fmt(f, owner, store)?;
827                f.write_str(": ")?;
828                bound.hir_fmt(f, owner, store)?;
829            }
830            Lifetime { target, bound } => {
831                target.hir_fmt(f, owner, store)?;
832                write!(f, ": ")?;
833                bound.hir_fmt(f, owner, store)?;
834            }
835        }
836
837        while let Some(nxt) = iter.next_if(|nxt| check_same_target(pred, nxt)) {
838            f.write_str(" + ")?;
839            match nxt {
840                TypeBound { bound, .. } => bound.hir_fmt(f, owner, store)?,
841                Lifetime { bound, .. } => bound.hir_fmt(f, owner, store)?,
842            }
843        }
844        f.write_str(",")?;
845    }
846
847    Ok(())
848}
849
850impl<'db> HirDisplay<'db> for Const {
851    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
852        let db = f.db;
853        let container = self.as_assoc_item(db).map(|it| it.container(db));
854        let mut module = self.module(db);
855        if let Some(AssocItemContainer::Impl(_)) = container {
856            // Block-local impls are "hoisted" to the nearest (non-block) module.
857            module = module.nearest_non_block_module(db);
858        }
859        write_visibility(module.id, self.visibility(db), f)?;
860        let data = ConstSignature::of(db, self.id);
861        f.write_str("const ")?;
862        match &data.name {
863            Some(name) => write!(f, "{}: ", name.display(f.db, f.edition()))?,
864            None => f.write_str("_: ")?,
865        }
866        data.type_ref.hir_fmt(f, ExpressionStoreOwnerId::Signature(self.id.into()), &data.store)?;
867        Ok(())
868    }
869}
870
871impl<'db> HirDisplay<'db> for Static {
872    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
873        write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
874        let data = StaticSignature::of(f.db, self.id);
875        f.write_str("static ")?;
876        if data.flags.contains(StaticFlags::MUTABLE) {
877            f.write_str("mut ")?;
878        }
879        write!(f, "{}: ", data.name.display(f.db, f.edition()))?;
880        data.type_ref.hir_fmt(f, ExpressionStoreOwnerId::Signature(self.id.into()), &data.store)?;
881        Ok(())
882    }
883}
884
885impl<'db> HirDisplay<'db> for TraitRef<'db> {
886    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
887        self.trait_ref.hir_fmt(f)
888    }
889}
890
891impl<'db> HirDisplay<'db> for TraitPredicate<'db> {
892    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
893        self.inner.hir_fmt(f)
894    }
895}
896
897impl<'db> HirDisplay<'db> for Trait {
898    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
899        // FIXME(trait-alias) needs special handling to print the equal sign
900        write_trait_header(*self, f)?;
901        let def_id = GenericDefId::TraitId(self.id);
902        let has_where_clause = write_where_clause(def_id, f)?;
903
904        if let Some(limit) = f.entity_limit {
905            let assoc_items = self.items(f.db);
906            let count = assoc_items.len().min(limit);
907            f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
908            if count == 0 {
909                if assoc_items.is_empty() {
910                    f.write_str("{}")?;
911                } else {
912                    f.write_str("{ /* … */ }")?;
913                }
914            } else {
915                f.write_str("{\n")?;
916                for item in &assoc_items[..count] {
917                    f.write_str("    ")?;
918                    match item {
919                        AssocItem::Function(func) => func.hir_fmt(f),
920                        AssocItem::Const(cst) => cst.hir_fmt(f),
921                        AssocItem::TypeAlias(type_alias) => type_alias.hir_fmt(f),
922                    }?;
923                    f.write_str(";\n")?;
924                }
925
926                if assoc_items.len() > count {
927                    f.write_str("    /* … */\n")?;
928                }
929                f.write_str("}")?;
930            }
931        }
932
933        Ok(())
934    }
935}
936
937fn write_trait_header<'db>(trait_: Trait, f: &mut HirFormatter<'_, 'db>) -> Result {
938    write_visibility(trait_.module(f.db).id, trait_.visibility(f.db), f)?;
939    let data = TraitSignature::of(f.db, trait_.id);
940    if data.flags.contains(TraitFlags::UNSAFE) {
941        f.write_str("unsafe ")?;
942    }
943    if data.flags.contains(TraitFlags::AUTO) {
944        f.write_str("auto ")?;
945    }
946    write!(f, "trait {}", data.name.display(f.db, f.edition()))?;
947    write_generic_params(GenericDefId::TraitId(trait_.id), f)?;
948    Ok(())
949}
950
951impl<'db> HirDisplay<'db> for TypeAlias {
952    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
953        write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
954        let data = TypeAliasSignature::of(f.db, self.id);
955        write!(f, "type {}", data.name.display(f.db, f.edition()))?;
956        let def_id = GenericDefId::TypeAliasId(self.id);
957        write_generic_params(def_id, f)?;
958        if !data.bounds.is_empty() {
959            f.write_str(": ")?;
960            f.write_joined(
961                data.bounds.iter().map(|bound| {
962                    hir_display_with_store(
963                        bound,
964                        ExpressionStoreOwnerId::Signature(self.id.into()),
965                        &data.store,
966                    )
967                }),
968                " + ",
969            )?;
970        }
971        if let Some(ty) = data.ty {
972            f.write_str(" = ")?;
973            ty.hir_fmt(f, ExpressionStoreOwnerId::Signature(self.id.into()), &data.store)?;
974        }
975        write_where_clause(def_id, f)?;
976        Ok(())
977    }
978}
979
980impl<'db> HirDisplay<'db> for Module {
981    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
982        match self.parent(f.db) {
983            Some(m) => write_visibility(m.id, self.visibility(f.db), f)?,
984            None => {
985                return match self.krate(f.db).display_name(f.db) {
986                    Some(name) => write!(f, "extern crate {name}"),
987                    None => f.write_str("extern crate {unknown}"),
988                };
989            }
990        }
991        match self.name(f.db) {
992            Some(name) => write!(f, "mod {}", name.display(f.db, f.edition())),
993            None => f.write_str("mod {unknown}"),
994        }
995    }
996}
997
998impl<'db> HirDisplay<'db> for Crate {
999    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
1000        match self.display_name(f.db) {
1001            Some(name) => write!(f, "extern crate {name}"),
1002            None => f.write_str("extern crate {unknown}"),
1003        }
1004    }
1005}
1006
1007impl<'db> HirDisplay<'db> for Macro {
1008    fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
1009        match self.id {
1010            hir_def::MacroId::Macro2Id(_) => f.write_str("macro"),
1011            hir_def::MacroId::MacroRulesId(_) => f.write_str("macro_rules!"),
1012            hir_def::MacroId::ProcMacroId(_) => f.write_str("proc_macro"),
1013        }?;
1014        write!(f, " {}", self.name(f.db).display(f.db, f.edition()))
1015    }
1016}