hir/
display.rs

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