]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ast_pretty/src/pprust/state/expr.rs
Move `{core,std}::stream::Stream` to `{core,std}::async_iter::AsyncIterator`.
[rust.git] / compiler / rustc_ast_pretty / src / pprust / state / expr.rs
1 use crate::pp::Breaks::{Consistent, Inconsistent};
2 use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
3
4 use rustc_ast::ptr::P;
5 use rustc_ast::util::parser::{self, AssocOp, Fixity};
6 use rustc_ast::{self as ast, BlockCheckMode};
7
8 impl<'a> State<'a> {
9     fn print_else(&mut self, els: Option<&ast::Expr>) {
10         if let Some(_else) = els {
11             match _else.kind {
12                 // Another `else if` block.
13                 ast::ExprKind::If(ref i, ref then, ref e) => {
14                     self.cbox(INDENT_UNIT - 1);
15                     self.ibox(0);
16                     self.word(" else if ");
17                     self.print_expr_as_cond(i);
18                     self.space();
19                     self.print_block(then);
20                     self.print_else(e.as_deref())
21                 }
22                 // Final `else` block.
23                 ast::ExprKind::Block(ref b, _) => {
24                     self.cbox(INDENT_UNIT - 1);
25                     self.ibox(0);
26                     self.word(" else ");
27                     self.print_block(b)
28                 }
29                 // Constraints would be great here!
30                 _ => {
31                     panic!("print_if saw if with weird alternative");
32                 }
33             }
34         }
35     }
36
37     fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block, elseopt: Option<&ast::Expr>) {
38         self.head("if");
39         self.print_expr_as_cond(test);
40         self.space();
41         self.print_block(blk);
42         self.print_else(elseopt)
43     }
44
45     fn print_call_post(&mut self, args: &[P<ast::Expr>]) {
46         self.popen();
47         self.commasep_exprs(Inconsistent, args);
48         self.pclose()
49     }
50
51     fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8) {
52         self.print_expr_cond_paren(expr, expr.precedence().order() < prec)
53     }
54
55     /// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
56     /// `if cond { ... }`.
57     fn print_expr_as_cond(&mut self, expr: &ast::Expr) {
58         self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
59     }
60
61     // Does `expr` need parentheses when printed in a condition position?
62     //
63     // These cases need parens due to the parse error observed in #26461: `if return {}`
64     // parses as the erroneous construct `if (return {})`, not `if (return) {}`.
65     pub(super) fn cond_needs_par(expr: &ast::Expr) -> bool {
66         match expr.kind {
67             ast::ExprKind::Break(..) | ast::ExprKind::Closure(..) | ast::ExprKind::Ret(..) => true,
68             _ => parser::contains_exterior_struct_lit(expr),
69         }
70     }
71
72     /// Prints `expr` or `(expr)` when `needs_par` holds.
73     pub(super) fn print_expr_cond_paren(&mut self, expr: &ast::Expr, needs_par: bool) {
74         if needs_par {
75             self.popen();
76         }
77         self.print_expr(expr);
78         if needs_par {
79             self.pclose();
80         }
81     }
82
83     fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>]) {
84         self.ibox(INDENT_UNIT);
85         self.word("[");
86         self.commasep_exprs(Inconsistent, exprs);
87         self.word("]");
88         self.end();
89     }
90
91     pub(super) fn print_expr_anon_const(&mut self, expr: &ast::AnonConst) {
92         self.ibox(INDENT_UNIT);
93         self.word("const");
94         self.print_expr(&expr.value);
95         self.end();
96     }
97
98     fn print_expr_repeat(&mut self, element: &ast::Expr, count: &ast::AnonConst) {
99         self.ibox(INDENT_UNIT);
100         self.word("[");
101         self.print_expr(element);
102         self.word_space(";");
103         self.print_expr(&count.value);
104         self.word("]");
105         self.end();
106     }
107
108     fn print_expr_struct(
109         &mut self,
110         qself: &Option<ast::QSelf>,
111         path: &ast::Path,
112         fields: &[ast::ExprField],
113         rest: &ast::StructRest,
114     ) {
115         if let Some(qself) = qself {
116             self.print_qpath(path, qself, true);
117         } else {
118             self.print_path(path, true, 0);
119         }
120         self.word("{");
121         self.commasep_cmnt(
122             Consistent,
123             fields,
124             |s, field| {
125                 s.print_outer_attributes(&field.attrs);
126                 s.ibox(INDENT_UNIT);
127                 if !field.is_shorthand {
128                     s.print_ident(field.ident);
129                     s.word_space(":");
130                 }
131                 s.print_expr(&field.expr);
132                 s.end();
133             },
134             |f| f.span,
135         );
136         match rest {
137             ast::StructRest::Base(_) | ast::StructRest::Rest(_) => {
138                 self.ibox(INDENT_UNIT);
139                 if !fields.is_empty() {
140                     self.word(",");
141                     self.space();
142                 }
143                 self.word("..");
144                 if let ast::StructRest::Base(ref expr) = *rest {
145                     self.print_expr(expr);
146                 }
147                 self.end();
148             }
149             ast::StructRest::None if !fields.is_empty() => self.word(","),
150             _ => {}
151         }
152         self.word("}");
153     }
154
155     fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>]) {
156         self.popen();
157         self.commasep_exprs(Inconsistent, exprs);
158         if exprs.len() == 1 {
159             self.word(",");
160         }
161         self.pclose()
162     }
163
164     fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>]) {
165         let prec = match func.kind {
166             ast::ExprKind::Field(..) => parser::PREC_FORCE_PAREN,
167             _ => parser::PREC_POSTFIX,
168         };
169
170         self.print_expr_maybe_paren(func, prec);
171         self.print_call_post(args)
172     }
173
174     fn print_expr_method_call(&mut self, segment: &ast::PathSegment, args: &[P<ast::Expr>]) {
175         let base_args = &args[1..];
176         self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX);
177         self.word(".");
178         self.print_ident(segment.ident);
179         if let Some(ref args) = segment.args {
180             self.print_generic_args(args, true);
181         }
182         self.print_call_post(base_args)
183     }
184
185     fn print_expr_binary(&mut self, op: ast::BinOp, lhs: &ast::Expr, rhs: &ast::Expr) {
186         let assoc_op = AssocOp::from_ast_binop(op.node);
187         let prec = assoc_op.precedence() as i8;
188         let fixity = assoc_op.fixity();
189
190         let (left_prec, right_prec) = match fixity {
191             Fixity::Left => (prec, prec + 1),
192             Fixity::Right => (prec + 1, prec),
193             Fixity::None => (prec + 1, prec + 1),
194         };
195
196         let left_prec = match (&lhs.kind, op.node) {
197             // These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is
198             // the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead
199             // of `(x as i32) < ...`. We need to convince it _not_ to do that.
200             (&ast::ExprKind::Cast { .. }, ast::BinOpKind::Lt | ast::BinOpKind::Shl) => {
201                 parser::PREC_FORCE_PAREN
202             }
203             // We are given `(let _ = a) OP b`.
204             //
205             // - When `OP <= LAnd` we should print `let _ = a OP b` to avoid redundant parens
206             //   as the parser will interpret this as `(let _ = a) OP b`.
207             //
208             // - Otherwise, e.g. when we have `(let a = b) < c` in AST,
209             //   parens are required since the parser would interpret `let a = b < c` as
210             //   `let a = (b < c)`. To achieve this, we force parens.
211             (&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => {
212                 parser::PREC_FORCE_PAREN
213             }
214             _ => left_prec,
215         };
216
217         self.print_expr_maybe_paren(lhs, left_prec);
218         self.space();
219         self.word_space(op.node.to_string());
220         self.print_expr_maybe_paren(rhs, right_prec)
221     }
222
223     fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr) {
224         self.word(ast::UnOp::to_string(op));
225         self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
226     }
227
228     fn print_expr_addr_of(
229         &mut self,
230         kind: ast::BorrowKind,
231         mutability: ast::Mutability,
232         expr: &ast::Expr,
233     ) {
234         self.word("&");
235         match kind {
236             ast::BorrowKind::Ref => self.print_mutability(mutability, false),
237             ast::BorrowKind::Raw => {
238                 self.word_nbsp("raw");
239                 self.print_mutability(mutability, true);
240             }
241         }
242         self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
243     }
244
245     pub fn print_expr(&mut self, expr: &ast::Expr) {
246         self.print_expr_outer_attr_style(expr, true)
247     }
248
249     pub(super) fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline: bool) {
250         self.maybe_print_comment(expr.span.lo());
251
252         let attrs = &expr.attrs;
253         if is_inline {
254             self.print_outer_attributes_inline(attrs);
255         } else {
256             self.print_outer_attributes(attrs);
257         }
258
259         self.ibox(INDENT_UNIT);
260         self.ann.pre(self, AnnNode::Expr(expr));
261         match expr.kind {
262             ast::ExprKind::Box(ref expr) => {
263                 self.word_space("box");
264                 self.print_expr_maybe_paren(expr, parser::PREC_PREFIX);
265             }
266             ast::ExprKind::Array(ref exprs) => {
267                 self.print_expr_vec(exprs);
268             }
269             ast::ExprKind::ConstBlock(ref anon_const) => {
270                 self.print_expr_anon_const(anon_const);
271             }
272             ast::ExprKind::Repeat(ref element, ref count) => {
273                 self.print_expr_repeat(element, count);
274             }
275             ast::ExprKind::Struct(ref se) => {
276                 self.print_expr_struct(&se.qself, &se.path, &se.fields, &se.rest);
277             }
278             ast::ExprKind::Tup(ref exprs) => {
279                 self.print_expr_tup(exprs);
280             }
281             ast::ExprKind::Call(ref func, ref args) => {
282                 self.print_expr_call(func, &args);
283             }
284             ast::ExprKind::MethodCall(ref segment, ref args, _) => {
285                 self.print_expr_method_call(segment, &args);
286             }
287             ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
288                 self.print_expr_binary(op, lhs, rhs);
289             }
290             ast::ExprKind::Unary(op, ref expr) => {
291                 self.print_expr_unary(op, expr);
292             }
293             ast::ExprKind::AddrOf(k, m, ref expr) => {
294                 self.print_expr_addr_of(k, m, expr);
295             }
296             ast::ExprKind::Lit(ref lit) => {
297                 self.print_literal(lit);
298             }
299             ast::ExprKind::Cast(ref expr, ref ty) => {
300                 let prec = AssocOp::As.precedence() as i8;
301                 self.print_expr_maybe_paren(expr, prec);
302                 self.space();
303                 self.word_space("as");
304                 self.print_type(ty);
305             }
306             ast::ExprKind::Type(ref expr, ref ty) => {
307                 let prec = AssocOp::Colon.precedence() as i8;
308                 self.print_expr_maybe_paren(expr, prec);
309                 self.word_space(":");
310                 self.print_type(ty);
311             }
312             ast::ExprKind::Let(ref pat, ref scrutinee, _) => {
313                 self.print_let(pat, scrutinee);
314             }
315             ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
316                 self.print_if(test, blk, elseopt.as_deref())
317             }
318             ast::ExprKind::While(ref test, ref blk, opt_label) => {
319                 if let Some(label) = opt_label {
320                     self.print_ident(label.ident);
321                     self.word_space(":");
322                 }
323                 self.cbox(0);
324                 self.ibox(0);
325                 self.word_nbsp("while");
326                 self.print_expr_as_cond(test);
327                 self.space();
328                 self.print_block_with_attrs(blk, attrs);
329             }
330             ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_label) => {
331                 if let Some(label) = opt_label {
332                     self.print_ident(label.ident);
333                     self.word_space(":");
334                 }
335                 self.cbox(0);
336                 self.ibox(0);
337                 self.word_nbsp("for");
338                 self.print_pat(pat);
339                 self.space();
340                 self.word_space("in");
341                 self.print_expr_as_cond(iter);
342                 self.space();
343                 self.print_block_with_attrs(blk, attrs);
344             }
345             ast::ExprKind::Loop(ref blk, opt_label) => {
346                 if let Some(label) = opt_label {
347                     self.print_ident(label.ident);
348                     self.word_space(":");
349                 }
350                 self.cbox(0);
351                 self.ibox(0);
352                 self.word_nbsp("loop");
353                 self.print_block_with_attrs(blk, attrs);
354             }
355             ast::ExprKind::Match(ref expr, ref arms) => {
356                 self.cbox(0);
357                 self.ibox(0);
358                 self.word_nbsp("match");
359                 self.print_expr_as_cond(expr);
360                 self.space();
361                 self.bopen();
362                 self.print_inner_attributes_no_trailing_hardbreak(attrs);
363                 for arm in arms {
364                     self.print_arm(arm);
365                 }
366                 let empty = attrs.is_empty() && arms.is_empty();
367                 self.bclose(expr.span, empty);
368             }
369             ast::ExprKind::Closure(
370                 capture_clause,
371                 asyncness,
372                 movability,
373                 ref decl,
374                 ref body,
375                 _,
376             ) => {
377                 self.print_movability(movability);
378                 self.print_asyncness(asyncness);
379                 self.print_capture_clause(capture_clause);
380
381                 self.print_fn_params_and_ret(decl, true);
382                 self.space();
383                 self.print_expr(body);
384                 self.end(); // need to close a box
385
386                 // a box will be closed by print_expr, but we didn't want an overall
387                 // wrapper so we closed the corresponding opening. so create an
388                 // empty box to satisfy the close.
389                 self.ibox(0);
390             }
391             ast::ExprKind::Block(ref blk, opt_label) => {
392                 if let Some(label) = opt_label {
393                     self.print_ident(label.ident);
394                     self.word_space(":");
395                 }
396                 // containing cbox, will be closed by print-block at }
397                 self.cbox(0);
398                 // head-box, will be closed by print-block after {
399                 self.ibox(0);
400                 self.print_block_with_attrs(blk, attrs);
401             }
402             ast::ExprKind::Async(capture_clause, _, ref blk) => {
403                 self.word_nbsp("async");
404                 self.print_capture_clause(capture_clause);
405                 // cbox/ibox in analogy to the `ExprKind::Block` arm above
406                 self.cbox(0);
407                 self.ibox(0);
408                 self.print_block_with_attrs(blk, attrs);
409             }
410             ast::ExprKind::Await(ref expr) => {
411                 self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
412                 self.word(".await");
413             }
414             ast::ExprKind::Assign(ref lhs, ref rhs, _) => {
415                 let prec = AssocOp::Assign.precedence() as i8;
416                 self.print_expr_maybe_paren(lhs, prec + 1);
417                 self.space();
418                 self.word_space("=");
419                 self.print_expr_maybe_paren(rhs, prec);
420             }
421             ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
422                 let prec = AssocOp::Assign.precedence() as i8;
423                 self.print_expr_maybe_paren(lhs, prec + 1);
424                 self.space();
425                 self.word(op.node.to_string());
426                 self.word_space("=");
427                 self.print_expr_maybe_paren(rhs, prec);
428             }
429             ast::ExprKind::Field(ref expr, ident) => {
430                 self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
431                 self.word(".");
432                 self.print_ident(ident);
433             }
434             ast::ExprKind::Index(ref expr, ref index) => {
435                 self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
436                 self.word("[");
437                 self.print_expr(index);
438                 self.word("]");
439             }
440             ast::ExprKind::Range(ref start, ref end, limits) => {
441                 // Special case for `Range`.  `AssocOp` claims that `Range` has higher precedence
442                 // than `Assign`, but `x .. x = x` gives a parse error instead of `x .. (x = x)`.
443                 // Here we use a fake precedence value so that any child with lower precedence than
444                 // a "normal" binop gets parenthesized.  (`LOr` is the lowest-precedence binop.)
445                 let fake_prec = AssocOp::LOr.precedence() as i8;
446                 if let Some(ref e) = *start {
447                     self.print_expr_maybe_paren(e, fake_prec);
448                 }
449                 if limits == ast::RangeLimits::HalfOpen {
450                     self.word("..");
451                 } else {
452                     self.word("..=");
453                 }
454                 if let Some(ref e) = *end {
455                     self.print_expr_maybe_paren(e, fake_prec);
456                 }
457             }
458             ast::ExprKind::Underscore => self.word("_"),
459             ast::ExprKind::Path(None, ref path) => self.print_path(path, true, 0),
460             ast::ExprKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, true),
461             ast::ExprKind::Break(opt_label, ref opt_expr) => {
462                 self.word("break");
463                 if let Some(label) = opt_label {
464                     self.space();
465                     self.print_ident(label.ident);
466                 }
467                 if let Some(ref expr) = *opt_expr {
468                     self.space();
469                     self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
470                 }
471             }
472             ast::ExprKind::Continue(opt_label) => {
473                 self.word("continue");
474                 if let Some(label) = opt_label {
475                     self.space();
476                     self.print_ident(label.ident);
477                 }
478             }
479             ast::ExprKind::Ret(ref result) => {
480                 self.word("return");
481                 if let Some(ref expr) = *result {
482                     self.word(" ");
483                     self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
484                 }
485             }
486             ast::ExprKind::InlineAsm(ref a) => {
487                 self.word("asm!");
488                 self.print_inline_asm(a);
489             }
490             ast::ExprKind::MacCall(ref m) => self.print_mac(m),
491             ast::ExprKind::Paren(ref e) => {
492                 self.popen();
493                 self.print_expr(e);
494                 self.pclose();
495             }
496             ast::ExprKind::Yield(ref e) => {
497                 self.word("yield");
498
499                 if let Some(ref expr) = *e {
500                     self.space();
501                     self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
502                 }
503             }
504             ast::ExprKind::Try(ref e) => {
505                 self.print_expr_maybe_paren(e, parser::PREC_POSTFIX);
506                 self.word("?")
507             }
508             ast::ExprKind::TryBlock(ref blk) => {
509                 self.cbox(0);
510                 self.ibox(0);
511                 self.word_nbsp("try");
512                 self.print_block_with_attrs(blk, attrs)
513             }
514             ast::ExprKind::Err => {
515                 self.popen();
516                 self.word("/*ERROR*/");
517                 self.pclose()
518             }
519         }
520         self.ann.post(self, AnnNode::Expr(expr));
521         self.end();
522     }
523
524     fn print_arm(&mut self, arm: &ast::Arm) {
525         // Note, I have no idea why this check is necessary, but here it is.
526         if arm.attrs.is_empty() {
527             self.space();
528         }
529         self.cbox(INDENT_UNIT);
530         self.ibox(0);
531         self.maybe_print_comment(arm.pat.span.lo());
532         self.print_outer_attributes(&arm.attrs);
533         self.print_pat(&arm.pat);
534         self.space();
535         if let Some(ref e) = arm.guard {
536             self.word_space("if");
537             self.print_expr(e);
538             self.space();
539         }
540         self.word_space("=>");
541
542         match arm.body.kind {
543             ast::ExprKind::Block(ref blk, opt_label) => {
544                 if let Some(label) = opt_label {
545                     self.print_ident(label.ident);
546                     self.word_space(":");
547                 }
548
549                 // The block will close the pattern's ibox.
550                 self.print_block_unclosed_indent(blk);
551
552                 // If it is a user-provided unsafe block, print a comma after it.
553                 if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
554                     self.word(",");
555                 }
556             }
557             _ => {
558                 self.end(); // Close the ibox for the pattern.
559                 self.print_expr(&arm.body);
560                 self.word(",");
561             }
562         }
563         self.end(); // Close enclosing cbox.
564     }
565
566     fn print_movability(&mut self, movability: ast::Movability) {
567         match movability {
568             ast::Movability::Static => self.word_space("static"),
569             ast::Movability::Movable => {}
570         }
571     }
572
573     fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) {
574         match capture_clause {
575             ast::CaptureBy::Value => self.word_space("move"),
576             ast::CaptureBy::Ref => {}
577         }
578     }
579 }