]> git.lizzy.rs Git - rust.git/blobdiff - src/expr.rs
Format the last expression-statement as expression (#3631)
[rust.git] / src / expr.rs
index afd9465c73c90233b2dc18bd408a008e7aa298f1..d7640bf98caf451340819bcb43fa0d6cf5a34db4 100644 (file)
@@ -1,5 +1,6 @@
 use std::borrow::Cow;
 use std::cmp::min;
+use std::iter;
 
 use itertools::Itertools;
 use syntax::parse::token::DelimToken;
@@ -32,7 +33,7 @@
 use crate::utils::{
     colon_spaces, contains_skip, count_newlines, first_line_ends_with, inner_attributes,
     last_line_extendable, last_line_width, mk_sp, outer_attributes, ptr_vec_to_ref_vec,
-    semicolon_for_expr, semicolon_for_stmt, wrap_str,
+    semicolon_for_expr, unicode_str_width, wrap_str,
 };
 use crate::vertical::rewrite_with_alignment;
 use crate::visitor::FmtVisitor;
@@ -102,6 +103,7 @@ pub(crate) fn format_expr(
             path,
             fields,
             base.as_ref().map(|e| &**e),
+            &expr.attrs,
             expr.span,
             shape,
         ),
@@ -182,9 +184,9 @@ pub(crate) fn format_expr(
                 Some("yield".to_string())
             }
         }
-        ast::ExprKind::Closure(capture, asyncness, movability, ref fn_decl, ref body, _) => {
+        ast::ExprKind::Closure(capture, ref is_async, movability, ref fn_decl, ref body, _) => {
             closures::rewrite_closure(
-                capture, asyncness, movability, fn_decl, body, expr.span, context, shape,
+                capture, is_async, movability, fn_decl, body, expr.span, context, shape,
             )
         }
         ast::ExprKind::Try(..) | ast::ExprKind::Field(..) | ast::ExprKind::MethodCall(..) => {
@@ -334,10 +336,6 @@ fn needs_space_after_range(rhs: &ast::Expr) -> bool {
                 ))
             }
         }
-        ast::ExprKind::ObsoleteInPlace(ref lhs, ref rhs) => lhs
-            .rewrite(context, shape)
-            .map(|s| s + " <-")
-            .and_then(|lhs| rewrite_assign_rhs(context, lhs, &**rhs, shape)),
         ast::ExprKind::Async(capture_by, _node_id, ref block) => {
             let mover = if capture_by == ast::CaptureBy::Value {
                 "move "
@@ -370,6 +368,18 @@ fn needs_space_after_range(rhs: &ast::Expr) -> bool {
                 ))
             }
         }
+        ast::ExprKind::Await(ast::AwaitOrigin::FieldLike, _) => rewrite_chain(expr, context, shape),
+        ast::ExprKind::Await(ast::AwaitOrigin::MacroLike, ref nested) => {
+            overflow::rewrite_with_parens(
+                context,
+                "await!",
+                iter::once(nested),
+                shape,
+                expr.span,
+                context.config.max_width(),
+                None,
+            )
+        }
         ast::ExprKind::Err => None,
     };
 
@@ -558,28 +568,6 @@ fn rewrite_block(
     result
 }
 
-impl Rewrite for ast::Stmt {
-    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
-        skip_out_of_file_lines_range!(context, self.span());
-
-        let result = match self.node {
-            ast::StmtKind::Local(ref local) => local.rewrite(context, shape),
-            ast::StmtKind::Expr(ref ex) | ast::StmtKind::Semi(ref ex) => {
-                let suffix = if semicolon_for_stmt(context, self) {
-                    ";"
-                } else {
-                    ""
-                };
-
-                let shape = shape.sub_width(suffix.len())?;
-                format_expr(ex, ExprType::Statement, context, shape).map(|s| s + suffix)
-            }
-            ast::StmtKind::Mac(..) | ast::StmtKind::Item(..) => None,
-        };
-        result.and_then(|res| recover_comment_removed(res, self.span(), context))
-    }
-}
-
 // Rewrite condition if the given expression has one.
 pub(crate) fn rewrite_cond(
     context: &RewriteContext<'_>,
@@ -1179,16 +1167,6 @@ pub(crate) fn stmt_is_expr(stmt: &ast::Stmt) -> bool {
     }
 }
 
-pub(crate) fn stmt_is_if(stmt: &ast::Stmt) -> bool {
-    match stmt.node {
-        ast::StmtKind::Expr(ref e) => match e.node {
-            ast::ExprKind::If(..) => true,
-            _ => false,
-        },
-        _ => false,
-    }
-}
-
 pub(crate) fn is_unsafe_block(block: &ast::Block) -> bool {
     if let ast::BlockCheckMode::Unsafe(..) = block.rules {
         true
@@ -1570,6 +1548,7 @@ fn rewrite_struct_lit<'a>(
     path: &ast::Path,
     fields: &'a [ast::Field],
     base: Option<&'a ast::Expr>,
+    attrs: &[ast::Attribute],
     span: Span,
     shape: Shape,
 ) -> Option<String> {
@@ -1664,7 +1643,8 @@ enum StructLitField<'a> {
         write_list(&item_vec, &fmt)?
     };
 
-    let fields_str = wrap_struct_field(context, &fields_str, shape, v_shape, one_line_width);
+    let fields_str =
+        wrap_struct_field(context, &attrs, &fields_str, shape, v_shape, one_line_width)?;
     Some(format!("{} {{{}}}", path_str, fields_str))
 
     // FIXME if context.config.indent_style() == Visual, but we run out
@@ -1673,25 +1653,39 @@ enum StructLitField<'a> {
 
 pub(crate) fn wrap_struct_field(
     context: &RewriteContext<'_>,
+    attrs: &[ast::Attribute],
     fields_str: &str,
     shape: Shape,
     nested_shape: Shape,
     one_line_width: usize,
-) -> String {
-    if context.config.indent_style() == IndentStyle::Block
+) -> Option<String> {
+    let should_vertical = context.config.indent_style() == IndentStyle::Block
         && (fields_str.contains('\n')
             || !context.config.struct_lit_single_line()
-            || fields_str.len() > one_line_width)
-    {
-        format!(
-            "{}{}{}",
+            || fields_str.len() > one_line_width);
+
+    let inner_attrs = &inner_attributes(attrs);
+    if inner_attrs.is_empty() {
+        if should_vertical {
+            Some(format!(
+                "{}{}{}",
+                nested_shape.indent.to_string_with_newline(context.config),
+                fields_str,
+                shape.indent.to_string_with_newline(context.config)
+            ))
+        } else {
+            // One liner or visual indent.
+            Some(format!(" {} ", fields_str))
+        }
+    } else {
+        Some(format!(
+            "{}{}{}{}{}",
+            nested_shape.indent.to_string_with_newline(context.config),
+            inner_attrs.rewrite(context, shape)?,
             nested_shape.indent.to_string_with_newline(context.config),
             fields_str,
             shape.indent.to_string_with_newline(context.config)
-        )
-    } else {
-        // One liner or visual indent.
-        format!(" {} ", fields_str)
+        ))
     }
 }
 
@@ -1947,7 +1941,9 @@ fn choose_rhs<R: Rewrite>(
     rhs_tactics: RhsTactics,
 ) -> Option<String> {
     match orig_rhs {
-        Some(ref new_str) if !new_str.contains('\n') && new_str.len() <= shape.width => {
+        Some(ref new_str)
+            if !new_str.contains('\n') && unicode_str_width(new_str) <= shape.width =>
+        {
             Some(format!(" {}", new_str))
         }
         _ => {
@@ -2000,6 +1996,15 @@ fn shape_from_rhs_tactic(
     }
 }
 
+/// Returns true if formatting next_line_rhs is better on a new line when compared to the
+/// original's line formatting.
+///
+/// It is considered better if:
+/// 1. the tactic is ForceNextLineWithoutIndent
+/// 2. next_line_rhs doesn't have newlines
+/// 3. the original line has more newlines than next_line_rhs
+/// 4. the original formatting of the first line ends with `(`, `{`, or `[` and next_line_rhs
+///    doesn't
 pub(crate) fn prefer_next_line(
     orig_rhs: &str,
     next_line_rhs: &str,