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