aboutsummaryrefslogtreecommitdiff
path: root/crates/hir/src/display.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir/src/display.rs')
-rw-r--r--crates/hir/src/display.rs467
1 files changed, 467 insertions, 0 deletions
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
new file mode 100644
index 000000000..9f6d7be48
--- /dev/null
+++ b/crates/hir/src/display.rs
@@ -0,0 +1,467 @@
1//! HirDisplay implementations for various hir types.
2use hir_def::{
3 adt::VariantData,
4 generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
5 type_ref::{TypeBound, TypeRef},
6 AdtId, GenericDefId,
7};
8use hir_ty::display::{
9 write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError,
10 HirFormatter,
11};
12use syntax::ast::{self, NameOwner};
13
14use crate::{
15 Adt, Const, ConstParam, Enum, Field, Function, GenericParam, HasVisibility, LifetimeParam,
16 Module, Static, Struct, Substitution, Trait, Type, TypeAlias, TypeParam, Union, Variant,
17};
18
19impl HirDisplay for Function {
20 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
21 let data = f.db.function_data(self.id);
22 write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
23 let qual = &data.qualifier;
24 if qual.is_default {
25 write!(f, "default ")?;
26 }
27 if qual.is_const {
28 write!(f, "const ")?;
29 }
30 if qual.is_async {
31 write!(f, "async ")?;
32 }
33 if qual.is_unsafe {
34 write!(f, "unsafe ")?;
35 }
36 if let Some(abi) = &qual.abi {
37 // FIXME: String escape?
38 write!(f, "extern \"{}\" ", abi)?;
39 }
40 write!(f, "fn {}", data.name)?;
41
42 write_generic_params(GenericDefId::FunctionId(self.id), f)?;
43
44 write!(f, "(")?;
45
46 let write_self_param = |ty: &TypeRef, f: &mut HirFormatter| match ty {
47 TypeRef::Path(p) if p.is_self_type() => write!(f, "self"),
48 TypeRef::Reference(inner, lifetime, mut_) if matches!(&**inner,TypeRef::Path(p) if p.is_self_type()) =>
49 {
50 write!(f, "&")?;
51 if let Some(lifetime) = lifetime {
52 write!(f, "{} ", lifetime.name)?;
53 }
54 if let hir_def::type_ref::Mutability::Mut = mut_ {
55 write!(f, "mut ")?;
56 }
57 write!(f, "self")
58 }
59 _ => {
60 write!(f, "self: ")?;
61 ty.hir_fmt(f)
62 }
63 };
64
65 let mut first = true;
66 for (param, type_ref) in self.assoc_fn_params(f.db).into_iter().zip(&data.params) {
67 if !first {
68 write!(f, ", ")?;
69 } else {
70 first = false;
71 if data.has_self_param {
72 write_self_param(type_ref, f)?;
73 continue;
74 }
75 }
76 match param.pattern_source(f.db) {
77 Some(ast::Pat::IdentPat(p)) if p.name().is_some() => {
78 write!(f, "{}: ", p.name().unwrap())?
79 }
80 _ => write!(f, "_: ")?,
81 }
82 // FIXME: Use resolved `param.ty` or raw `type_ref`?
83 // The former will ignore lifetime arguments currently.
84 type_ref.hir_fmt(f)?;
85 }
86 write!(f, ")")?;
87
88 // `FunctionData::ret_type` will be `::core::future::Future<Output = ...>` for async fns.
89 // Use ugly pattern match to strip the Future trait.
90 // Better way?
91 let ret_type = if !qual.is_async {
92 &data.ret_type
93 } else {
94 match &data.ret_type {
95 TypeRef::ImplTrait(bounds) => match &bounds[0] {
96 TypeBound::Path(path) => {
97 path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings
98 [0]
99 .type_ref
100 .as_ref()
101 .unwrap()
102 }
103 _ => panic!("Async fn ret_type should be impl Future"),
104 },
105 _ => panic!("Async fn ret_type should be impl Future"),
106 }
107 };
108
109 match ret_type {
110 TypeRef::Tuple(tup) if tup.is_empty() => {}
111 ty => {
112 write!(f, " -> ")?;
113 ty.hir_fmt(f)?;
114 }
115 }
116
117 write_where_clause(GenericDefId::FunctionId(self.id), f)?;
118
119 Ok(())
120 }
121}
122
123impl HirDisplay for Adt {
124 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
125 match self {
126 Adt::Struct(it) => it.hir_fmt(f),
127 Adt::Union(it) => it.hir_fmt(f),
128 Adt::Enum(it) => it.hir_fmt(f),
129 }
130 }
131}
132
133impl HirDisplay for Struct {
134 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
135 write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
136 write!(f, "struct ")?;
137 write!(f, "{}", self.name(f.db))?;
138 let def_id = GenericDefId::AdtId(AdtId::StructId(self.id));
139 write_generic_params(def_id, f)?;
140 write_where_clause(def_id, f)?;
141 Ok(())
142 }
143}
144
145impl HirDisplay for Enum {
146 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
147 write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
148 write!(f, "enum ")?;
149 write!(f, "{}", self.name(f.db))?;
150 let def_id = GenericDefId::AdtId(AdtId::EnumId(self.id));
151 write_generic_params(def_id, f)?;
152 write_where_clause(def_id, f)?;
153 Ok(())
154 }
155}
156
157impl HirDisplay for Union {
158 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
159 write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
160 write!(f, "union ")?;
161 write!(f, "{}", self.name(f.db))?;
162 let def_id = GenericDefId::AdtId(AdtId::UnionId(self.id));
163 write_generic_params(def_id, f)?;
164 write_where_clause(def_id, f)?;
165 Ok(())
166 }
167}
168
169impl HirDisplay for Field {
170 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
171 write_visibility(self.parent.module(f.db).id, self.visibility(f.db), f)?;
172 write!(f, "{}: ", self.name(f.db))?;
173 self.signature_ty(f.db).hir_fmt(f)
174 }
175}
176
177impl HirDisplay for Variant {
178 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
179 write!(f, "{}", self.name(f.db))?;
180 let data = self.variant_data(f.db);
181 match &*data {
182 VariantData::Unit => {}
183 VariantData::Tuple(fields) => {
184 write!(f, "(")?;
185 let mut first = true;
186 for (_, field) in fields.iter() {
187 if first {
188 first = false;
189 } else {
190 write!(f, ", ")?;
191 }
192 // Enum variant fields must be pub.
193 field.type_ref.hir_fmt(f)?;
194 }
195 write!(f, ")")?;
196 }
197 VariantData::Record(fields) => {
198 write!(f, " {{")?;
199 let mut first = true;
200 for (_, field) in fields.iter() {
201 if first {
202 first = false;
203 write!(f, " ")?;
204 } else {
205 write!(f, ", ")?;
206 }
207 // Enum variant fields must be pub.
208 write!(f, "{}: ", field.name)?;
209 field.type_ref.hir_fmt(f)?;
210 }
211 write!(f, " }}")?;
212 }
213 }
214 Ok(())
215 }
216}
217
218impl HirDisplay for Type {
219 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
220 self.ty.value.hir_fmt(f)
221 }
222}
223
224impl HirDisplay for GenericParam {
225 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
226 match self {
227 GenericParam::TypeParam(it) => it.hir_fmt(f),
228 GenericParam::LifetimeParam(it) => it.hir_fmt(f),
229 GenericParam::ConstParam(it) => it.hir_fmt(f),
230 }
231 }
232}
233
234impl HirDisplay for TypeParam {
235 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
236 write!(f, "{}", self.name(f.db))?;
237 let bounds = f.db.generic_predicates_for_param(self.id);
238 let substs = Substitution::type_params(f.db, self.id.parent);
239 let predicates = bounds.iter().cloned().map(|b| b.subst(&substs)).collect::<Vec<_>>();
240 if !(predicates.is_empty() || f.omit_verbose_types()) {
241 write_bounds_like_dyn_trait_with_prefix(":", &predicates, f)?;
242 }
243 Ok(())
244 }
245}
246
247impl HirDisplay for LifetimeParam {
248 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
249 write!(f, "{}", self.name(f.db))
250 }
251}
252
253impl HirDisplay for ConstParam {
254 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
255 write!(f, "const {}: ", self.name(f.db))?;
256 self.ty(f.db).hir_fmt(f)
257 }
258}
259
260fn write_generic_params(def: GenericDefId, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
261 let params = f.db.generic_params(def);
262 if params.lifetimes.is_empty()
263 && params.consts.is_empty()
264 && params
265 .types
266 .iter()
267 .all(|(_, param)| !matches!(param.provenance, TypeParamProvenance::TypeParamList))
268 {
269 return Ok(());
270 }
271 write!(f, "<")?;
272
273 let mut first = true;
274 let mut delim = |f: &mut HirFormatter| {
275 if first {
276 first = false;
277 Ok(())
278 } else {
279 write!(f, ", ")
280 }
281 };
282 for (_, lifetime) in params.lifetimes.iter() {
283 delim(f)?;
284 write!(f, "{}", lifetime.name)?;
285 }
286 for (_, ty) in params.types.iter() {
287 if ty.provenance != TypeParamProvenance::TypeParamList {
288 continue;
289 }
290 if let Some(name) = &ty.name {
291 delim(f)?;
292 write!(f, "{}", name)?;
293 if let Some(default) = &ty.default {
294 write!(f, " = ")?;
295 default.hir_fmt(f)?;
296 }
297 }
298 }
299 for (_, konst) in params.consts.iter() {
300 delim(f)?;
301 write!(f, "const {}: ", konst.name)?;
302 konst.ty.hir_fmt(f)?;
303 }
304
305 write!(f, ">")?;
306 Ok(())
307}
308
309fn write_where_clause(def: GenericDefId, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
310 let params = f.db.generic_params(def);
311 if params.where_predicates.is_empty() {
312 return Ok(());
313 }
314
315 let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter| match target {
316 WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f),
317 WherePredicateTypeTarget::TypeParam(id) => match &params.types[*id].name {
318 Some(name) => write!(f, "{}", name),
319 None => write!(f, "{{unnamed}}"),
320 },
321 };
322
323 write!(f, "\nwhere")?;
324
325 for (pred_idx, pred) in params.where_predicates.iter().enumerate() {
326 let prev_pred =
327 if pred_idx == 0 { None } else { Some(&params.where_predicates[pred_idx - 1]) };
328
329 let new_predicate = |f: &mut HirFormatter| {
330 write!(f, "{}", if pred_idx == 0 { "\n " } else { ",\n " })
331 };
332
333 match pred {
334 WherePredicate::TypeBound { target, bound } => {
335 if matches!(prev_pred, Some(WherePredicate::TypeBound { target: target_, .. }) if target_ == target)
336 {
337 write!(f, " + ")?;
338 } else {
339 new_predicate(f)?;
340 write_target(target, f)?;
341 write!(f, ": ")?;
342 }
343 bound.hir_fmt(f)?;
344 }
345 WherePredicate::Lifetime { target, bound } => {
346 if matches!(prev_pred, Some(WherePredicate::Lifetime { target: target_, .. }) if target_ == target)
347 {
348 write!(f, " + {}", bound.name)?;
349 } else {
350 new_predicate(f)?;
351 write!(f, "{}: {}", target.name, bound.name)?;
352 }
353 }
354 WherePredicate::ForLifetime { lifetimes, target, bound } => {
355 if matches!(
356 prev_pred,
357 Some(WherePredicate::ForLifetime { lifetimes: lifetimes_, target: target_, .. })
358 if lifetimes_ == lifetimes && target_ == target,
359 ) {
360 write!(f, " + ")?;
361 } else {
362 new_predicate(f)?;
363 write!(f, "for<")?;
364 for (idx, lifetime) in lifetimes.iter().enumerate() {
365 if idx != 0 {
366 write!(f, ", ")?;
367 }
368 write!(f, "{}", lifetime)?;
369 }
370 write!(f, "> ")?;
371 write_target(target, f)?;
372 write!(f, ": ")?;
373 }
374 bound.hir_fmt(f)?;
375 }
376 }
377 }
378
379 // End of final predicate. There must be at least one predicate here.
380 write!(f, ",")?;
381
382 Ok(())
383}
384
385impl HirDisplay for Const {
386 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
387 write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
388 let data = f.db.const_data(self.id);
389 write!(f, "const ")?;
390 match &data.name {
391 Some(name) => write!(f, "{}: ", name)?,
392 None => write!(f, "_: ")?,
393 }
394 data.type_ref.hir_fmt(f)?;
395 Ok(())
396 }
397}
398
399impl HirDisplay for Static {
400 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
401 write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
402 let data = f.db.static_data(self.id);
403 write!(f, "static ")?;
404 if data.mutable {
405 write!(f, "mut ")?;
406 }
407 match &data.name {
408 Some(name) => write!(f, "{}: ", name)?,
409 None => write!(f, "_: ")?,
410 }
411 data.type_ref.hir_fmt(f)?;
412 Ok(())
413 }
414}
415
416impl HirDisplay for Trait {
417 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
418 write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
419 let data = f.db.trait_data(self.id);
420 if data.is_unsafe {
421 write!(f, "unsafe ")?;
422 }
423 if data.is_auto {
424 write!(f, "auto ")?;
425 }
426 write!(f, "trait {}", data.name)?;
427 let def_id = GenericDefId::TraitId(self.id);
428 write_generic_params(def_id, f)?;
429 if !data.bounds.is_empty() {
430 write!(f, ": ")?;
431 f.write_joined(&*data.bounds, " + ")?;
432 }
433 write_where_clause(def_id, f)?;
434 Ok(())
435 }
436}
437
438impl HirDisplay for TypeAlias {
439 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
440 write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
441 let data = f.db.type_alias_data(self.id);
442 write!(f, "type {}", data.name)?;
443 if !data.bounds.is_empty() {
444 write!(f, ": ")?;
445 f.write_joined(&data.bounds, " + ")?;
446 }
447 if let Some(ty) = &data.type_ref {
448 write!(f, " = ")?;
449 ty.hir_fmt(f)?;
450 }
451 Ok(())
452 }
453}
454
455impl HirDisplay for Module {
456 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
457 // FIXME: Module doesn't have visibility saved in data.
458 match self.name(f.db) {
459 Some(name) => write!(f, "mod {}", name),
460 None if self.crate_root(f.db) == *self => match self.krate().display_name(f.db) {
461 Some(name) => write!(f, "extern crate {}", name),
462 None => write!(f, "extern crate {{unknown}}"),
463 },
464 None => write!(f, "mod {{unnamed}}"),
465 }
466 }
467}