diff options
Diffstat (limited to 'crates/hir/src/display.rs')
-rw-r--r-- | crates/hir/src/display.rs | 441 |
1 files changed, 441 insertions, 0 deletions
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs new file mode 100644 index 000000000..44cdcc296 --- /dev/null +++ b/crates/hir/src/display.rs | |||
@@ -0,0 +1,441 @@ | |||
1 | //! HirDisplay implementations for various hir types. | ||
2 | use hir_def::{ | ||
3 | adt::VariantData, | ||
4 | generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget}, | ||
5 | type_ref::{TypeBound, TypeRef}, | ||
6 | AdtId, GenericDefId, | ||
7 | }; | ||
8 | use hir_ty::display::{ | ||
9 | write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError, | ||
10 | HirFormatter, | ||
11 | }; | ||
12 | use syntax::ast::{self, NameOwner}; | ||
13 | |||
14 | use crate::{ | ||
15 | Const, ConstParam, Enum, Field, Function, HasVisibility, Module, Static, Struct, Substs, Trait, | ||
16 | Type, TypeAlias, TypeParam, Union, Variant, | ||
17 | }; | ||
18 | |||
19 | impl 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 | |||
123 | impl HirDisplay for Struct { | ||
124 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
125 | write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; | ||
126 | write!(f, "struct ")?; | ||
127 | write!(f, "{}", self.name(f.db))?; | ||
128 | let def_id = GenericDefId::AdtId(AdtId::StructId(self.id)); | ||
129 | write_generic_params(def_id, f)?; | ||
130 | write_where_clause(def_id, f)?; | ||
131 | Ok(()) | ||
132 | } | ||
133 | } | ||
134 | |||
135 | impl HirDisplay for Enum { | ||
136 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
137 | write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; | ||
138 | write!(f, "enum ")?; | ||
139 | write!(f, "{}", self.name(f.db))?; | ||
140 | let def_id = GenericDefId::AdtId(AdtId::EnumId(self.id)); | ||
141 | write_generic_params(def_id, f)?; | ||
142 | write_where_clause(def_id, f)?; | ||
143 | Ok(()) | ||
144 | } | ||
145 | } | ||
146 | |||
147 | impl HirDisplay for Union { | ||
148 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
149 | write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; | ||
150 | write!(f, "union ")?; | ||
151 | write!(f, "{}", self.name(f.db))?; | ||
152 | let def_id = GenericDefId::AdtId(AdtId::UnionId(self.id)); | ||
153 | write_generic_params(def_id, f)?; | ||
154 | write_where_clause(def_id, f)?; | ||
155 | Ok(()) | ||
156 | } | ||
157 | } | ||
158 | |||
159 | impl HirDisplay for Field { | ||
160 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
161 | write_visibility(self.parent.module(f.db).id, self.visibility(f.db), f)?; | ||
162 | write!(f, "{}: ", self.name(f.db))?; | ||
163 | self.signature_ty(f.db).hir_fmt(f) | ||
164 | } | ||
165 | } | ||
166 | |||
167 | impl HirDisplay for Variant { | ||
168 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
169 | write!(f, "{}", self.name(f.db))?; | ||
170 | let data = self.variant_data(f.db); | ||
171 | match &*data { | ||
172 | VariantData::Unit => {} | ||
173 | VariantData::Tuple(fields) => { | ||
174 | write!(f, "(")?; | ||
175 | let mut first = true; | ||
176 | for (_, field) in fields.iter() { | ||
177 | if first { | ||
178 | first = false; | ||
179 | } else { | ||
180 | write!(f, ", ")?; | ||
181 | } | ||
182 | // Enum variant fields must be pub. | ||
183 | field.type_ref.hir_fmt(f)?; | ||
184 | } | ||
185 | write!(f, ")")?; | ||
186 | } | ||
187 | VariantData::Record(fields) => { | ||
188 | write!(f, " {{")?; | ||
189 | let mut first = true; | ||
190 | for (_, field) in fields.iter() { | ||
191 | if first { | ||
192 | first = false; | ||
193 | write!(f, " ")?; | ||
194 | } else { | ||
195 | write!(f, ", ")?; | ||
196 | } | ||
197 | // Enum variant fields must be pub. | ||
198 | write!(f, "{}: ", field.name)?; | ||
199 | field.type_ref.hir_fmt(f)?; | ||
200 | } | ||
201 | write!(f, " }}")?; | ||
202 | } | ||
203 | } | ||
204 | Ok(()) | ||
205 | } | ||
206 | } | ||
207 | |||
208 | impl HirDisplay for Type { | ||
209 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
210 | self.ty.value.hir_fmt(f) | ||
211 | } | ||
212 | } | ||
213 | |||
214 | impl HirDisplay for TypeParam { | ||
215 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
216 | write!(f, "{}", self.name(f.db))?; | ||
217 | let bounds = f.db.generic_predicates_for_param(self.id); | ||
218 | let substs = Substs::type_params(f.db, self.id.parent); | ||
219 | let predicates = bounds.iter().cloned().map(|b| b.subst(&substs)).collect::<Vec<_>>(); | ||
220 | if !(predicates.is_empty() || f.omit_verbose_types()) { | ||
221 | write_bounds_like_dyn_trait_with_prefix(":", &predicates, f)?; | ||
222 | } | ||
223 | Ok(()) | ||
224 | } | ||
225 | } | ||
226 | |||
227 | impl HirDisplay for ConstParam { | ||
228 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
229 | write!(f, "const {}: ", self.name(f.db))?; | ||
230 | self.ty(f.db).hir_fmt(f) | ||
231 | } | ||
232 | } | ||
233 | |||
234 | fn write_generic_params(def: GenericDefId, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
235 | let params = f.db.generic_params(def); | ||
236 | if params.lifetimes.is_empty() | ||
237 | && params.consts.is_empty() | ||
238 | && params | ||
239 | .types | ||
240 | .iter() | ||
241 | .all(|(_, param)| !matches!(param.provenance, TypeParamProvenance::TypeParamList)) | ||
242 | { | ||
243 | return Ok(()); | ||
244 | } | ||
245 | write!(f, "<")?; | ||
246 | |||
247 | let mut first = true; | ||
248 | let mut delim = |f: &mut HirFormatter| { | ||
249 | if first { | ||
250 | first = false; | ||
251 | Ok(()) | ||
252 | } else { | ||
253 | write!(f, ", ") | ||
254 | } | ||
255 | }; | ||
256 | for (_, lifetime) in params.lifetimes.iter() { | ||
257 | delim(f)?; | ||
258 | write!(f, "{}", lifetime.name)?; | ||
259 | } | ||
260 | for (_, ty) in params.types.iter() { | ||
261 | if ty.provenance != TypeParamProvenance::TypeParamList { | ||
262 | continue; | ||
263 | } | ||
264 | if let Some(name) = &ty.name { | ||
265 | delim(f)?; | ||
266 | write!(f, "{}", name)?; | ||
267 | if let Some(default) = &ty.default { | ||
268 | write!(f, " = ")?; | ||
269 | default.hir_fmt(f)?; | ||
270 | } | ||
271 | } | ||
272 | } | ||
273 | for (_, konst) in params.consts.iter() { | ||
274 | delim(f)?; | ||
275 | write!(f, "const {}: ", konst.name)?; | ||
276 | konst.ty.hir_fmt(f)?; | ||
277 | } | ||
278 | |||
279 | write!(f, ">")?; | ||
280 | Ok(()) | ||
281 | } | ||
282 | |||
283 | fn write_where_clause(def: GenericDefId, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
284 | let params = f.db.generic_params(def); | ||
285 | if params.where_predicates.is_empty() { | ||
286 | return Ok(()); | ||
287 | } | ||
288 | |||
289 | let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter| match target { | ||
290 | WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f), | ||
291 | WherePredicateTypeTarget::TypeParam(id) => match ¶ms.types[*id].name { | ||
292 | Some(name) => write!(f, "{}", name), | ||
293 | None => write!(f, "{{unnamed}}"), | ||
294 | }, | ||
295 | }; | ||
296 | |||
297 | write!(f, "\nwhere")?; | ||
298 | |||
299 | for (pred_idx, pred) in params.where_predicates.iter().enumerate() { | ||
300 | let prev_pred = | ||
301 | if pred_idx == 0 { None } else { Some(¶ms.where_predicates[pred_idx - 1]) }; | ||
302 | |||
303 | let new_predicate = |f: &mut HirFormatter| { | ||
304 | write!(f, "{}", if pred_idx == 0 { "\n " } else { ",\n " }) | ||
305 | }; | ||
306 | |||
307 | match pred { | ||
308 | WherePredicate::TypeBound { target, bound } => { | ||
309 | if matches!(prev_pred, Some(WherePredicate::TypeBound { target: target_, .. }) if target_ == target) | ||
310 | { | ||
311 | write!(f, " + ")?; | ||
312 | } else { | ||
313 | new_predicate(f)?; | ||
314 | write_target(target, f)?; | ||
315 | write!(f, ": ")?; | ||
316 | } | ||
317 | bound.hir_fmt(f)?; | ||
318 | } | ||
319 | WherePredicate::Lifetime { target, bound } => { | ||
320 | if matches!(prev_pred, Some(WherePredicate::Lifetime { target: target_, .. }) if target_ == target) | ||
321 | { | ||
322 | write!(f, " + {}", bound.name)?; | ||
323 | } else { | ||
324 | new_predicate(f)?; | ||
325 | write!(f, "{}: {}", target.name, bound.name)?; | ||
326 | } | ||
327 | } | ||
328 | WherePredicate::ForLifetime { lifetimes, target, bound } => { | ||
329 | if matches!( | ||
330 | prev_pred, | ||
331 | Some(WherePredicate::ForLifetime { lifetimes: lifetimes_, target: target_, .. }) | ||
332 | if lifetimes_ == lifetimes && target_ == target, | ||
333 | ) { | ||
334 | write!(f, " + ")?; | ||
335 | } else { | ||
336 | new_predicate(f)?; | ||
337 | write!(f, "for<")?; | ||
338 | for (idx, lifetime) in lifetimes.iter().enumerate() { | ||
339 | if idx != 0 { | ||
340 | write!(f, ", ")?; | ||
341 | } | ||
342 | write!(f, "{}", lifetime)?; | ||
343 | } | ||
344 | write!(f, "> ")?; | ||
345 | write_target(target, f)?; | ||
346 | write!(f, ": ")?; | ||
347 | } | ||
348 | bound.hir_fmt(f)?; | ||
349 | } | ||
350 | } | ||
351 | } | ||
352 | |||
353 | // End of final predicate. There must be at least one predicate here. | ||
354 | write!(f, ",")?; | ||
355 | |||
356 | Ok(()) | ||
357 | } | ||
358 | |||
359 | impl HirDisplay for Const { | ||
360 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
361 | write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; | ||
362 | let data = f.db.const_data(self.id); | ||
363 | write!(f, "const ")?; | ||
364 | match &data.name { | ||
365 | Some(name) => write!(f, "{}: ", name)?, | ||
366 | None => write!(f, "_: ")?, | ||
367 | } | ||
368 | data.type_ref.hir_fmt(f)?; | ||
369 | Ok(()) | ||
370 | } | ||
371 | } | ||
372 | |||
373 | impl HirDisplay for Static { | ||
374 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
375 | write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; | ||
376 | let data = f.db.static_data(self.id); | ||
377 | write!(f, "static ")?; | ||
378 | if data.mutable { | ||
379 | write!(f, "mut ")?; | ||
380 | } | ||
381 | match &data.name { | ||
382 | Some(name) => write!(f, "{}: ", name)?, | ||
383 | None => write!(f, "_: ")?, | ||
384 | } | ||
385 | data.type_ref.hir_fmt(f)?; | ||
386 | Ok(()) | ||
387 | } | ||
388 | } | ||
389 | |||
390 | impl HirDisplay for Trait { | ||
391 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
392 | write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; | ||
393 | let data = f.db.trait_data(self.id); | ||
394 | if data.is_unsafe { | ||
395 | write!(f, "unsafe ")?; | ||
396 | } | ||
397 | if data.is_auto { | ||
398 | write!(f, "auto ")?; | ||
399 | } | ||
400 | write!(f, "trait {}", data.name)?; | ||
401 | let def_id = GenericDefId::TraitId(self.id); | ||
402 | write_generic_params(def_id, f)?; | ||
403 | if !data.bounds.is_empty() { | ||
404 | write!(f, ": ")?; | ||
405 | f.write_joined(&*data.bounds, " + ")?; | ||
406 | } | ||
407 | write_where_clause(def_id, f)?; | ||
408 | Ok(()) | ||
409 | } | ||
410 | } | ||
411 | |||
412 | impl HirDisplay for TypeAlias { | ||
413 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
414 | write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; | ||
415 | let data = f.db.type_alias_data(self.id); | ||
416 | write!(f, "type {}", data.name)?; | ||
417 | if !data.bounds.is_empty() { | ||
418 | write!(f, ": ")?; | ||
419 | f.write_joined(&data.bounds, " + ")?; | ||
420 | } | ||
421 | if let Some(ty) = &data.type_ref { | ||
422 | write!(f, " = ")?; | ||
423 | ty.hir_fmt(f)?; | ||
424 | } | ||
425 | Ok(()) | ||
426 | } | ||
427 | } | ||
428 | |||
429 | impl HirDisplay for Module { | ||
430 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
431 | // FIXME: Module doesn't have visibility saved in data. | ||
432 | match self.name(f.db) { | ||
433 | Some(name) => write!(f, "mod {}", name), | ||
434 | None if self.crate_root(f.db) == *self => match self.krate().display_name(f.db) { | ||
435 | Some(name) => write!(f, "extern crate {}", name), | ||
436 | None => write!(f, "extern crate {{unknown}}"), | ||
437 | }, | ||
438 | None => write!(f, "mod {{unnamed}}"), | ||
439 | } | ||
440 | } | ||
441 | } | ||