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