]> git.lizzy.rs Git - rust.git/blobdiff - src/expr.rs
Fixed comment dropped between & and type issue (#4482)
[rust.git] / src / expr.rs
index 8665f2a7248df2ac7181ab88ba0fa9a0352550f4..71446ce1ab0b1ec1d6c19e98045aea85bbdccb0c 100644 (file)
@@ -2,15 +2,15 @@
 use std::cmp::min;
 
 use itertools::Itertools;
-use syntax::parse::token::{DelimToken, LitKind};
-use syntax::source_map::{BytePos, SourceMap, Span};
-use syntax::{ast, ptr};
+use rustc_ast::token::{DelimToken, LitKind};
+use rustc_ast::{ast, ptr};
+use rustc_span::{BytePos, Span};
 
 use crate::chains::rewrite_chain;
 use crate::closures;
 use crate::comment::{
-    combine_strs_with_missing_comments, contains_comment, recover_comment_removed, rewrite_comment,
-    rewrite_missing_comment, CharClasses, FindUncommented,
+    combine_strs_with_missing_comments, comment_style, contains_comment, recover_comment_removed,
+    rewrite_comment, rewrite_missing_comment, CharClasses, FindUncommented,
 };
 use crate::config::lists::*;
 use crate::config::{Config, ControlBraceStyle, IndentStyle, Version};
@@ -106,11 +106,11 @@ pub(crate) fn format_expr(
             })
         }
         ast::ExprKind::Unary(op, ref subexpr) => rewrite_unary_op(context, op, subexpr, shape),
-        ast::ExprKind::Struct(ref path, ref fields, ref base) => rewrite_struct_lit(
+        ast::ExprKind::Struct(ref path, ref fields, ref struct_rest) => rewrite_struct_lit(
             context,
             path,
             fields,
-            base.as_ref().map(|e| &**e),
+            struct_rest,
             &expr.attrs,
             expr.span,
             shape,
@@ -124,6 +124,9 @@ pub(crate) fn format_expr(
         | ast::ExprKind::Loop(..)
         | ast::ExprKind::While(..) => to_control_flow(expr, expr_type)
             .and_then(|control_flow| control_flow.rewrite(context, shape)),
+        ast::ExprKind::ConstBlock(ref anon_const) => {
+            Some(format!("const {}", anon_const.rewrite(context, shape)?))
+        }
         ast::ExprKind::Block(ref block, opt_label) => {
             match expr_type {
                 ExprType::Statement => {
@@ -159,7 +162,7 @@ pub(crate) fn format_expr(
         ast::ExprKind::Path(ref qself, ref path) => {
             rewrite_path(context, PathContext::Expr, qself.as_ref(), path, shape)
         }
-        ast::ExprKind::Assign(ref lhs, ref rhs) => {
+        ast::ExprKind::Assign(ref lhs, ref rhs, _) => {
             rewrite_assignment(context, lhs, rhs, None, shape)
         }
         ast::ExprKind::AssignOp(ref op, ref lhs, ref rhs) => {
@@ -199,7 +202,7 @@ pub(crate) fn format_expr(
         ast::ExprKind::Try(..) | ast::ExprKind::Field(..) | ast::ExprKind::MethodCall(..) => {
             rewrite_chain(expr, context, shape)
         }
-        ast::ExprKind::Mac(ref mac) => {
+        ast::ExprKind::MacCall(ref mac) => {
             rewrite_macro(mac, None, context, shape, MacroPosition::Expression).or_else(|| {
                 wrap_str(
                     context.snippet(expr.span).to_owned(),
@@ -213,8 +216,8 @@ pub(crate) fn format_expr(
             rewrite_unary_prefix(context, "return ", &**expr, shape)
         }
         ast::ExprKind::Box(ref expr) => rewrite_unary_prefix(context, "box ", &**expr, shape),
-        ast::ExprKind::AddrOf(mutability, ref expr) => {
-            rewrite_expr_addrof(context, mutability, expr, shape)
+        ast::ExprKind::AddrOf(borrow_kind, mutability, ref expr) => {
+            rewrite_expr_addrof(context, borrow_kind, mutability, expr, shape)
         }
         ast::ExprKind::Cast(ref expr, ref ty) => rewrite_pair(
             &**expr,
@@ -252,7 +255,7 @@ pub(crate) fn format_expr(
             fn needs_space_before_range(context: &RewriteContext<'_>, lhs: &ast::Expr) -> bool {
                 match lhs.kind {
                     ast::ExprKind::Lit(ref lit) => match lit.kind {
-                        ast::LitKind::FloatUnsuffixed(..) => {
+                        ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => {
                             context.snippet(lit.span).ends_with('.')
                         }
                         _ => false,
@@ -322,7 +325,11 @@ fn needs_space_after_range(rhs: &ast::Expr) -> bool {
         }
         // We do not format these expressions yet, but they should still
         // satisfy our width restrictions.
-        ast::ExprKind::InlineAsm(..) => Some(context.snippet(expr.span).to_owned()),
+        // Style Guide RFC for InlineAsm variant pending
+        // https://github.com/rust-dev-tools/fmt-rfcs/issues/152
+        ast::ExprKind::LlvmInlineAsm(..) | ast::ExprKind::InlineAsm(..) => {
+            Some(context.snippet(expr.span).to_owned())
+        }
         ast::ExprKind::TryBlock(ref block) => {
             if let rw @ Some(_) =
                 rewrite_single_line_block(context, "try ", block, Some(&expr.attrs), None, shape)
@@ -377,6 +384,7 @@ fn needs_space_after_range(rhs: &ast::Expr) -> bool {
             }
         }
         ast::ExprKind::Await(_) => rewrite_chain(expr, context, shape),
+        ast::ExprKind::Underscore => Some("_".to_owned()),
         ast::ExprKind::Err => None,
     };
 
@@ -430,7 +438,7 @@ fn rewrite_empty_block(
         return None;
     }
 
-    if !block_contains_comment(block, context.source_map) && shape.width >= 2 {
+    if !block_contains_comment(context, block) && shape.width >= 2 {
         return Some(format!("{}{}{{}}", prefix, label_str));
     }
 
@@ -487,7 +495,7 @@ fn rewrite_single_line_block(
     label: Option<ast::Label>,
     shape: Shape,
 ) -> Option<String> {
-    if is_simple_block(block, attrs, context.source_map) {
+    if is_simple_block(context, block, attrs) {
         let expr_shape = shape.offset_left(last_line_width(prefix))?;
         let expr_str = block.stmts[0].rewrite(context, expr_shape)?;
         let label_str = rewrite_label(label);
@@ -750,8 +758,8 @@ fn rewrite_single_line(
         let fixed_cost = self.keyword.len() + "  {  } else {  }".len();
 
         if let ast::ExprKind::Block(ref else_node, _) = else_block.kind {
-            if !is_simple_block(self.block, None, context.source_map)
-                || !is_simple_block(else_node, None, context.source_map)
+            if !is_simple_block(context, self.block, None)
+                || !is_simple_block(context, else_node, None)
                 || pat_expr_str.contains('\n')
             {
                 return None;
@@ -808,7 +816,7 @@ fn rewrite_pat_expr(
         debug!("rewrite_pat_expr {:?} {:?} {:?}", shape, self.pat, expr);
 
         let cond_shape = shape.offset_left(offset)?;
-        if !self.pat.is_none() {
+        if let Some(pat) = self.pat {
             let matcher = if self.matcher.is_empty() {
                 self.matcher.to_owned()
             } else {
@@ -817,12 +825,41 @@ fn rewrite_pat_expr(
             let pat_shape = cond_shape
                 .offset_left(matcher.len())?
                 .sub_width(self.connector.len())?;
-            let pat_string = if let Some(pat) = self.pat {
-                pat.rewrite(context, pat_shape)?
+            let pat_string = pat.rewrite(context, pat_shape)?;
+            let comments_lo = context
+                .snippet_provider
+                .span_after(self.span, self.connector.trim());
+            let missing_comments = if let Some(comment) =
+                rewrite_missing_comment(mk_sp(comments_lo, expr.span.lo()), cond_shape, context)
+            {
+                if !self.connector.is_empty() && !comment.is_empty() {
+                    if comment_style(&comment, false).is_line_comment() || comment.contains("\n") {
+                        let newline = &pat_shape
+                            .indent
+                            .block_indent(context.config)
+                            .to_string_with_newline(context.config);
+                        // An extra space is added when the lhs and rhs are joined
+                        // so we need to remove one space from the end to ensure
+                        // the comment and rhs are aligned.
+                        let mut suffix = newline.as_ref().to_string();
+                        if !suffix.is_empty() {
+                            suffix.truncate(suffix.len() - 1);
+                        }
+                        format!("{}{}{}", newline, comment, suffix)
+                    } else {
+                        format!(" {}", comment)
+                    }
+                } else {
+                    comment
+                }
             } else {
                 "".to_owned()
             };
-            let result = format!("{}{}{}", matcher, pat_string, self.connector);
+
+            let result = format!(
+                "{}{}{}{}",
+                matcher, pat_string, self.connector, missing_comments
+            );
             return rewrite_assign_rhs(context, result, expr, cond_shape);
         }
 
@@ -1105,9 +1142,8 @@ fn extract_comment(span: Span, context: &RewriteContext<'_>, shape: Shape) -> Op
     }
 }
 
-pub(crate) fn block_contains_comment(block: &ast::Block, source_map: &SourceMap) -> bool {
-    let snippet = source_map.span_to_snippet(block.span).unwrap();
-    contains_comment(&snippet)
+pub(crate) fn block_contains_comment(context: &RewriteContext<'_>, block: &ast::Block) -> bool {
+    contains_comment(context.snippet(block.span))
 }
 
 // Checks that a block contains no statements, an expression and no comments or
@@ -1115,37 +1151,37 @@ pub(crate) fn block_contains_comment(block: &ast::Block, source_map: &SourceMap)
 // FIXME: incorrectly returns false when comment is contained completely within
 // the expression.
 pub(crate) fn is_simple_block(
+    context: &RewriteContext<'_>,
     block: &ast::Block,
     attrs: Option<&[ast::Attribute]>,
-    source_map: &SourceMap,
 ) -> bool {
-    (block.stmts.len() == 1
+    block.stmts.len() == 1
         && stmt_is_expr(&block.stmts[0])
-        && !block_contains_comment(block, source_map)
-        && attrs.map_or(true, |a| a.is_empty()))
+        && !block_contains_comment(context, block)
+        && attrs.map_or(true, |a| a.is_empty())
 }
 
 /// Checks whether a block contains at most one statement or expression, and no
 /// comments or attributes.
 pub(crate) fn is_simple_block_stmt(
+    context: &RewriteContext<'_>,
     block: &ast::Block,
     attrs: Option<&[ast::Attribute]>,
-    source_map: &SourceMap,
 ) -> bool {
     block.stmts.len() <= 1
-        && !block_contains_comment(block, source_map)
+        && !block_contains_comment(context, block)
         && attrs.map_or(true, |a| a.is_empty())
 }
 
 /// Checks whether a block contains no statements, expressions, comments, or
 /// inner attributes.
 pub(crate) fn is_empty_block(
+    context: &RewriteContext<'_>,
     block: &ast::Block,
     attrs: Option<&[ast::Attribute]>,
-    source_map: &SourceMap,
 ) -> bool {
     block.stmts.is_empty()
-        && !block_contains_comment(block, source_map)
+        && !block_contains_comment(context, block)
         && attrs.map_or(true, |a| inner_attributes(a).is_empty())
 }
 
@@ -1239,7 +1275,7 @@ pub(crate) fn is_simple_expr(expr: &ast::Expr) -> bool {
     match expr.kind {
         ast::ExprKind::Lit(..) => true,
         ast::ExprKind::Path(ref qself, ref path) => qself.is_none() && path.segments.len() <= 1,
-        ast::ExprKind::AddrOf(_, ref expr)
+        ast::ExprKind::AddrOf(_, _, ref expr)
         | ast::ExprKind::Box(ref expr)
         | ast::ExprKind::Cast(ref expr, _)
         | ast::ExprKind::Field(ref expr, _)
@@ -1284,9 +1320,13 @@ pub(crate) fn can_be_overflowed_expr(
             context.config.overflow_delimited_expr()
                 || (context.use_block_indent() && args_len == 1)
         }
-        ast::ExprKind::Mac(ref mac) => {
-            match (mac.delim, context.config.overflow_delimited_expr()) {
-                (ast::MacDelimiter::Bracket, true) | (ast::MacDelimiter::Brace, true) => true,
+        ast::ExprKind::MacCall(ref mac) => {
+            match (
+                rustc_ast::ast::MacDelimiter::from_token(mac.args.delim()),
+                context.config.overflow_delimited_expr(),
+            ) {
+                (Some(ast::MacDelimiter::Bracket), true)
+                | (Some(ast::MacDelimiter::Brace), true) => true,
                 _ => context.use_block_indent() && args_len == 1,
             }
         }
@@ -1297,7 +1337,7 @@ pub(crate) fn can_be_overflowed_expr(
         }
 
         // Handle unary-like expressions
-        ast::ExprKind::AddrOf(_, ref expr)
+        ast::ExprKind::AddrOf(_, _, ref expr)
         | ast::ExprKind::Box(ref expr)
         | ast::ExprKind::Try(ref expr)
         | ast::ExprKind::Unary(_, ref expr)
@@ -1308,8 +1348,8 @@ pub(crate) fn can_be_overflowed_expr(
 
 pub(crate) fn is_nested_call(expr: &ast::Expr) -> bool {
     match expr.kind {
-        ast::ExprKind::Call(..) | ast::ExprKind::Mac(..) => true,
-        ast::ExprKind::AddrOf(_, ref expr)
+        ast::ExprKind::Call(..) | ast::ExprKind::MacCall(..) => true,
+        ast::ExprKind::AddrOf(_, _, ref expr)
         | ast::ExprKind::Box(ref expr)
         | ast::ExprKind::Try(ref expr)
         | ast::ExprKind::Unary(_, ref expr)
@@ -1471,19 +1511,15 @@ fn rewrite_index(
     }
 }
 
-fn struct_lit_can_be_aligned(fields: &[ast::Field], base: Option<&ast::Expr>) -> bool {
-    if base.is_some() {
-        return false;
-    }
-
-    fields.iter().all(|field| !field.is_shorthand)
+fn struct_lit_can_be_aligned(fields: &[ast::Field], has_base: bool) -> bool {
+    !has_base && fields.iter().all(|field| !field.is_shorthand)
 }
 
 fn rewrite_struct_lit<'a>(
     context: &RewriteContext<'_>,
     path: &ast::Path,
     fields: &'a [ast::Field],
-    base: Option<&'a ast::Expr>,
+    struct_rest: &ast::StructRest,
     attrs: &[ast::Attribute],
     span: Span,
     shape: Shape,
@@ -1493,22 +1529,28 @@ fn rewrite_struct_lit<'a>(
     enum StructLitField<'a> {
         Regular(&'a ast::Field),
         Base(&'a ast::Expr),
+        Rest(&'a Span),
     }
 
     // 2 = " {".len()
     let path_shape = shape.sub_width(2)?;
     let path_str = rewrite_path(context, PathContext::Expr, None, path, path_shape)?;
 
-    if fields.is_empty() && base.is_none() {
-        return Some(format!("{} {{}}", path_str));
-    }
+    let has_base = match struct_rest {
+        ast::StructRest::None if fields.is_empty() => return Some(format!("{} {{}}", path_str)),
+        ast::StructRest::Rest(_) if fields.is_empty() => {
+            return Some(format!("{} {{ .. }}", path_str));
+        }
+        ast::StructRest::Base(_) => true,
+        _ => false,
+    };
 
     // Foo { a: Foo } - indent is +3, width is -5.
     let (h_shape, v_shape) = struct_lit_shape(shape, context, path_str.len() + 3, 2)?;
 
     let one_line_width = h_shape.map_or(0, |shape| shape.width);
     let body_lo = context.snippet_provider.span_after(span, "{");
-    let fields_str = if struct_lit_can_be_aligned(fields, base)
+    let fields_str = if struct_lit_can_be_aligned(fields, has_base)
         && context.config.struct_field_align_threshold() > 0
     {
         rewrite_with_alignment(
@@ -1519,10 +1561,14 @@ enum StructLitField<'a> {
             one_line_width,
         )?
     } else {
-        let field_iter = fields
-            .iter()
-            .map(StructLitField::Regular)
-            .chain(base.into_iter().map(StructLitField::Base));
+        let field_iter = fields.iter().map(StructLitField::Regular).chain(
+            match struct_rest {
+                ast::StructRest::Base(expr) => Some(StructLitField::Base(&**expr)),
+                ast::StructRest::Rest(span) => Some(StructLitField::Rest(span)),
+                ast::StructRest::None => None,
+            }
+            .into_iter(),
+        );
 
         let span_lo = |item: &StructLitField<'_>| match *item {
             StructLitField::Regular(field) => field.span().lo(),
@@ -1532,10 +1578,12 @@ enum StructLitField<'a> {
                 let pos = snippet.find_uncommented("..").unwrap();
                 last_field_hi + BytePos(pos as u32)
             }
+            StructLitField::Rest(span) => span.lo(),
         };
         let span_hi = |item: &StructLitField<'_>| match *item {
             StructLitField::Regular(field) => field.span().hi(),
             StructLitField::Base(expr) => expr.span.hi(),
+            StructLitField::Rest(span) => span.hi(),
         };
         let rewrite = |item: &StructLitField<'_>| match *item {
             StructLitField::Regular(field) => {
@@ -1547,6 +1595,7 @@ enum StructLitField<'a> {
                 expr.rewrite(context, v_shape.offset_left(2)?)
                     .map(|s| format!("..{}", s))
             }
+            StructLitField::Rest(_) => Some("..".to_owned()),
         };
 
         let items = itemize_list(
@@ -1573,7 +1622,7 @@ enum StructLitField<'a> {
             nested_shape,
             tactic,
             context,
-            force_no_trailing_comma || base.is_some() || !context.use_block_indent(),
+            force_no_trailing_comma || has_base || !context.use_block_indent(),
         );
 
         write_list(&item_vec, &fmt)?
@@ -1956,13 +2005,16 @@ pub(crate) fn prefer_next_line(
 
 fn rewrite_expr_addrof(
     context: &RewriteContext<'_>,
+    borrow_kind: ast::BorrowKind,
     mutability: ast::Mutability,
     expr: &ast::Expr,
     shape: Shape,
 ) -> Option<String> {
-    let operator_str = match mutability {
-        ast::Mutability::Immutable => "&",
-        ast::Mutability::Mutable => "&mut ",
+    let operator_str = match (mutability, borrow_kind) {
+        (ast::Mutability::Not, ast::BorrowKind::Ref) => "&",
+        (ast::Mutability::Not, ast::BorrowKind::Raw) => "&raw const ",
+        (ast::Mutability::Mut, ast::BorrowKind::Ref) => "&mut ",
+        (ast::Mutability::Mut, ast::BorrowKind::Raw) => "&raw mut ",
     };
     rewrite_unary_prefix(context, operator_str, expr, shape)
 }
@@ -1970,7 +2022,7 @@ fn rewrite_expr_addrof(
 pub(crate) fn is_method_call(expr: &ast::Expr) -> bool {
     match expr.kind {
         ast::ExprKind::MethodCall(..) => true,
-        ast::ExprKind::AddrOf(_, ref expr)
+        ast::ExprKind::AddrOf(_, _, ref expr)
         | ast::ExprKind::Box(ref expr)
         | ast::ExprKind::Cast(ref expr, _)
         | ast::ExprKind::Try(ref expr)