1 //! A pretty-printer for HIR.
2
3 use std::fmt::{self, Write};
4
5 use hir_expand::db::ExpandDatabase;
6 use syntax::ast::HasName;
7
8 use crate::{
9 hir::{
10 Array, BindingAnnotation, BindingId, CaptureBy, ClosureKind, Literal, LiteralOrConst,
11 Movability, Statement,
12 },
13 pretty::{print_generic_args, print_path, print_type_ref},
14 type_ref::TypeRef,
15 };
16
17 use super::*;
18
print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBodyId) -> String19 pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBodyId) -> String {
20 let header = match owner {
21 DefWithBodyId::FunctionId(it) => {
22 let item_tree_id = it.lookup(db).id;
23 format!(
24 "fn {}",
25 item_tree_id.item_tree(db)[item_tree_id.value].name.display(db.upcast())
26 )
27 }
28 DefWithBodyId::StaticId(it) => {
29 let item_tree_id = it.lookup(db).id;
30 format!(
31 "static {} = ",
32 item_tree_id.item_tree(db)[item_tree_id.value].name.display(db.upcast())
33 )
34 }
35 DefWithBodyId::ConstId(it) => {
36 let item_tree_id = it.lookup(db).id;
37 let name = match &item_tree_id.item_tree(db)[item_tree_id.value].name {
38 Some(name) => name.display(db.upcast()).to_string(),
39 None => "_".to_string(),
40 };
41 format!("const {name} = ")
42 }
43 DefWithBodyId::InTypeConstId(_) => format!("In type const = "),
44 DefWithBodyId::VariantId(it) => {
45 let src = it.parent.child_source(db);
46 let variant = &src.value[it.local_id];
47 match &variant.name() {
48 Some(name) => name.to_string(),
49 None => "_".to_string(),
50 }
51 }
52 };
53
54 let mut p =
55 Printer { db: db.upcast(), body, buf: header, indent_level: 0, needs_indent: false };
56 if let DefWithBodyId::FunctionId(it) = owner {
57 p.buf.push('(');
58 body.params.iter().zip(&db.function_data(it).params).for_each(|(¶m, ty)| {
59 p.print_pat(param);
60 p.buf.push(':');
61 p.print_type_ref(ty);
62 });
63 p.buf.push(')');
64 p.buf.push(' ');
65 }
66 p.print_expr(body.body_expr);
67 if matches!(owner, DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_)) {
68 p.buf.push(';');
69 }
70 p.buf
71 }
72
print_expr_hir( db: &dyn DefDatabase, body: &Body, _owner: DefWithBodyId, expr: ExprId, ) -> String73 pub(super) fn print_expr_hir(
74 db: &dyn DefDatabase,
75 body: &Body,
76 _owner: DefWithBodyId,
77 expr: ExprId,
78 ) -> String {
79 let mut p =
80 Printer { db: db.upcast(), body, buf: String::new(), indent_level: 0, needs_indent: false };
81 p.print_expr(expr);
82 p.buf
83 }
84
85 macro_rules! w {
86 ($dst:expr, $($arg:tt)*) => {
87 { let _ = write!($dst, $($arg)*); }
88 };
89 }
90
91 macro_rules! wln {
92 ($dst:expr) => {
93 { let _ = writeln!($dst); }
94 };
95 ($dst:expr, $($arg:tt)*) => {
96 { let _ = writeln!($dst, $($arg)*); }
97 };
98 }
99
100 struct Printer<'a> {
101 db: &'a dyn ExpandDatabase,
102 body: &'a Body,
103 buf: String,
104 indent_level: usize,
105 needs_indent: bool,
106 }
107
108 impl<'a> Write for Printer<'a> {
write_str(&mut self, s: &str) -> fmt::Result109 fn write_str(&mut self, s: &str) -> fmt::Result {
110 for line in s.split_inclusive('\n') {
111 if self.needs_indent {
112 match self.buf.chars().rev().find(|ch| *ch != ' ') {
113 Some('\n') | None => {}
114 _ => self.buf.push('\n'),
115 }
116 self.buf.push_str(&" ".repeat(self.indent_level));
117 self.needs_indent = false;
118 }
119
120 self.buf.push_str(line);
121 self.needs_indent = line.ends_with('\n');
122 }
123
124 Ok(())
125 }
126 }
127
128 impl<'a> Printer<'a> {
indented(&mut self, f: impl FnOnce(&mut Self))129 fn indented(&mut self, f: impl FnOnce(&mut Self)) {
130 self.indent_level += 1;
131 wln!(self);
132 f(self);
133 self.indent_level -= 1;
134 self.buf = self.buf.trim_end_matches('\n').to_string();
135 }
136
whitespace(&mut self)137 fn whitespace(&mut self) {
138 match self.buf.chars().next_back() {
139 None | Some('\n' | ' ') => {}
140 _ => self.buf.push(' '),
141 }
142 }
143
newline(&mut self)144 fn newline(&mut self) {
145 match self.buf.chars().rev().find(|ch| *ch != ' ') {
146 Some('\n') | None => {}
147 _ => writeln!(self).unwrap(),
148 }
149 }
150
print_expr(&mut self, expr: ExprId)151 fn print_expr(&mut self, expr: ExprId) {
152 let expr = &self.body[expr];
153
154 match expr {
155 Expr::Missing => w!(self, "�"),
156 Expr::Underscore => w!(self, "_"),
157 Expr::Path(path) => self.print_path(path),
158 Expr::If { condition, then_branch, else_branch } => {
159 w!(self, "if ");
160 self.print_expr(*condition);
161 w!(self, " ");
162 self.print_expr(*then_branch);
163 if let Some(els) = *else_branch {
164 w!(self, " else ");
165 self.print_expr(els);
166 }
167 }
168 Expr::Let { pat, expr } => {
169 w!(self, "let ");
170 self.print_pat(*pat);
171 w!(self, " = ");
172 self.print_expr(*expr);
173 }
174 Expr::Loop { body, label } => {
175 if let Some(lbl) = label {
176 w!(self, "{}: ", self.body[*lbl].name.display(self.db));
177 }
178 w!(self, "loop ");
179 self.print_expr(*body);
180 }
181 Expr::While { condition, body, label } => {
182 if let Some(lbl) = label {
183 w!(self, "{}: ", self.body[*lbl].name.display(self.db));
184 }
185 w!(self, "while ");
186 self.print_expr(*condition);
187 self.print_expr(*body);
188 }
189 Expr::Call { callee, args, is_assignee_expr: _ } => {
190 self.print_expr(*callee);
191 w!(self, "(");
192 if !args.is_empty() {
193 self.indented(|p| {
194 for arg in &**args {
195 p.print_expr(*arg);
196 wln!(p, ",");
197 }
198 });
199 }
200 w!(self, ")");
201 }
202 Expr::MethodCall { receiver, method_name, args, generic_args } => {
203 self.print_expr(*receiver);
204 w!(self, ".{}", method_name.display(self.db));
205 if let Some(args) = generic_args {
206 w!(self, "::<");
207 print_generic_args(self.db, args, self).unwrap();
208 w!(self, ">");
209 }
210 w!(self, "(");
211 if !args.is_empty() {
212 self.indented(|p| {
213 for arg in &**args {
214 p.print_expr(*arg);
215 wln!(p, ",");
216 }
217 });
218 }
219 w!(self, ")");
220 }
221 Expr::Match { expr, arms } => {
222 w!(self, "match ");
223 self.print_expr(*expr);
224 w!(self, " {{");
225 self.indented(|p| {
226 for arm in &**arms {
227 p.print_pat(arm.pat);
228 if let Some(guard) = arm.guard {
229 w!(p, " if ");
230 p.print_expr(guard);
231 }
232 w!(p, " => ");
233 p.print_expr(arm.expr);
234 wln!(p, ",");
235 }
236 });
237 wln!(self, "}}");
238 }
239 Expr::Continue { label } => {
240 w!(self, "continue");
241 if let Some(lbl) = label {
242 w!(self, " {}", self.body[*lbl].name.display(self.db));
243 }
244 }
245 Expr::Break { expr, label } => {
246 w!(self, "break");
247 if let Some(lbl) = label {
248 w!(self, " {}", self.body[*lbl].name.display(self.db));
249 }
250 if let Some(expr) = expr {
251 self.whitespace();
252 self.print_expr(*expr);
253 }
254 }
255 Expr::Return { expr } => {
256 w!(self, "return");
257 if let Some(expr) = expr {
258 self.whitespace();
259 self.print_expr(*expr);
260 }
261 }
262 Expr::Yield { expr } => {
263 w!(self, "yield");
264 if let Some(expr) = expr {
265 self.whitespace();
266 self.print_expr(*expr);
267 }
268 }
269 Expr::Yeet { expr } => {
270 w!(self, "do");
271 self.whitespace();
272 w!(self, "yeet");
273 if let Some(expr) = expr {
274 self.whitespace();
275 self.print_expr(*expr);
276 }
277 }
278 Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr: _ } => {
279 match path {
280 Some(path) => self.print_path(path),
281 None => w!(self, "�"),
282 }
283
284 w!(self, "{{");
285 self.indented(|p| {
286 for field in &**fields {
287 w!(p, "{}: ", field.name.display(self.db));
288 p.print_expr(field.expr);
289 wln!(p, ",");
290 }
291 if let Some(spread) = spread {
292 w!(p, "..");
293 p.print_expr(*spread);
294 wln!(p);
295 }
296 if *ellipsis {
297 wln!(p, "..");
298 }
299 });
300 w!(self, "}}");
301 }
302 Expr::Field { expr, name } => {
303 self.print_expr(*expr);
304 w!(self, ".{}", name.display(self.db));
305 }
306 Expr::Await { expr } => {
307 self.print_expr(*expr);
308 w!(self, ".await");
309 }
310 Expr::Cast { expr, type_ref } => {
311 self.print_expr(*expr);
312 w!(self, " as ");
313 self.print_type_ref(type_ref);
314 }
315 Expr::Ref { expr, rawness, mutability } => {
316 w!(self, "&");
317 if rawness.is_raw() {
318 w!(self, "raw ");
319 }
320 if mutability.is_mut() {
321 w!(self, "mut ");
322 }
323 self.print_expr(*expr);
324 }
325 Expr::Box { expr } => {
326 w!(self, "box ");
327 self.print_expr(*expr);
328 }
329 Expr::UnaryOp { expr, op } => {
330 let op = match op {
331 ast::UnaryOp::Deref => "*",
332 ast::UnaryOp::Not => "!",
333 ast::UnaryOp::Neg => "-",
334 };
335 w!(self, "{}", op);
336 self.print_expr(*expr);
337 }
338 Expr::BinaryOp { lhs, rhs, op } => {
339 let (bra, ket) = match op {
340 None | Some(ast::BinaryOp::Assignment { .. }) => ("", ""),
341 _ => ("(", ")"),
342 };
343 w!(self, "{}", bra);
344 self.print_expr(*lhs);
345 w!(self, "{} ", ket);
346 match op {
347 Some(op) => w!(self, "{}", op),
348 None => w!(self, "�"), // :)
349 }
350 w!(self, " {}", bra);
351 self.print_expr(*rhs);
352 w!(self, "{}", ket);
353 }
354 Expr::Range { lhs, rhs, range_type } => {
355 if let Some(lhs) = lhs {
356 w!(self, "(");
357 self.print_expr(*lhs);
358 w!(self, ") ");
359 }
360 let range = match range_type {
361 ast::RangeOp::Exclusive => "..",
362 ast::RangeOp::Inclusive => "..=",
363 };
364 w!(self, "{}", range);
365 if let Some(rhs) = rhs {
366 w!(self, "(");
367 self.print_expr(*rhs);
368 w!(self, ") ");
369 }
370 }
371 Expr::Index { base, index } => {
372 self.print_expr(*base);
373 w!(self, "[");
374 self.print_expr(*index);
375 w!(self, "]");
376 }
377 Expr::Closure { args, arg_types, ret_type, body, closure_kind, capture_by } => {
378 match closure_kind {
379 ClosureKind::Generator(Movability::Static) => {
380 w!(self, "static ");
381 }
382 ClosureKind::Async => {
383 w!(self, "async ");
384 }
385 _ => (),
386 }
387 match capture_by {
388 CaptureBy::Value => {
389 w!(self, "move ");
390 }
391 CaptureBy::Ref => (),
392 }
393 w!(self, "|");
394 for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() {
395 if i != 0 {
396 w!(self, ", ");
397 }
398 self.print_pat(*pat);
399 if let Some(ty) = ty {
400 w!(self, ": ");
401 self.print_type_ref(ty);
402 }
403 }
404 w!(self, "|");
405 if let Some(ret_ty) = ret_type {
406 w!(self, " -> ");
407 self.print_type_ref(ret_ty);
408 }
409 self.whitespace();
410 self.print_expr(*body);
411 }
412 Expr::Tuple { exprs, is_assignee_expr: _ } => {
413 w!(self, "(");
414 for expr in exprs.iter() {
415 self.print_expr(*expr);
416 w!(self, ", ");
417 }
418 w!(self, ")");
419 }
420 Expr::Array(arr) => {
421 w!(self, "[");
422 if !matches!(arr, Array::ElementList { elements, .. } if elements.is_empty()) {
423 self.indented(|p| match arr {
424 Array::ElementList { elements, is_assignee_expr: _ } => {
425 for elem in elements.iter() {
426 p.print_expr(*elem);
427 w!(p, ", ");
428 }
429 }
430 Array::Repeat { initializer, repeat } => {
431 p.print_expr(*initializer);
432 w!(p, "; ");
433 p.print_expr(*repeat);
434 }
435 });
436 self.newline();
437 }
438 w!(self, "]");
439 }
440 Expr::Literal(lit) => self.print_literal(lit),
441 Expr::Block { id: _, statements, tail, label } => {
442 let label = label.map(|lbl| format!("{}: ", self.body[lbl].name.display(self.db)));
443 self.print_block(label.as_deref(), statements, tail);
444 }
445 Expr::Unsafe { id: _, statements, tail } => {
446 self.print_block(Some("unsafe "), statements, tail);
447 }
448 Expr::Async { id: _, statements, tail } => {
449 self.print_block(Some("async "), statements, tail);
450 }
451 Expr::Const(id) => {
452 w!(self, "const {{ /* {id:?} */ }}");
453 }
454 }
455 }
456
print_block( &mut self, label: Option<&str>, statements: &[Statement], tail: &Option<la_arena::Idx<Expr>>, )457 fn print_block(
458 &mut self,
459 label: Option<&str>,
460 statements: &[Statement],
461 tail: &Option<la_arena::Idx<Expr>>,
462 ) {
463 self.whitespace();
464 if let Some(lbl) = label {
465 w!(self, "{}", lbl);
466 }
467 w!(self, "{{");
468 if !statements.is_empty() || tail.is_some() {
469 self.indented(|p| {
470 for stmt in statements {
471 p.print_stmt(stmt);
472 }
473 if let Some(tail) = tail {
474 p.print_expr(*tail);
475 }
476 p.newline();
477 });
478 }
479 w!(self, "}}");
480 }
481
print_pat(&mut self, pat: PatId)482 fn print_pat(&mut self, pat: PatId) {
483 let pat = &self.body[pat];
484
485 match pat {
486 Pat::Missing => w!(self, "�"),
487 Pat::Wild => w!(self, "_"),
488 Pat::Tuple { args, ellipsis } => {
489 w!(self, "(");
490 for (i, pat) in args.iter().enumerate() {
491 if i != 0 {
492 w!(self, ", ");
493 }
494 if *ellipsis == Some(i) {
495 w!(self, ".., ");
496 }
497 self.print_pat(*pat);
498 }
499 w!(self, ")");
500 }
501 Pat::Or(pats) => {
502 for (i, pat) in pats.iter().enumerate() {
503 if i != 0 {
504 w!(self, " | ");
505 }
506 self.print_pat(*pat);
507 }
508 }
509 Pat::Record { path, args, ellipsis } => {
510 match path {
511 Some(path) => self.print_path(path),
512 None => w!(self, "�"),
513 }
514
515 w!(self, " {{");
516 self.indented(|p| {
517 for arg in args.iter() {
518 w!(p, "{}: ", arg.name.display(self.db));
519 p.print_pat(arg.pat);
520 wln!(p, ",");
521 }
522 if *ellipsis {
523 wln!(p, "..");
524 }
525 });
526 w!(self, "}}");
527 }
528 Pat::Range { start, end } => {
529 if let Some(start) = start {
530 self.print_literal_or_const(start);
531 }
532 w!(self, "..=");
533 if let Some(end) = end {
534 self.print_literal_or_const(end);
535 }
536 }
537 Pat::Slice { prefix, slice, suffix } => {
538 w!(self, "[");
539 for pat in prefix.iter() {
540 self.print_pat(*pat);
541 w!(self, ", ");
542 }
543 if let Some(pat) = slice {
544 self.print_pat(*pat);
545 w!(self, ", ");
546 }
547 for pat in suffix.iter() {
548 self.print_pat(*pat);
549 w!(self, ", ");
550 }
551 w!(self, "]");
552 }
553 Pat::Path(path) => self.print_path(path),
554 Pat::Lit(expr) => self.print_expr(*expr),
555 Pat::Bind { id, subpat } => {
556 self.print_binding(*id);
557 if let Some(pat) = subpat {
558 self.whitespace();
559 self.print_pat(*pat);
560 }
561 }
562 Pat::TupleStruct { path, args, ellipsis } => {
563 match path {
564 Some(path) => self.print_path(path),
565 None => w!(self, "�"),
566 }
567 w!(self, "(");
568 for (i, arg) in args.iter().enumerate() {
569 if i != 0 {
570 w!(self, ", ");
571 }
572 if *ellipsis == Some(i) {
573 w!(self, ", ..");
574 }
575 self.print_pat(*arg);
576 }
577 w!(self, ")");
578 }
579 Pat::Ref { pat, mutability } => {
580 w!(self, "&");
581 if mutability.is_mut() {
582 w!(self, "mut ");
583 }
584 self.print_pat(*pat);
585 }
586 Pat::Box { inner } => {
587 w!(self, "box ");
588 self.print_pat(*inner);
589 }
590 Pat::ConstBlock(c) => {
591 w!(self, "const ");
592 self.print_expr(*c);
593 }
594 }
595 }
596
print_stmt(&mut self, stmt: &Statement)597 fn print_stmt(&mut self, stmt: &Statement) {
598 match stmt {
599 Statement::Let { pat, type_ref, initializer, else_branch } => {
600 w!(self, "let ");
601 self.print_pat(*pat);
602 if let Some(ty) = type_ref {
603 w!(self, ": ");
604 self.print_type_ref(ty);
605 }
606 if let Some(init) = initializer {
607 w!(self, " = ");
608 self.print_expr(*init);
609 }
610 if let Some(els) = else_branch {
611 w!(self, " else ");
612 self.print_expr(*els);
613 }
614 wln!(self, ";");
615 }
616 Statement::Expr { expr, has_semi } => {
617 self.print_expr(*expr);
618 if *has_semi {
619 w!(self, ";");
620 }
621 wln!(self);
622 }
623 }
624 }
625
print_literal_or_const(&mut self, literal_or_const: &LiteralOrConst)626 fn print_literal_or_const(&mut self, literal_or_const: &LiteralOrConst) {
627 match literal_or_const {
628 LiteralOrConst::Literal(l) => self.print_literal(l),
629 LiteralOrConst::Const(c) => self.print_path(c),
630 }
631 }
632
print_literal(&mut self, literal: &Literal)633 fn print_literal(&mut self, literal: &Literal) {
634 match literal {
635 Literal::String(it) => w!(self, "{:?}", it),
636 Literal::ByteString(it) => w!(self, "\"{}\"", it.escape_ascii()),
637 Literal::CString(it) => w!(self, "\"{}\\0\"", it),
638 Literal::Char(it) => w!(self, "'{}'", it.escape_debug()),
639 Literal::Bool(it) => w!(self, "{}", it),
640 Literal::Int(i, suffix) => {
641 w!(self, "{}", i);
642 if let Some(suffix) = suffix {
643 w!(self, "{}", suffix);
644 }
645 }
646 Literal::Uint(i, suffix) => {
647 w!(self, "{}", i);
648 if let Some(suffix) = suffix {
649 w!(self, "{}", suffix);
650 }
651 }
652 Literal::Float(f, suffix) => {
653 w!(self, "{}", f);
654 if let Some(suffix) = suffix {
655 w!(self, "{}", suffix);
656 }
657 }
658 }
659 }
660
print_type_ref(&mut self, ty: &TypeRef)661 fn print_type_ref(&mut self, ty: &TypeRef) {
662 print_type_ref(self.db, ty, self).unwrap();
663 }
664
print_path(&mut self, path: &Path)665 fn print_path(&mut self, path: &Path) {
666 print_path(self.db, path, self).unwrap();
667 }
668
print_binding(&mut self, id: BindingId)669 fn print_binding(&mut self, id: BindingId) {
670 let Binding { name, mode, .. } = &self.body.bindings[id];
671 let mode = match mode {
672 BindingAnnotation::Unannotated => "",
673 BindingAnnotation::Mutable => "mut ",
674 BindingAnnotation::Ref => "ref ",
675 BindingAnnotation::RefMut => "ref mut ",
676 };
677 w!(self, "{}{}", mode, name.display(self.db));
678 }
679 }
680