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