Skip to main content

hir/
display.rs

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