]> git.lizzy.rs Git - rust.git/blob - crates/hir/src/display.rs
Rollup merge of #100643 - TaKO8Ki:point-at-type-parameter-shadowing-another-type...
[rust.git] / crates / hir / src / display.rs
1 //! HirDisplay implementations for various hir types.
2 use hir_def::{
3     adt::VariantData,
4     generics::{
5         TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
6     },
7     type_ref::{TypeBound, TypeRef},
8     AdtId, GenericDefId,
9 };
10 use hir_ty::{
11     display::{
12         write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError,
13         HirFormatter, SizedByDefault,
14     },
15     Interner, TraitRefExt, WhereClause,
16 };
17 use syntax::SmolStr;
18
19 use crate::{
20     Adt, Const, ConstParam, Enum, Field, Function, GenericParam, HasCrate, HasVisibility,
21     LifetimeParam, Macro, Module, Static, Struct, Trait, TyBuilder, Type, TypeAlias,
22     TypeOrConstParam, TypeParam, Union, Variant,
23 };
24
25 impl HirDisplay for Function {
26     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
27         let data = f.db.function_data(self.id);
28         write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
29         if data.has_default_kw() {
30             f.write_str("default ")?;
31         }
32         if data.has_const_kw() {
33             f.write_str("const ")?;
34         }
35         if data.has_async_kw() {
36             f.write_str("async ")?;
37         }
38         if self.is_unsafe_to_call(f.db) {
39             f.write_str("unsafe ")?;
40         }
41         if let Some(abi) = &data.abi {
42             // FIXME: String escape?
43             write!(f, "extern \"{}\" ", &**abi)?;
44         }
45         write!(f, "fn {}", data.name)?;
46
47         write_generic_params(GenericDefId::FunctionId(self.id), f)?;
48
49         f.write_char('(')?;
50
51         let write_self_param = |ty: &TypeRef, f: &mut HirFormatter<'_>| match ty {
52             TypeRef::Path(p) if p.is_self_type() => f.write_str("self"),
53             TypeRef::Reference(inner, lifetime, mut_) if matches!(&**inner,TypeRef::Path(p) if p.is_self_type()) =>
54             {
55                 f.write_char('&')?;
56                 if let Some(lifetime) = lifetime {
57                     write!(f, "{} ", lifetime.name)?;
58                 }
59                 if let hir_def::type_ref::Mutability::Mut = mut_ {
60                     f.write_str("mut ")?;
61                 }
62                 f.write_str("self")
63             }
64             _ => {
65                 f.write_str("self: ")?;
66                 ty.hir_fmt(f)
67             }
68         };
69
70         let mut first = true;
71         for (name, type_ref) in &data.params {
72             if !first {
73                 f.write_str(", ")?;
74             } else {
75                 first = false;
76                 if data.has_self_param() {
77                     write_self_param(type_ref, f)?;
78                     continue;
79                 }
80             }
81             match name {
82                 Some(name) => write!(f, "{}: ", name)?,
83                 None => f.write_str("_: ")?,
84             }
85             // FIXME: Use resolved `param.ty` or raw `type_ref`?
86             // The former will ignore lifetime arguments currently.
87             type_ref.hir_fmt(f)?;
88         }
89
90         if data.is_varargs() {
91             f.write_str(", ...")?;
92         }
93
94         f.write_char(')')?;
95
96         // `FunctionData::ret_type` will be `::core::future::Future<Output = ...>` for async fns.
97         // Use ugly pattern match to strip the Future trait.
98         // Better way?
99         let ret_type = if !data.has_async_kw() {
100             &data.ret_type
101         } else {
102             match &*data.ret_type {
103                 TypeRef::ImplTrait(bounds) => match bounds[0].as_ref() {
104                     TypeBound::Path(path, _) => {
105                         path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings
106                             [0]
107                         .type_ref
108                         .as_ref()
109                         .unwrap()
110                     }
111                     _ => panic!("Async fn ret_type should be impl Future"),
112                 },
113                 _ => panic!("Async fn ret_type should be impl Future"),
114             }
115         };
116
117         match ret_type {
118             TypeRef::Tuple(tup) if tup.is_empty() => {}
119             ty => {
120                 f.write_str(" -> ")?;
121                 ty.hir_fmt(f)?;
122             }
123         }
124
125         write_where_clause(GenericDefId::FunctionId(self.id), f)?;
126
127         Ok(())
128     }
129 }
130
131 impl HirDisplay for Adt {
132     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
133         match self {
134             Adt::Struct(it) => it.hir_fmt(f),
135             Adt::Union(it) => it.hir_fmt(f),
136             Adt::Enum(it) => it.hir_fmt(f),
137         }
138     }
139 }
140
141 impl HirDisplay for Struct {
142     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
143         write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
144         f.write_str("struct ")?;
145         write!(f, "{}", self.name(f.db))?;
146         let def_id = GenericDefId::AdtId(AdtId::StructId(self.id));
147         write_generic_params(def_id, f)?;
148         write_where_clause(def_id, f)?;
149         Ok(())
150     }
151 }
152
153 impl HirDisplay for Enum {
154     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
155         write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
156         f.write_str("enum ")?;
157         write!(f, "{}", self.name(f.db))?;
158         let def_id = GenericDefId::AdtId(AdtId::EnumId(self.id));
159         write_generic_params(def_id, f)?;
160         write_where_clause(def_id, f)?;
161         Ok(())
162     }
163 }
164
165 impl HirDisplay for Union {
166     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
167         write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
168         f.write_str("union ")?;
169         write!(f, "{}", self.name(f.db))?;
170         let def_id = GenericDefId::AdtId(AdtId::UnionId(self.id));
171         write_generic_params(def_id, f)?;
172         write_where_clause(def_id, f)?;
173         Ok(())
174     }
175 }
176
177 impl HirDisplay for Field {
178     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
179         write_visibility(self.parent.module(f.db).id, self.visibility(f.db), f)?;
180         write!(f, "{}: ", self.name(f.db))?;
181         self.ty(f.db).hir_fmt(f)
182     }
183 }
184
185 impl HirDisplay for Variant {
186     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
187         write!(f, "{}", self.name(f.db))?;
188         let data = self.variant_data(f.db);
189         match &*data {
190             VariantData::Unit => {}
191             VariantData::Tuple(fields) => {
192                 f.write_char('(')?;
193                 let mut first = true;
194                 for (_, field) in fields.iter() {
195                     if first {
196                         first = false;
197                     } else {
198                         f.write_str(", ")?;
199                     }
200                     // Enum variant fields must be pub.
201                     field.type_ref.hir_fmt(f)?;
202                 }
203                 f.write_char(')')?;
204             }
205             VariantData::Record(fields) => {
206                 f.write_str(" {")?;
207                 let mut first = true;
208                 for (_, field) in fields.iter() {
209                     if first {
210                         first = false;
211                         f.write_char(' ')?;
212                     } else {
213                         f.write_str(", ")?;
214                     }
215                     // Enum variant fields must be pub.
216                     write!(f, "{}: ", field.name)?;
217                     field.type_ref.hir_fmt(f)?;
218                 }
219                 f.write_str(" }")?;
220             }
221         }
222         Ok(())
223     }
224 }
225
226 impl HirDisplay for Type {
227     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
228         self.ty.hir_fmt(f)
229     }
230 }
231
232 impl HirDisplay for GenericParam {
233     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
234         match self {
235             GenericParam::TypeParam(it) => it.hir_fmt(f),
236             GenericParam::ConstParam(it) => it.hir_fmt(f),
237             GenericParam::LifetimeParam(it) => it.hir_fmt(f),
238         }
239     }
240 }
241
242 impl HirDisplay for TypeOrConstParam {
243     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
244         match self.split(f.db) {
245             either::Either::Left(x) => x.hir_fmt(f),
246             either::Either::Right(x) => x.hir_fmt(f),
247         }
248     }
249 }
250
251 impl HirDisplay for TypeParam {
252     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
253         write!(f, "{}", self.name(f.db))?;
254         if f.omit_verbose_types() {
255             return Ok(());
256         }
257
258         let bounds = f.db.generic_predicates_for_param(self.id.parent(), self.id.into(), None);
259         let substs = TyBuilder::placeholder_subst(f.db, self.id.parent());
260         let predicates: Vec<_> =
261             bounds.iter().cloned().map(|b| b.substitute(Interner, &substs)).collect();
262         let krate = self.id.parent().krate(f.db).id;
263         let sized_trait =
264             f.db.lang_item(krate, SmolStr::new_inline("sized"))
265                 .and_then(|lang_item| lang_item.as_trait());
266         let has_only_sized_bound = predicates.iter().all(move |pred| match pred.skip_binders() {
267             WhereClause::Implemented(it) => Some(it.hir_trait_id()) == sized_trait,
268             _ => false,
269         });
270         let has_only_not_sized_bound = predicates.is_empty();
271         if !has_only_sized_bound || has_only_not_sized_bound {
272             let default_sized = SizedByDefault::Sized { anchor: krate };
273             write_bounds_like_dyn_trait_with_prefix(":", &predicates, default_sized, f)?;
274         }
275         Ok(())
276     }
277 }
278
279 impl HirDisplay for LifetimeParam {
280     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
281         write!(f, "{}", self.name(f.db))
282     }
283 }
284
285 impl HirDisplay for ConstParam {
286     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
287         write!(f, "const {}: ", self.name(f.db))?;
288         self.ty(f.db).hir_fmt(f)
289     }
290 }
291
292 fn write_generic_params(
293     def: GenericDefId,
294     f: &mut HirFormatter<'_>,
295 ) -> Result<(), HirDisplayError> {
296     let params = f.db.generic_params(def);
297     if params.lifetimes.is_empty()
298         && params.type_or_consts.iter().all(|x| x.1.const_param().is_none())
299         && params
300             .type_or_consts
301             .iter()
302             .filter_map(|x| x.1.type_param())
303             .all(|param| !matches!(param.provenance, TypeParamProvenance::TypeParamList))
304     {
305         return Ok(());
306     }
307     f.write_char('<')?;
308
309     let mut first = true;
310     let mut delim = |f: &mut HirFormatter<'_>| {
311         if first {
312             first = false;
313             Ok(())
314         } else {
315             f.write_str(", ")
316         }
317     };
318     for (_, lifetime) in params.lifetimes.iter() {
319         delim(f)?;
320         write!(f, "{}", lifetime.name)?;
321     }
322     for (_, ty) in params.type_or_consts.iter() {
323         if let Some(name) = &ty.name() {
324             match ty {
325                 TypeOrConstParamData::TypeParamData(ty) => {
326                     if ty.provenance != TypeParamProvenance::TypeParamList {
327                         continue;
328                     }
329                     delim(f)?;
330                     write!(f, "{}", name)?;
331                     if let Some(default) = &ty.default {
332                         f.write_str(" = ")?;
333                         default.hir_fmt(f)?;
334                     }
335                 }
336                 TypeOrConstParamData::ConstParamData(c) => {
337                     delim(f)?;
338                     write!(f, "const {}: ", name)?;
339                     c.ty.hir_fmt(f)?;
340                 }
341             }
342         }
343     }
344
345     f.write_char('>')?;
346     Ok(())
347 }
348
349 fn write_where_clause(def: GenericDefId, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
350     let params = f.db.generic_params(def);
351
352     // unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`.
353     let is_unnamed_type_target = |target: &WherePredicateTypeTarget| match target {
354         WherePredicateTypeTarget::TypeRef(_) => false,
355         WherePredicateTypeTarget::TypeOrConstParam(id) => {
356             params.type_or_consts[*id].name().is_none()
357         }
358     };
359
360     let has_displayable_predicate = params
361         .where_predicates
362         .iter()
363         .any(|pred| {
364             !matches!(pred, WherePredicate::TypeBound { target, .. } if is_unnamed_type_target(target))
365         });
366
367     if !has_displayable_predicate {
368         return Ok(());
369     }
370
371     let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter<'_>| match target {
372         WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f),
373         WherePredicateTypeTarget::TypeOrConstParam(id) => {
374             match &params.type_or_consts[*id].name() {
375                 Some(name) => write!(f, "{}", name),
376                 None => f.write_str("{unnamed}"),
377             }
378         }
379     };
380
381     f.write_str("\nwhere")?;
382
383     for (pred_idx, pred) in params.where_predicates.iter().enumerate() {
384         let prev_pred =
385             if pred_idx == 0 { None } else { Some(&params.where_predicates[pred_idx - 1]) };
386
387         let new_predicate = |f: &mut HirFormatter<'_>| {
388             f.write_str(if pred_idx == 0 { "\n    " } else { ",\n    " })
389         };
390
391         match pred {
392             WherePredicate::TypeBound { target, .. } if is_unnamed_type_target(target) => {}
393             WherePredicate::TypeBound { target, bound } => {
394                 if matches!(prev_pred, Some(WherePredicate::TypeBound { target: target_, .. }) if target_ == target)
395                 {
396                     f.write_str(" + ")?;
397                 } else {
398                     new_predicate(f)?;
399                     write_target(target, f)?;
400                     f.write_str(": ")?;
401                 }
402                 bound.hir_fmt(f)?;
403             }
404             WherePredicate::Lifetime { target, bound } => {
405                 if matches!(prev_pred, Some(WherePredicate::Lifetime { target: target_, .. }) if target_ == target)
406                 {
407                     write!(f, " + {}", bound.name)?;
408                 } else {
409                     new_predicate(f)?;
410                     write!(f, "{}: {}", target.name, bound.name)?;
411                 }
412             }
413             WherePredicate::ForLifetime { lifetimes, target, bound } => {
414                 if matches!(
415                     prev_pred,
416                     Some(WherePredicate::ForLifetime { lifetimes: lifetimes_, target: target_, .. })
417                     if lifetimes_ == lifetimes && target_ == target,
418                 ) {
419                     f.write_str(" + ")?;
420                 } else {
421                     new_predicate(f)?;
422                     f.write_str("for<")?;
423                     for (idx, lifetime) in lifetimes.iter().enumerate() {
424                         if idx != 0 {
425                             f.write_str(", ")?;
426                         }
427                         write!(f, "{}", lifetime)?;
428                     }
429                     f.write_str("> ")?;
430                     write_target(target, f)?;
431                     f.write_str(": ")?;
432                 }
433                 bound.hir_fmt(f)?;
434             }
435         }
436     }
437
438     // End of final predicate. There must be at least one predicate here.
439     f.write_char(',')?;
440
441     Ok(())
442 }
443
444 impl HirDisplay for Const {
445     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
446         write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
447         let data = f.db.const_data(self.id);
448         f.write_str("const ")?;
449         match &data.name {
450             Some(name) => write!(f, "{}: ", name)?,
451             None => f.write_str("_: ")?,
452         }
453         data.type_ref.hir_fmt(f)?;
454         Ok(())
455     }
456 }
457
458 impl HirDisplay for Static {
459     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
460         write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
461         let data = f.db.static_data(self.id);
462         f.write_str("static ")?;
463         if data.mutable {
464             f.write_str("mut ")?;
465         }
466         write!(f, "{}: ", &data.name)?;
467         data.type_ref.hir_fmt(f)?;
468         Ok(())
469     }
470 }
471
472 impl HirDisplay for Trait {
473     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
474         write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
475         let data = f.db.trait_data(self.id);
476         if data.is_unsafe {
477             f.write_str("unsafe ")?;
478         }
479         if data.is_auto {
480             f.write_str("auto ")?;
481         }
482         write!(f, "trait {}", data.name)?;
483         let def_id = GenericDefId::TraitId(self.id);
484         write_generic_params(def_id, f)?;
485         write_where_clause(def_id, f)?;
486         Ok(())
487     }
488 }
489
490 impl HirDisplay for TypeAlias {
491     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
492         write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
493         let data = f.db.type_alias_data(self.id);
494         write!(f, "type {}", data.name)?;
495         if !data.bounds.is_empty() {
496             f.write_str(": ")?;
497             f.write_joined(&data.bounds, " + ")?;
498         }
499         if let Some(ty) = &data.type_ref {
500             f.write_str(" = ")?;
501             ty.hir_fmt(f)?;
502         }
503         Ok(())
504     }
505 }
506
507 impl HirDisplay for Module {
508     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
509         // FIXME: Module doesn't have visibility saved in data.
510         match self.name(f.db) {
511             Some(name) => write!(f, "mod {}", name),
512             None if self.is_crate_root(f.db) => match self.krate(f.db).display_name(f.db) {
513                 Some(name) => write!(f, "extern crate {}", name),
514                 None => f.write_str("extern crate {unknown}"),
515             },
516             None => f.write_str("mod {unnamed}"),
517         }
518     }
519 }
520
521 impl HirDisplay for Macro {
522     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
523         match self.id {
524             hir_def::MacroId::Macro2Id(_) => f.write_str("macro"),
525             hir_def::MacroId::MacroRulesId(_) => f.write_str("macro_rules!"),
526             hir_def::MacroId::ProcMacroId(_) => f.write_str("proc_macro"),
527         }?;
528         write!(f, " {}", self.name(f.db))
529     }
530 }