]> git.lizzy.rs Git - rust.git/blobdiff - src/types.rs
Box `ExprKind::{Closure,MethodCall}`, and `QSelf` in expressions, types, and patterns.
[rust.git] / src / types.rs
index 1c2c386932aae209de4bc32bd22ee28dc6ef7800..d5177a2057b8ab05fb3daebe466de1d87dc32710 100644 (file)
@@ -1,52 +1,48 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 use std::iter::ExactSizeIterator;
 use std::ops::Deref;
 
-use config::lists::*;
-use syntax::ast::{self, FunctionRetTy, Mutability};
-use syntax::source_map::{self, BytePos, Span};
-use syntax::symbol::keywords;
-
-use config::{IndentStyle, TypeDensity};
-use expr::{rewrite_assign_rhs, rewrite_tuple, rewrite_unary_prefix};
-use lists::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator};
-use macros::{rewrite_macro, MacroPosition};
-use overflow;
-use pairs::{rewrite_pair, PairParts};
-use rewrite::{Rewrite, RewriteContext};
-use shape::Shape;
-use source_map::SpanUtils;
-use spanned::Spanned;
-use utils::{
-    colon_spaces, extra_offset, first_line_width, format_abi, format_mutability,
+use rustc_ast::ast::{self, FnRetTy, Mutability, Term};
+use rustc_ast::ptr;
+use rustc_span::{symbol::kw, BytePos, Pos, Span};
+
+use crate::comment::{combine_strs_with_missing_comments, contains_comment};
+use crate::config::lists::*;
+use crate::config::{IndentStyle, TypeDensity, Version};
+use crate::expr::{
+    format_expr, rewrite_assign_rhs, rewrite_call, rewrite_tuple, rewrite_unary_prefix, ExprType,
+    RhsAssignKind,
+};
+use crate::lists::{
+    definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator,
+};
+use crate::macros::{rewrite_macro, MacroPosition};
+use crate::overflow;
+use crate::pairs::{rewrite_pair, PairParts};
+use crate::rewrite::{Rewrite, RewriteContext};
+use crate::shape::Shape;
+use crate::source_map::SpanUtils;
+use crate::spanned::Spanned;
+use crate::utils::{
+    colon_spaces, extra_offset, first_line_width, format_extern, format_mutability,
     last_line_extendable, last_line_width, mk_sp, rewrite_ident,
 };
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub enum PathContext {
+pub(crate) enum PathContext {
     Expr,
     Type,
     Import,
 }
 
 // Does not wrap on simple segments.
-pub fn rewrite_path(
-    context: &RewriteContext,
+pub(crate) fn rewrite_path(
+    context: &RewriteContext<'_>,
     path_context: PathContext,
-    qself: Option<&ast::QSelf>,
+    qself: &Option<ptr::P<ast::QSelf>>,
     path: &ast::Path,
     shape: Shape,
 ) -> Option<String> {
-    let skip_count = qself.map_or(0, |x| x.position);
+    let skip_count = qself.as_ref().map_or(0, |x| x.position);
 
     let mut result = if path.is_global() && qself.is_none() && path_context != PathContext::Import {
         "::".to_owned()
@@ -103,7 +99,7 @@ fn rewrite_path_segments<'a, I>(
     iter: I,
     mut span_lo: BytePos,
     span_hi: BytePos,
-    context: &RewriteContext,
+    context: &RewriteContext<'_>,
     shape: Shape,
 ) -> Option<String>
 where
@@ -114,7 +110,7 @@ fn rewrite_path_segments<'a, I>(
 
     for segment in iter {
         // Indicates a global path, shouldn't be rendered.
-        if segment.ident.name == keywords::PathRoot.name() {
+        if segment.ident.name == kw::PathRoot {
             continue;
         }
         if first {
@@ -141,17 +137,19 @@ fn rewrite_path_segments<'a, I>(
 }
 
 #[derive(Debug)]
-pub enum SegmentParam<'a> {
+pub(crate) enum SegmentParam<'a> {
+    Const(&'a ast::AnonConst),
     LifeTime(&'a ast::Lifetime),
     Type(&'a ast::Ty),
-    Binding(&'a ast::TypeBinding),
+    Binding(&'a ast::AssocConstraint),
 }
 
 impl<'a> SegmentParam<'a> {
-    fn from_generic_arg(arg: &ast::GenericArg) -> SegmentParam {
+    fn from_generic_arg(arg: &ast::GenericArg) -> SegmentParam<'_> {
         match arg {
             ast::GenericArg::Lifetime(ref lt) => SegmentParam::LifeTime(lt),
             ast::GenericArg::Type(ref ty) => SegmentParam::Type(ty),
+            ast::GenericArg::Const(const_) => SegmentParam::Const(const_),
         }
     }
 }
@@ -159,6 +157,7 @@ fn from_generic_arg(arg: &ast::GenericArg) -> SegmentParam {
 impl<'a> Spanned for SegmentParam<'a> {
     fn span(&self) -> Span {
         match *self {
+            SegmentParam::Const(const_) => const_.value.span,
             SegmentParam::LifeTime(lt) => lt.ident.span,
             SegmentParam::Type(ty) => ty.span,
             SegmentParam::Binding(binding) => binding.span,
@@ -167,24 +166,54 @@ fn span(&self) -> Span {
 }
 
 impl<'a> Rewrite for SegmentParam<'a> {
-    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
+    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
         match *self {
+            SegmentParam::Const(const_) => const_.rewrite(context, shape),
             SegmentParam::LifeTime(lt) => lt.rewrite(context, shape),
             SegmentParam::Type(ty) => ty.rewrite(context, shape),
-            SegmentParam::Binding(binding) => {
-                let mut result = match context.config.type_punctuation_density() {
-                    TypeDensity::Wide => format!("{} = ", rewrite_ident(context, binding.ident)),
-                    TypeDensity::Compressed => {
-                        format!("{}=", rewrite_ident(context, binding.ident))
-                    }
-                };
-                let budget = shape.width.checked_sub(result.len())?;
-                let rewrite = binding
-                    .ty
-                    .rewrite(context, Shape::legacy(budget, shape.indent + result.len()))?;
-                result.push_str(&rewrite);
-                Some(result)
-            }
+            SegmentParam::Binding(atc) => atc.rewrite(context, shape),
+        }
+    }
+}
+
+impl Rewrite for ast::AssocConstraint {
+    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
+        use ast::AssocConstraintKind::{Bound, Equality};
+
+        let mut result = String::with_capacity(128);
+        result.push_str(rewrite_ident(context, self.ident));
+
+        if let Some(ref gen_args) = self.gen_args {
+            let budget = shape.width.checked_sub(result.len())?;
+            let shape = Shape::legacy(budget, shape.indent + result.len());
+            let gen_str = rewrite_generic_args(gen_args, context, shape, gen_args.span())?;
+            result.push_str(&gen_str);
+        }
+
+        let infix = match (&self.kind, context.config.type_punctuation_density()) {
+            (Bound { .. }, _) => ": ",
+            (Equality { .. }, TypeDensity::Wide) => " = ",
+            (Equality { .. }, TypeDensity::Compressed) => "=",
+        };
+        result.push_str(infix);
+
+        let budget = shape.width.checked_sub(result.len())?;
+        let shape = Shape::legacy(budget, shape.indent + result.len());
+        let rewrite = self.kind.rewrite(context, shape)?;
+        result.push_str(&rewrite);
+
+        Some(result)
+    }
+}
+
+impl Rewrite for ast::AssocConstraintKind {
+    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
+        match self {
+            ast::AssocConstraintKind::Equality { term } => match term {
+                Term::Ty(ty) => ty.rewrite(context, shape),
+                Term::Const(c) => c.rewrite(context, shape),
+            },
+            ast::AssocConstraintKind::Bound { bounds } => bounds.rewrite(context, shape),
         }
     }
 }
@@ -204,7 +233,7 @@ fn rewrite_segment(
     segment: &ast::PathSegment,
     span_lo: &mut BytePos,
     span_hi: BytePos,
-    context: &RewriteContext,
+    context: &RewriteContext<'_>,
     shape: Shape,
 ) -> Option<String> {
     let mut result = String::with_capacity(128);
@@ -218,19 +247,17 @@ fn rewrite_segment(
     };
 
     if let Some(ref args) = segment.args {
+        let generics_str = rewrite_generic_args(args, context, shape, mk_sp(*span_lo, span_hi))?;
         match **args {
-            ast::GenericArgs::AngleBracketed(ref data)
-                if !data.args.is_empty() || !data.bindings.is_empty() =>
-            {
-                let param_list = data
-                    .args
-                    .iter()
-                    .map(SegmentParam::from_generic_arg)
-                    .chain(data.bindings.iter().map(|x| SegmentParam::Binding(&*x)))
-                    .collect::<Vec<_>>();
-
-                let force_separator =
-                    context.inside_macro() && context.snippet(data.span).starts_with("::");
+            ast::GenericArgs::AngleBracketed(ref data) if !data.args.is_empty() => {
+                // HACK: squeeze out the span between the identifier and the parameters.
+                // The hack is required so that we don't remove the separator inside macro calls.
+                // This does not work in the presence of comment, hoping that people are
+                // sane about where to put their comment.
+                let separator_snippet = context
+                    .snippet(mk_sp(segment.ident.span.hi(), data.span.lo()))
+                    .trim();
+                let force_separator = context.inside_macro() && separator_snippet.starts_with("::");
                 let separator = if path_context == PathContext::Expr || force_separator {
                     "::"
                 } else {
@@ -238,37 +265,14 @@ fn rewrite_segment(
                 };
                 result.push_str(separator);
 
-                let generics_str = overflow::rewrite_with_angle_brackets(
-                    context,
-                    "",
-                    param_list.iter(),
-                    shape,
-                    mk_sp(*span_lo, span_hi),
-                )?;
-
                 // Update position of last bracket.
                 *span_lo = context
                     .snippet_provider
                     .span_after(mk_sp(*span_lo, span_hi), "<");
-
-                result.push_str(&generics_str)
-            }
-            ast::GenericArgs::Parenthesized(ref data) => {
-                let output = match data.output {
-                    Some(ref ty) => FunctionRetTy::Ty(ty.clone()),
-                    None => FunctionRetTy::Default(source_map::DUMMY_SP),
-                };
-                result.push_str(&format_function_type(
-                    data.inputs.iter().map(|x| &**x),
-                    &output,
-                    false,
-                    data.span,
-                    context,
-                    shape,
-                )?);
             }
             _ => (),
         }
+        result.push_str(&generics_str)
     }
 
     Some(result)
@@ -276,10 +280,10 @@ fn rewrite_segment(
 
 fn format_function_type<'a, I>(
     inputs: I,
-    output: &FunctionRetTy,
+    output: &FnRetTy,
     variadic: bool,
     span: Span,
-    context: &RewriteContext,
+    context: &RewriteContext<'_>,
     shape: Shape,
 ) -> Option<String>
 where
@@ -295,29 +299,11 @@ fn format_function_type<'a, I>(
         IndentStyle::Visual => shape.block_left(4)?,
     };
     let output = match *output {
-        FunctionRetTy::Ty(ref ty) => {
+        FnRetTy::Ty(ref ty) => {
             let type_str = ty.rewrite(context, ty_shape)?;
             format!(" -> {}", type_str)
         }
-        FunctionRetTy::Default(..) => String::new(),
-    };
-
-    // Code for handling variadics is somewhat duplicated for items, but they
-    // are different enough to need some serious refactoring to share code.
-    enum ArgumentKind<T>
-    where
-        T: Deref,
-        <T as Deref>::Target: Rewrite + Spanned,
-    {
-        Regular(T),
-        Variadic(BytePos),
-    }
-
-    let variadic_arg = if variadic {
-        let variadic_start = context.snippet_provider.span_before(span, "...");
-        Some(ArgumentKind::Variadic(variadic_start))
-    } else {
-        None
+        FnRetTy::Default(..) => String::new(),
     };
 
     let list_shape = if context.use_block_indent() {
@@ -332,57 +318,61 @@ enum ArgumentKind<T>
         let offset = shape.indent + 1;
         Shape::legacy(budget, offset)
     };
+
+    let is_inputs_empty = inputs.len() == 0;
     let list_lo = context.snippet_provider.span_after(span, "(");
-    let items = itemize_list(
-        context.snippet_provider,
-        inputs.map(ArgumentKind::Regular).chain(variadic_arg),
-        ")",
-        ",",
-        |arg| match *arg {
-            ArgumentKind::Regular(ref ty) => ty.span().lo(),
-            ArgumentKind::Variadic(start) => start,
-        },
-        |arg| match *arg {
-            ArgumentKind::Regular(ref ty) => ty.span().hi(),
-            ArgumentKind::Variadic(start) => start + BytePos(3),
-        },
-        |arg| match *arg {
-            ArgumentKind::Regular(ref ty) => ty.rewrite(context, list_shape),
-            ArgumentKind::Variadic(_) => Some("...".to_owned()),
-        },
-        list_lo,
-        span.hi(),
-        false,
-    );
+    let (list_str, tactic) = if is_inputs_empty {
+        let tactic = get_tactics(&[], &output, shape);
+        let list_hi = context.snippet_provider.span_before(span, ")");
+        let comment = context
+            .snippet_provider
+            .span_to_snippet(mk_sp(list_lo, list_hi))?
+            .trim();
+        let comment = if comment.starts_with("//") {
+            format!(
+                "{}{}{}",
+                &list_shape.indent.to_string_with_newline(context.config),
+                comment,
+                &shape.block().indent.to_string_with_newline(context.config)
+            )
+        } else {
+            comment.to_string()
+        };
+        (comment, tactic)
+    } else {
+        let items = itemize_list(
+            context.snippet_provider,
+            inputs,
+            ")",
+            ",",
+            |arg| arg.span().lo(),
+            |arg| arg.span().hi(),
+            |arg| arg.rewrite(context, list_shape),
+            list_lo,
+            span.hi(),
+            false,
+        );
 
-    let item_vec: Vec<_> = items.collect();
+        let item_vec: Vec<_> = items.collect();
+        let tactic = get_tactics(&item_vec, &output, shape);
+        let trailing_separator = if !context.use_block_indent() || variadic {
+            SeparatorTactic::Never
+        } else {
+            context.config.trailing_comma()
+        };
 
-    // If the return type is multi-lined, then force to use multiple lines for
-    // arguments as well.
-    let tactic = if output.contains('\n') {
-        DefinitiveListTactic::Vertical
-    } else {
-        definitive_tactic(
-            &*item_vec,
-            ListTactic::HorizontalVertical,
-            Separator::Comma,
-            shape.width.saturating_sub(2 + output.len()),
-        )
-    };
-    let trailing_separator = if !context.use_block_indent() || variadic {
-        SeparatorTactic::Never
-    } else {
-        context.config.trailing_comma()
+        let fmt = ListFormatting::new(list_shape, context.config)
+            .tactic(tactic)
+            .trailing_separator(trailing_separator)
+            .ends_with_newline(tactic.ends_with_newline(context.config.indent_style()))
+            .preserve_newline(true);
+        (write_list(&item_vec, &fmt)?, tactic)
     };
 
-    let fmt = ListFormatting::new(list_shape, context.config)
-        .tactic(tactic)
-        .trailing_separator(trailing_separator)
-        .ends_with_newline(tactic.ends_with_newline(context.config.indent_style()))
-        .preserve_newline(true);
-    let list_str = write_list(&item_vec, &fmt)?;
-
-    let args = if tactic == DefinitiveListTactic::Horizontal || !context.use_block_indent() {
+    let args = if tactic == DefinitiveListTactic::Horizontal
+        || !context.use_block_indent()
+        || is_inputs_empty
+    {
         format!("({})", list_str)
     } else {
         format!(
@@ -399,20 +389,33 @@ enum ArgumentKind<T>
             "{}\n{}{}",
             args,
             list_shape.indent.to_string(context.config),
-            output.trim_left()
+            output.trim_start()
         ))
     }
 }
 
-fn type_bound_colon(context: &RewriteContext) -> &'static str {
-    colon_spaces(
-        context.config.space_before_colon(),
-        context.config.space_after_colon(),
-    )
+fn type_bound_colon(context: &RewriteContext<'_>) -> &'static str {
+    colon_spaces(context.config)
+}
+
+// If the return type is multi-lined, then force to use multiple lines for
+// arguments as well.
+fn get_tactics(item_vec: &[ListItem], output: &str, shape: Shape) -> DefinitiveListTactic {
+    if output.contains('\n') {
+        DefinitiveListTactic::Vertical
+    } else {
+        definitive_tactic(
+            item_vec,
+            ListTactic::HorizontalVertical,
+            Separator::Comma,
+            // 2 is for the case of ',\n'
+            shape.width.saturating_sub(2 + output.len()),
+        )
+    }
 }
 
 impl Rewrite for ast::WherePredicate {
-    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
+    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
         // FIXME: dead spans?
         let result = match *self {
             ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
@@ -422,7 +425,7 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
                 ..
             }) => {
                 let type_str = bounded_ty.rewrite(context, shape)?;
-                let colon = type_bound_colon(context).trim_right();
+                let colon = type_bound_colon(context).trim_end();
                 let lhs = if let Some(lifetime_str) =
                     rewrite_lifetime_param(context, shape, bound_generic_params)
                 {
@@ -431,7 +434,7 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
                     format!("{}{}", type_str, colon)
                 };
 
-                rewrite_assign_rhs(context, lhs, bounds, shape)?
+                rewrite_assign_rhs(context, lhs, bounds, &RhsAssignKind::Bounds, shape)?
             }
             ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
                 ref lifetime,
@@ -444,7 +447,7 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
                 ..
             }) => {
                 let lhs_ty_str = lhs_ty.rewrite(context, shape).map(|lhs| lhs + " =")?;
-                rewrite_assign_rhs(context, lhs_ty_str, &**rhs_ty, shape)?
+                rewrite_assign_rhs(context, lhs_ty_str, &**rhs_ty, &RhsAssignKind::Ty, shape)?
             }
         };
 
@@ -453,18 +456,54 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
 }
 
 impl Rewrite for ast::GenericArg {
-    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
+    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
         match *self {
             ast::GenericArg::Lifetime(ref lt) => lt.rewrite(context, shape),
             ast::GenericArg::Type(ref ty) => ty.rewrite(context, shape),
+            ast::GenericArg::Const(ref const_) => const_.rewrite(context, shape),
+        }
+    }
+}
+
+fn rewrite_generic_args(
+    gen_args: &ast::GenericArgs,
+    context: &RewriteContext<'_>,
+    shape: Shape,
+    span: Span,
+) -> Option<String> {
+    match gen_args {
+        ast::GenericArgs::AngleBracketed(ref data) if !data.args.is_empty() => {
+            let args = data
+                .args
+                .iter()
+                .map(|x| match x {
+                    ast::AngleBracketedArg::Arg(generic_arg) => {
+                        SegmentParam::from_generic_arg(generic_arg)
+                    }
+                    ast::AngleBracketedArg::Constraint(constraint) => {
+                        SegmentParam::Binding(constraint)
+                    }
+                })
+                .collect::<Vec<_>>();
+
+            overflow::rewrite_with_angle_brackets(context, "", args.iter(), shape, span)
         }
+        ast::GenericArgs::Parenthesized(ref data) => format_function_type(
+            data.inputs.iter().map(|x| &**x),
+            &data.output,
+            false,
+            data.span,
+            context,
+            shape,
+        ),
+        _ => Some("".to_owned()),
     }
 }
 
 fn rewrite_bounded_lifetime(
     lt: &ast::Lifetime,
     bounds: &[ast::GenericBound],
-    context: &RewriteContext,
+    context: &RewriteContext<'_>,
     shape: Shape,
 ) -> Option<String> {
     let result = lt.rewrite(context, shape)?;
@@ -484,14 +523,20 @@ fn rewrite_bounded_lifetime(
     }
 }
 
+impl Rewrite for ast::AnonConst {
+    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
+        format_expr(&self.value, ExprType::SubExpression, context, shape)
+    }
+}
+
 impl Rewrite for ast::Lifetime {
-    fn rewrite(&self, context: &RewriteContext, _: Shape) -> Option<String> {
+    fn rewrite(&self, context: &RewriteContext<'_>, _: Shape) -> Option<String> {
         Some(rewrite_ident(context, self.ident).to_owned())
     }
 }
 
 impl Rewrite for ast::GenericBound {
-    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
+    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
         match *self {
             ast::GenericBound::Trait(ref poly_trait_ref, trait_bound_modifier) => {
                 let snippet = context.snippet(self.span());
@@ -501,6 +546,12 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
                     ast::TraitBoundModifier::Maybe => poly_trait_ref
                         .rewrite(context, shape.offset_left(1)?)
                         .map(|s| format!("?{}", s)),
+                    ast::TraitBoundModifier::MaybeConst => poly_trait_ref
+                        .rewrite(context, shape.offset_left(7)?)
+                        .map(|s| format!("~const {}", s)),
+                    ast::TraitBoundModifier::MaybeConstMaybe => poly_trait_ref
+                        .rewrite(context, shape.offset_left(8)?)
+                        .map(|s| format!("~const ?{}", s)),
                 };
                 rewrite.map(|s| if has_paren { format!("({})", s) } else { s })
             }
@@ -510,7 +561,7 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
 }
 
 impl Rewrite for ast::GenericBounds {
-    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
+    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
         if self.is_empty() {
             return Some(String::new());
         }
@@ -520,14 +571,47 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
 }
 
 impl Rewrite for ast::GenericParam {
-    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
+    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
         let mut result = String::with_capacity(128);
         // FIXME: If there are more than one attributes, this will force multiline.
         match self.attrs.rewrite(context, shape) {
-            Some(ref rw) if !rw.is_empty() => result.push_str(&format!("{} ", rw)),
+            Some(ref rw) if !rw.is_empty() => {
+                result.push_str(rw);
+                // When rewriting generic params, an extra newline should be put
+                // if the attributes end with a doc comment
+                if let Some(true) = self.attrs.last().map(|a| a.is_doc_comment()) {
+                    result.push_str(&shape.indent.to_string_with_newline(context.config));
+                } else {
+                    result.push(' ');
+                }
+            }
             _ => (),
         }
-        result.push_str(rewrite_ident(context, self.ident));
+
+        if let ast::GenericParamKind::Const {
+            ref ty,
+            kw_span: _,
+            default,
+        } = &self.kind
+        {
+            result.push_str("const ");
+            result.push_str(rewrite_ident(context, self.ident));
+            result.push_str(": ");
+            result.push_str(&ty.rewrite(context, shape)?);
+            if let Some(default) = default {
+                let eq_str = match context.config.type_punctuation_density() {
+                    TypeDensity::Compressed => "=",
+                    TypeDensity::Wide => " = ",
+                };
+                result.push_str(eq_str);
+                let budget = shape.width.checked_sub(result.len())?;
+                let rewrite = default.rewrite(context, Shape::legacy(budget, shape.indent))?;
+                result.push_str(&rewrite);
+            }
+        } else {
+            result.push_str(rewrite_ident(context, self.ident));
+        }
+
         if !self.bounds.is_empty() {
             result.push_str(type_bound_colon(context));
             result.push_str(&self.bounds.rewrite(context, shape)?)
@@ -552,7 +636,7 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
 }
 
 impl Rewrite for ast::PolyTraitRef {
-    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
+    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
         if let Some(lifetime_str) =
             rewrite_lifetime_param(context, shape, &self.bound_generic_params)
         {
@@ -570,20 +654,26 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
 }
 
 impl Rewrite for ast::TraitRef {
-    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
-        rewrite_path(context, PathContext::Type, None, &self.path, shape)
+    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
+        rewrite_path(context, PathContext::Type, &None, &self.path, shape)
     }
 }
 
 impl Rewrite for ast::Ty {
-    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
-        match self.node {
+    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
+        match self.kind {
             ast::TyKind::TraitObject(ref bounds, tobj_syntax) => {
                 // we have to consider 'dyn' keyword is used or not!!!
                 let is_dyn = tobj_syntax == ast::TraitObjectSyntax::Dyn;
                 // 4 is length of 'dyn '
                 let shape = if is_dyn { shape.offset_left(4)? } else { shape };
-                let res = bounds.rewrite(context, shape)?;
+                let mut res = bounds.rewrite(context, shape)?;
+                // We may have falsely removed a trailing `+` inside macro call.
+                if context.inside_macro() && bounds.len() == 1 {
+                    if context.snippet(self.span).ends_with('+') && !res.ends_with('+') {
+                        res.push('+');
+                    }
+                }
                 if is_dyn {
                     Some(format!("dyn {}", res))
                 } else {
@@ -592,8 +682,8 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
             }
             ast::TyKind::Ptr(ref mt) => {
                 let prefix = match mt.mutbl {
-                    Mutability::Mutable => "*mut ",
-                    Mutability::Immutable => "*const ",
+                    Mutability::Mut => "*mut ",
+                    Mutability::Not => "*const ",
                 };
 
                 rewrite_unary_prefix(context, prefix, &*mt.ty, shape)
@@ -601,44 +691,105 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
             ast::TyKind::Rptr(ref lifetime, ref mt) => {
                 let mut_str = format_mutability(mt.mutbl);
                 let mut_len = mut_str.len();
-                Some(match *lifetime {
-                    Some(ref lifetime) => {
-                        let lt_budget = shape.width.checked_sub(2 + mut_len)?;
-                        let lt_str = lifetime.rewrite(
+                let mut result = String::with_capacity(128);
+                result.push('&');
+                let ref_hi = context.snippet_provider.span_after(self.span(), "&");
+                let mut cmnt_lo = ref_hi;
+
+                if let Some(ref lifetime) = *lifetime {
+                    let lt_budget = shape.width.checked_sub(2 + mut_len)?;
+                    let lt_str = lifetime.rewrite(
+                        context,
+                        Shape::legacy(lt_budget, shape.indent + 2 + mut_len),
+                    )?;
+                    let before_lt_span = mk_sp(cmnt_lo, lifetime.ident.span.lo());
+                    if contains_comment(context.snippet(before_lt_span)) {
+                        result = combine_strs_with_missing_comments(
                             context,
-                            Shape::legacy(lt_budget, shape.indent + 2 + mut_len),
+                            &result,
+                            &lt_str,
+                            before_lt_span,
+                            shape,
+                            true,
                         )?;
-                        let lt_len = lt_str.len();
-                        let budget = shape.width.checked_sub(2 + mut_len + lt_len)?;
-                        format!(
-                            "&{} {}{}",
-                            lt_str,
-                            mut_str,
-                            mt.ty.rewrite(
-                                context,
-                                Shape::legacy(budget, shape.indent + 2 + mut_len + lt_len)
-                            )?
-                        )
+                    } else {
+                        result.push_str(&lt_str);
                     }
-                    None => {
-                        let budget = shape.width.checked_sub(1 + mut_len)?;
-                        format!(
-                            "&{}{}",
+                    result.push(' ');
+                    cmnt_lo = lifetime.ident.span.hi();
+                }
+
+                if ast::Mutability::Mut == mt.mutbl {
+                    let mut_hi = context.snippet_provider.span_after(self.span(), "mut");
+                    let before_mut_span = mk_sp(cmnt_lo, mut_hi - BytePos::from_usize(3));
+                    if contains_comment(context.snippet(before_mut_span)) {
+                        result = combine_strs_with_missing_comments(
+                            context,
+                            result.trim_end(),
                             mut_str,
-                            mt.ty.rewrite(
-                                context,
-                                Shape::legacy(budget, shape.indent + 1 + mut_len)
-                            )?
-                        )
+                            before_mut_span,
+                            shape,
+                            true,
+                        )?;
+                    } else {
+                        result.push_str(mut_str);
                     }
-                })
+                    cmnt_lo = mut_hi;
+                }
+
+                let before_ty_span = mk_sp(cmnt_lo, mt.ty.span.lo());
+                if contains_comment(context.snippet(before_ty_span)) {
+                    result = combine_strs_with_missing_comments(
+                        context,
+                        result.trim_end(),
+                        &mt.ty.rewrite(context, shape)?,
+                        before_ty_span,
+                        shape,
+                        true,
+                    )?;
+                } else {
+                    let used_width = last_line_width(&result);
+                    let budget = shape.width.checked_sub(used_width)?;
+                    let ty_str = mt
+                        .ty
+                        .rewrite(context, Shape::legacy(budget, shape.indent + used_width))?;
+                    result.push_str(&ty_str);
+                }
+
+                Some(result)
             }
             // FIXME: we drop any comments here, even though it's a silly place to put
             // comments.
             ast::TyKind::Paren(ref ty) => {
-                let budget = shape.width.checked_sub(2)?;
-                ty.rewrite(context, Shape::legacy(budget, shape.indent + 1))
-                    .map(|ty_str| format!("({})", ty_str))
+                if context.config.version() == Version::One
+                    || context.config.indent_style() == IndentStyle::Visual
+                {
+                    let budget = shape.width.checked_sub(2)?;
+                    return ty
+                        .rewrite(context, Shape::legacy(budget, shape.indent + 1))
+                        .map(|ty_str| format!("({})", ty_str));
+                }
+
+                // 2 = ()
+                if let Some(sh) = shape.sub_width(2) {
+                    if let Some(ref s) = ty.rewrite(context, sh) {
+                        if !s.contains('\n') {
+                            return Some(format!("({})", s));
+                        }
+                    }
+                }
+
+                let indent_str = shape.indent.to_string_with_newline(context.config);
+                let shape = shape
+                    .block_indent(context.config.tab_spaces())
+                    .with_max_width(context.config);
+                let rw = ty.rewrite(context, shape)?;
+                Some(format!(
+                    "({}{}{})",
+                    shape.to_string_with_newline(context.config),
+                    rw,
+                    indent_str
+                ))
             }
             ast::TyKind::Slice(ref ty) => {
                 let budget = shape.width.checked_sub(4)?;
@@ -649,7 +800,7 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
                 rewrite_tuple(context, items.iter(), self.span, shape, items.len() == 1)
             }
             ast::TyKind::Path(ref q_self, ref path) => {
-                rewrite_path(context, PathContext::Type, q_self.as_ref(), path, shape)
+                rewrite_path(context, PathContext::Type, q_self, path, shape)
             }
             ast::TyKind::Array(ref ty, ref repeats) => rewrite_pair(
                 &**ty,
@@ -668,14 +819,34 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
             }
             ast::TyKind::BareFn(ref bare_fn) => rewrite_bare_fn(bare_fn, self.span, context, shape),
             ast::TyKind::Never => Some(String::from("!")),
-            ast::TyKind::Mac(ref mac) => {
+            ast::TyKind::MacCall(ref mac) => {
                 rewrite_macro(mac, None, context, shape, MacroPosition::Expression)
             }
             ast::TyKind::ImplicitSelf => Some(String::from("")),
-            ast::TyKind::ImplTrait(_, ref it) => it
-                .rewrite(context, shape)
-                .map(|it_str| format!("impl {}", it_str)),
-            ast::TyKind::Err | ast::TyKind::Typeof(..) => unreachable!(),
+            ast::TyKind::ImplTrait(_, ref it) => {
+                // Empty trait is not a parser error.
+                if it.is_empty() {
+                    return Some("impl".to_owned());
+                }
+                let rw = if context.config.version() == Version::One {
+                    it.rewrite(context, shape)
+                } else {
+                    join_bounds(context, shape, it, false)
+                };
+                rw.map(|it_str| {
+                    let space = if it_str.is_empty() { "" } else { " " };
+                    format!("impl{}{}", space, it_str)
+                })
+            }
+            ast::TyKind::CVarArgs => Some("...".to_owned()),
+            ast::TyKind::Err => Some(context.snippet(self.span).to_owned()),
+            ast::TyKind::Typeof(ref anon_const) => rewrite_call(
+                context,
+                "typeof",
+                &[anon_const.value.clone()],
+                self.span,
+                shape,
+            ),
         }
     }
 }
@@ -683,7 +854,7 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
 fn rewrite_bare_fn(
     bare_fn: &ast::BareFnTy,
     span: Span,
-    context: &RewriteContext,
+    context: &RewriteContext<'_>,
     shape: Shape,
 ) -> Option<String> {
     debug!("rewrite_bare_fn {:#?}", shape);
@@ -700,10 +871,10 @@ fn rewrite_bare_fn(
         result.push_str("> ");
     }
 
-    result.push_str(::utils::format_unsafety(bare_fn.unsafety));
+    result.push_str(crate::utils::format_unsafety(bare_fn.unsafety));
 
-    result.push_str(&format_abi(
-        bare_fn.abi,
+    result.push_str(&format_extern(
+        bare_fn.ext,
         context.config.force_explicit_abi(),
         false,
     ));
@@ -719,7 +890,7 @@ fn rewrite_bare_fn(
     let rewrite = format_function_type(
         bare_fn.decl.inputs.iter(),
         &bare_fn.decl.output,
-        bare_fn.decl.variadic,
+        bare_fn.decl.c_variadic(),
         span,
         context,
         func_ty_shape,
@@ -747,64 +918,146 @@ fn is_generic_bounds_in_order(generic_bounds: &[ast::GenericBound]) -> bool {
 }
 
 fn join_bounds(
-    context: &RewriteContext,
+    context: &RewriteContext<'_>,
     shape: Shape,
     items: &[ast::GenericBound],
     need_indent: bool,
 ) -> Option<String> {
-    debug_assert!(!items.is_empty());
-
-    // Try to join types in a single line
-    let joiner = match context.config.type_punctuation_density() {
-        TypeDensity::Compressed => "+",
-        TypeDensity::Wide => " + ",
-    };
-    let type_strs = items
-        .iter()
-        .map(|item| item.rewrite(context, shape))
-        .collect::<Option<Vec<_>>>()?;
-    let result = type_strs.join(joiner);
-    if items.len() <= 1 || (!result.contains('\n') && result.len() <= shape.width) {
-        return Some(result);
-    }
+    join_bounds_inner(context, shape, items, need_indent, false)
+}
 
-    // We need to use multiple lines.
-    let (type_strs, offset) = if need_indent {
-        // Rewrite with additional indentation.
-        let nested_shape = shape.block_indent(context.config.tab_spaces());
-        let type_strs = items
-            .iter()
-            .map(|item| item.rewrite(context, nested_shape))
-            .collect::<Option<Vec<_>>>()?;
-        (type_strs, nested_shape.indent)
-    } else {
-        (type_strs, shape.indent)
-    };
+fn join_bounds_inner(
+    context: &RewriteContext<'_>,
+    shape: Shape,
+    items: &[ast::GenericBound],
+    need_indent: bool,
+    force_newline: bool,
+) -> Option<String> {
+    debug_assert!(!items.is_empty());
 
+    let generic_bounds_in_order = is_generic_bounds_in_order(items);
     let is_bound_extendable = |s: &str, b: &ast::GenericBound| match b {
         ast::GenericBound::Outlives(..) => true,
         ast::GenericBound::Trait(..) => last_line_extendable(s),
     };
-    let mut result = String::with_capacity(128);
-    result.push_str(&type_strs[0]);
-    let mut can_be_put_on_the_same_line = is_bound_extendable(&result, &items[0]);
-    let generic_bounds_in_order = is_generic_bounds_in_order(items);
-    for (bound, bound_str) in items[1..].iter().zip(type_strs[1..].iter()) {
-        if generic_bounds_in_order && can_be_put_on_the_same_line {
-            result.push_str(joiner);
-        } else {
-            result.push_str(&offset.to_string_with_newline(context.config));
-            result.push_str("+ ");
-        }
-        result.push_str(bound_str);
-        can_be_put_on_the_same_line = is_bound_extendable(bound_str, bound);
+
+    let result = items.iter().enumerate().try_fold(
+        (String::new(), None, false),
+        |(strs, prev_trailing_span, prev_extendable), (i, item)| {
+            let trailing_span = if i < items.len() - 1 {
+                let hi = context
+                    .snippet_provider
+                    .span_before(mk_sp(items[i + 1].span().lo(), item.span().hi()), "+");
+
+                Some(mk_sp(item.span().hi(), hi))
+            } else {
+                None
+            };
+            let (leading_span, has_leading_comment) = if i > 0 {
+                let lo = context
+                    .snippet_provider
+                    .span_after(mk_sp(items[i - 1].span().hi(), item.span().lo()), "+");
+
+                let span = mk_sp(lo, item.span().lo());
+
+                let has_comments = contains_comment(context.snippet(span));
+
+                (Some(mk_sp(lo, item.span().lo())), has_comments)
+            } else {
+                (None, false)
+            };
+            let prev_has_trailing_comment = match prev_trailing_span {
+                Some(ts) => contains_comment(context.snippet(ts)),
+                _ => false,
+            };
+
+            let shape = if need_indent && force_newline {
+                shape
+                    .block_indent(context.config.tab_spaces())
+                    .with_max_width(context.config)
+            } else {
+                shape
+            };
+            let whitespace = if force_newline && (!prev_extendable || !generic_bounds_in_order) {
+                shape
+                    .indent
+                    .to_string_with_newline(context.config)
+                    .to_string()
+            } else {
+                String::from(" ")
+            };
+
+            let joiner = match context.config.type_punctuation_density() {
+                TypeDensity::Compressed => String::from("+"),
+                TypeDensity::Wide => whitespace + "+ ",
+            };
+            let joiner = if has_leading_comment {
+                joiner.trim_end()
+            } else {
+                &joiner
+            };
+            let joiner = if prev_has_trailing_comment {
+                joiner.trim_start()
+            } else {
+                joiner
+            };
+
+            let (extendable, trailing_str) = if i == 0 {
+                let bound_str = item.rewrite(context, shape)?;
+                (is_bound_extendable(&bound_str, item), bound_str)
+            } else {
+                let bound_str = &item.rewrite(context, shape)?;
+                match leading_span {
+                    Some(ls) if has_leading_comment => (
+                        is_bound_extendable(bound_str, item),
+                        combine_strs_with_missing_comments(
+                            context, joiner, bound_str, ls, shape, true,
+                        )?,
+                    ),
+                    _ => (
+                        is_bound_extendable(bound_str, item),
+                        String::from(joiner) + bound_str,
+                    ),
+                }
+            };
+            match prev_trailing_span {
+                Some(ts) if prev_has_trailing_comment => combine_strs_with_missing_comments(
+                    context,
+                    &strs,
+                    &trailing_str,
+                    ts,
+                    shape,
+                    true,
+                )
+                .map(|v| (v, trailing_span, extendable)),
+                _ => Some((strs + &trailing_str, trailing_span, extendable)),
+            }
+        },
+    )?;
+
+    if !force_newline
+        && items.len() > 1
+        && (result.0.contains('\n') || result.0.len() > shape.width)
+    {
+        join_bounds_inner(context, shape, items, need_indent, true)
+    } else {
+        Some(result.0)
     }
+}
 
-    Some(result)
+pub(crate) fn opaque_ty(ty: &Option<ptr::P<ast::Ty>>) -> Option<&ast::GenericBounds> {
+    ty.as_ref().and_then(|t| match &t.kind {
+        ast::TyKind::ImplTrait(_, bounds) => Some(bounds),
+        _ => None,
+    })
 }
 
-pub fn can_be_overflowed_type(context: &RewriteContext, ty: &ast::Ty, len: usize) -> bool {
-    match ty.node {
+pub(crate) fn can_be_overflowed_type(
+    context: &RewriteContext<'_>,
+    ty: &ast::Ty,
+    len: usize,
+) -> bool {
+    match ty.kind {
         ast::TyKind::Tup(..) => context.use_block_indent() && len == 1,
         ast::TyKind::Rptr(_, ref mutty) | ast::TyKind::Ptr(ref mutty) => {
             can_be_overflowed_type(context, &*mutty.ty, len)
@@ -814,17 +1067,14 @@ pub fn can_be_overflowed_type(context: &RewriteContext, ty: &ast::Ty, len: usize
 }
 
 /// Returns `None` if there is no `LifetimeDef` in the given generic parameters.
-fn rewrite_lifetime_param(
-    context: &RewriteContext,
+pub(crate) fn rewrite_lifetime_param(
+    context: &RewriteContext<'_>,
     shape: Shape,
     generic_params: &[ast::GenericParam],
 ) -> Option<String> {
     let result = generic_params
         .iter()
-        .filter(|p| match p.kind {
-            ast::GenericParamKind::Lifetime => true,
-            _ => false,
-        })
+        .filter(|p| matches!(p.kind, ast::GenericParamKind::Lifetime))
         .map(|lt| lt.rewrite(context, shape))
         .collect::<Option<Vec<_>>>()?
         .join(", ");