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