Skip to main content

hir/
display.rs

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