about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authording-young <lsyhime@snu.ac.kr>2024-07-22 14:55:54 +0900
committerYacin Tmimi <yacintmimi@gmail.com>2024-08-25 09:23:04 -0400
commit6f5e99b7b5a00a1bed4d29f323fce0c989cf28aa (patch)
treed646e8e7b0f51c8d5cd3941527c7a9e10eb1e28a /src
parent448906160d70a84f9c248d3b92ca96a134511c99 (diff)
downloadrust-6f5e99b7b5a00a1bed4d29f323fce0c989cf28aa.tar.gz
rust-6f5e99b7b5a00a1bed4d29f323fce0c989cf28aa.zip
update macro rewrite functions to return RewriteResult
Diffstat (limited to 'src')
-rw-r--r--src/expr.rs17
-rw-r--r--src/items.rs2
-rw-r--r--src/macros.rs252
-rw-r--r--src/patterns.rs2
-rw-r--r--src/rewrite.rs28
-rw-r--r--src/types.rs2
-rw-r--r--src/visitor.rs5
7 files changed, 198 insertions, 110 deletions
diff --git a/src/expr.rs b/src/expr.rs
index 138689bc132..02372e7be13 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -243,13 +243,16 @@ pub(crate) fn format_expr(
         | ast::ExprKind::MethodCall(..)
         | ast::ExprKind::Await(_, _) => rewrite_chain(expr, context, shape).ok(),
         ast::ExprKind::MacCall(ref mac) => {
-            rewrite_macro(mac, None, context, shape, MacroPosition::Expression).or_else(|| {
-                wrap_str(
-                    context.snippet(expr.span).to_owned(),
-                    context.config.max_width(),
-                    shape,
-                )
-            })
+            rewrite_macro(mac, None, context, shape, MacroPosition::Expression)
+                .or_else(|_| {
+                    wrap_str(
+                        context.snippet(expr.span).to_owned(),
+                        context.config.max_width(),
+                        shape,
+                    )
+                    .max_width_error(shape.width, expr.span)
+                })
+                .ok()
         }
         ast::ExprKind::Ret(None) => Some("return".to_owned()),
         ast::ExprKind::Ret(Some(ref expr)) => {
diff --git a/src/items.rs b/src/items.rs
index 35591df0fd8..3894ee2cdf8 100644
--- a/src/items.rs
+++ b/src/items.rs
@@ -3427,7 +3427,7 @@ impl Rewrite for ast::ForeignItem {
                 rewrite_type_alias(ty_alias, context, shape.indent, kind, span)
             }
             ast::ForeignItemKind::MacCall(ref mac) => {
-                rewrite_macro(mac, None, context, shape, MacroPosition::Item)
+                rewrite_macro(mac, None, context, shape, MacroPosition::Item).ok()
             }
         }?;
 
diff --git a/src/macros.rs b/src/macros.rs
index c520971f40c..51ded869229 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -31,7 +31,9 @@ use crate::lists::{itemize_list, write_list, ListFormatting};
 use crate::overflow;
 use crate::parse::macros::lazy_static::parse_lazy_static;
 use crate::parse::macros::{parse_expr, parse_macro_args, ParsedMacroArgs};
-use crate::rewrite::{Rewrite, RewriteContext, RewriteError};
+use crate::rewrite::{
+    MacroErrorKind, Rewrite, RewriteContext, RewriteError, RewriteErrorExt, RewriteResult,
+};
 use crate::shape::{Indent, Shape};
 use crate::source_map::SpanUtils;
 use crate::spanned::Spanned;
@@ -71,22 +73,30 @@ impl MacroArg {
 
 impl Rewrite for ast::Item {
     fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
+        self.rewrite_result(context, shape).ok()
+    }
+
+    fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
         let mut visitor = crate::visitor::FmtVisitor::from_context(context);
         visitor.block_indent = shape.indent;
         visitor.last_pos = self.span().lo();
         visitor.visit_item(self);
-        Some(visitor.buffer.to_owned())
+        Ok(visitor.buffer.to_owned())
     }
 }
 
 impl Rewrite for MacroArg {
     fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
+        self.rewrite_result(context, shape).ok()
+    }
+
+    fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
         match *self {
-            MacroArg::Expr(ref expr) => expr.rewrite(context, shape),
-            MacroArg::Ty(ref ty) => ty.rewrite(context, shape),
-            MacroArg::Pat(ref pat) => pat.rewrite(context, shape),
-            MacroArg::Item(ref item) => item.rewrite(context, shape),
-            MacroArg::Keyword(ident, _) => Some(ident.name.to_string()),
+            MacroArg::Expr(ref expr) => expr.rewrite_result(context, shape),
+            MacroArg::Ty(ref ty) => ty.rewrite_result(context, shape),
+            MacroArg::Pat(ref pat) => pat.rewrite_result(context, shape),
+            MacroArg::Item(ref item) => item.rewrite_result(context, shape),
+            MacroArg::Keyword(ident, _) => Ok(ident.name.to_string()),
         }
     }
 }
@@ -110,12 +120,14 @@ fn rewrite_macro_name(
 }
 
 // Use this on failing to format the macro call.
+// TODO(ding-young) We should also report macro parse failure to tell users why given snippet
+// is left unformatted. One possible improvement is appending formatting error to context.report
 fn return_macro_parse_failure_fallback(
     context: &RewriteContext<'_>,
     indent: Indent,
     position: MacroPosition,
     span: Span,
-) -> Option<String> {
+) -> RewriteResult {
     // Mark this as a failure however we format it
     context.macro_rewrite_failure.replace(true);
 
@@ -133,7 +145,8 @@ fn return_macro_parse_failure_fallback(
         })
         .unwrap_or(false);
     if is_like_block_indent_style {
-        return trim_left_preserve_layout(context.snippet(span), indent, context.config);
+        return trim_left_preserve_layout(context.snippet(span), indent, context.config)
+            .macro_error(MacroErrorKind::Unknown, span);
     }
 
     context.skipped_range.borrow_mut().push((
@@ -146,7 +159,7 @@ fn return_macro_parse_failure_fallback(
     if position == MacroPosition::Item {
         snippet.push(';');
     }
-    Some(snippet)
+    Ok(snippet)
 }
 
 pub(crate) fn rewrite_macro(
@@ -155,13 +168,13 @@ pub(crate) fn rewrite_macro(
     context: &RewriteContext<'_>,
     shape: Shape,
     position: MacroPosition,
-) -> Option<String> {
+) -> RewriteResult {
     let should_skip = context
         .skip_context
         .macros
         .skip(context.snippet(mac.path.span));
     if should_skip {
-        None
+        Err(RewriteError::SkipFormatting)
     } else {
         let guard = context.enter_macro();
         let result = catch_unwind(AssertUnwindSafe(|| {
@@ -175,9 +188,16 @@ pub(crate) fn rewrite_macro(
             )
         }));
         match result {
-            Err(..) | Ok(None) => {
+            Err(..) => {
                 context.macro_rewrite_failure.replace(true);
-                None
+                Err(RewriteError::MacroFailure {
+                    kind: MacroErrorKind::Unknown,
+                    span: mac.span(),
+                })
+            }
+            Ok(Err(e)) => {
+                context.macro_rewrite_failure.replace(true);
+                Err(e)
             }
             Ok(rw) => rw,
         }
@@ -191,11 +211,11 @@ fn rewrite_macro_inner(
     shape: Shape,
     position: MacroPosition,
     is_nested_macro: bool,
-) -> Option<String> {
+) -> RewriteResult {
     if context.config.use_try_shorthand() {
         if let Some(expr) = convert_try_mac(mac, context) {
             context.leave_macro();
-            return expr.rewrite(context, shape);
+            return expr.rewrite_result(context, shape);
         }
     }
 
@@ -215,21 +235,27 @@ fn rewrite_macro_inner(
     if ts.is_empty() && !has_comment {
         return match style {
             Delimiter::Parenthesis if position == MacroPosition::Item => {
-                Some(format!("{macro_name}();"))
-            }
-            Delimiter::Bracket if position == MacroPosition::Item => {
-                Some(format!("{macro_name}[];"))
+                Ok(format!("{macro_name}();"))
             }
-            Delimiter::Parenthesis => Some(format!("{macro_name}()")),
-            Delimiter::Bracket => Some(format!("{macro_name}[]")),
-            Delimiter::Brace => Some(format!("{macro_name} {{}}")),
+            Delimiter::Bracket if position == MacroPosition::Item => Ok(format!("{macro_name}[];")),
+            Delimiter::Parenthesis => Ok(format!("{macro_name}()")),
+            Delimiter::Bracket => Ok(format!("{macro_name}[]")),
+            Delimiter::Brace => Ok(format!("{macro_name} {{}}")),
             _ => unreachable!(),
         };
     }
     // Format well-known macros which cannot be parsed as a valid AST.
     if macro_name == "lazy_static!" && !has_comment {
-        if let success @ Some(..) = format_lazy_static(context, shape, ts.clone()) {
-            return success;
+        match format_lazy_static(context, shape, ts.clone(), mac.span()) {
+            Ok(rw) => return Ok(rw),
+            Err(err) => match err {
+                // We will move on to parsing macro args just like other macros
+                // if we could not parse lazy_static! with known syntax
+                RewriteError::MacroFailure { kind, span: _ }
+                    if kind == MacroErrorKind::ParseFailure => {}
+                // If formatting fails even though parsing succeeds, return the err early
+                _ => return Err(err),
+            },
         }
     }
 
@@ -266,7 +292,7 @@ fn rewrite_macro_inner(
         Delimiter::Parenthesis => {
             // Handle special case: `vec!(expr; expr)`
             if vec_with_semi {
-                handle_vec_semi(context, shape, arg_vec, macro_name, style)
+                handle_vec_semi(context, shape, arg_vec, macro_name, style, mac.span())
             } else {
                 // Format macro invocation as function call, preserve the trailing
                 // comma because not all macros support them.
@@ -283,7 +309,6 @@ fn rewrite_macro_inner(
                         Some(SeparatorTactic::Never)
                     },
                 )
-                .ok()
                 .map(|rw| match position {
                     MacroPosition::Item => format!("{};", rw),
                     _ => rw,
@@ -293,7 +318,7 @@ fn rewrite_macro_inner(
         Delimiter::Bracket => {
             // Handle special case: `vec![expr; expr]`
             if vec_with_semi {
-                handle_vec_semi(context, shape, arg_vec, macro_name, style)
+                handle_vec_semi(context, shape, arg_vec, macro_name, style, mac.span())
             } else {
                 // If we are rewriting `vec!` macro or other special macros,
                 // then we can rewrite this as a usual array literal.
@@ -317,14 +342,13 @@ fn rewrite_macro_inner(
                     shape,
                     force_trailing_comma,
                     Some(original_style),
-                )
-                .ok()?;
+                )?;
                 let comma = match position {
                     MacroPosition::Item => ";",
                     _ => "",
                 };
 
-                Some(format!("{rewrite}{comma}"))
+                Ok(format!("{rewrite}{comma}"))
             }
         }
         Delimiter::Brace => {
@@ -333,8 +357,8 @@ fn rewrite_macro_inner(
             // anything in between the braces (for now).
             let snippet = context.snippet(mac.span()).trim_start_matches(|c| c != '{');
             match trim_left_preserve_layout(snippet, shape.indent, context.config) {
-                Some(macro_body) => Some(format!("{macro_name} {macro_body}")),
-                None => Some(format!("{macro_name} {snippet}")),
+                Some(macro_body) => Ok(format!("{macro_name} {macro_body}")),
+                None => Ok(format!("{macro_name} {snippet}")),
             }
         }
         _ => unreachable!(),
@@ -347,28 +371,32 @@ fn handle_vec_semi(
     arg_vec: Vec<MacroArg>,
     macro_name: String,
     delim_token: Delimiter,
-) -> Option<String> {
+    span: Span,
+) -> RewriteResult {
     let (left, right) = match delim_token {
         Delimiter::Parenthesis => ("(", ")"),
         Delimiter::Bracket => ("[", "]"),
         _ => unreachable!(),
     };
 
-    let mac_shape = shape.offset_left(macro_name.len())?;
+    // Should we return MaxWidthError, Or Macro failure
+    let mac_shape = shape
+        .offset_left(macro_name.len())
+        .max_width_error(shape.width, span)?;
     // 8 = `vec![]` + `; ` or `vec!()` + `; `
     let total_overhead = 8;
     let nested_shape = mac_shape.block_indent(context.config.tab_spaces());
-    let lhs = arg_vec[0].rewrite(context, nested_shape)?;
-    let rhs = arg_vec[1].rewrite(context, nested_shape)?;
+    let lhs = arg_vec[0].rewrite_result(context, nested_shape)?;
+    let rhs = arg_vec[1].rewrite_result(context, nested_shape)?;
     if !lhs.contains('\n')
         && !rhs.contains('\n')
         && lhs.len() + rhs.len() + total_overhead <= shape.width
     {
         // macro_name(lhs; rhs) or macro_name[lhs; rhs]
-        Some(format!("{macro_name}{left}{lhs}; {rhs}{right}"))
+        Ok(format!("{macro_name}{left}{lhs}; {rhs}{right}"))
     } else {
         // macro_name(\nlhs;\nrhs\n) or macro_name[\nlhs;\nrhs\n]
-        Some(format!(
+        Ok(format!(
             "{}{}{}{};{}{}{}{}",
             macro_name,
             left,
@@ -386,7 +414,7 @@ fn rewrite_empty_macro_def_body(
     context: &RewriteContext<'_>,
     span: Span,
     shape: Shape,
-) -> Option<String> {
+) -> RewriteResult {
     // Create an empty, dummy `ast::Block` representing an empty macro body
     let block = ast::Block {
         stmts: vec![].into(),
@@ -396,7 +424,7 @@ fn rewrite_empty_macro_def_body(
         tokens: None,
         could_be_bare_literal: false,
     };
-    block.rewrite(context, shape)
+    block.rewrite_result(context, shape)
 }
 
 pub(crate) fn rewrite_macro_def(
@@ -407,8 +435,8 @@ pub(crate) fn rewrite_macro_def(
     ident: symbol::Ident,
     vis: &ast::Visibility,
     span: Span,
-) -> Option<String> {
-    let snippet = Some(remove_trailing_white_spaces(context.snippet(span)));
+) -> RewriteResult {
+    let snippet = Ok(remove_trailing_white_spaces(context.snippet(span)));
     if snippet.as_ref().map_or(true, |s| s.ends_with(';')) {
         return snippet;
     }
@@ -443,7 +471,7 @@ pub(crate) fn rewrite_macro_def(
         let lo = context.snippet_provider.span_before(span, "{");
         result += " ";
         result += &rewrite_empty_macro_def_body(context, span.with_lo(lo), shape)?;
-        return Some(result);
+        return Ok(result);
     }
 
     let branch_items = itemize_list(
@@ -454,13 +482,14 @@ pub(crate) fn rewrite_macro_def(
         |branch| branch.span.lo(),
         |branch| branch.span.hi(),
         |branch| match branch.rewrite(context, arm_shape, multi_branch_style) {
-            Some(v) => Ok(v),
+            Ok(v) => Ok(v),
             // if the rewrite returned None because a macro could not be rewritten, then return the
             // original body
-            None if context.macro_rewrite_failure.get() => {
+            // TODO(ding-young) report rewrite error even if we return Ok with original snippet
+            Err(_) if context.macro_rewrite_failure.get() => {
                 Ok(context.snippet(branch.body).trim().to_string())
             }
-            None => Err(RewriteError::Unknown),
+            Err(e) => Err(e),
         },
         context.snippet_provider.span_after(span, "{"),
         span.hi(),
@@ -488,7 +517,7 @@ pub(crate) fn rewrite_macro_def(
         result += "}";
     }
 
-    Some(result)
+    Ok(result)
 }
 
 fn register_metavariable(
@@ -640,12 +669,13 @@ impl MacroArgKind {
         context: &RewriteContext<'_>,
         shape: Shape,
         use_multiple_lines: bool,
-    ) -> Option<String> {
-        let rewrite_delimited_inner = |delim_tok, args| -> Option<(String, String, String)> {
+    ) -> RewriteResult {
+        type DelimitedArgsRewrite = Result<(String, String, String), RewriteError>;
+        let rewrite_delimited_inner = |delim_tok, args| -> DelimitedArgsRewrite {
             let inner = wrap_macro_args(context, args, shape)?;
             let (lhs, rhs) = delim_token_to_str(context, delim_tok, shape, false, inner.is_empty());
             if lhs.len() + inner.len() + rhs.len() <= shape.width {
-                return Some((lhs, inner, rhs));
+                return Ok((lhs, inner, rhs));
             }
 
             let (lhs, rhs) = delim_token_to_str(context, delim_tok, shape, true, false);
@@ -653,27 +683,27 @@ impl MacroArgKind {
                 .block_indent(context.config.tab_spaces())
                 .with_max_width(context.config);
             let inner = wrap_macro_args(context, args, nested_shape)?;
-            Some((lhs, inner, rhs))
+            Ok((lhs, inner, rhs))
         };
 
         match *self {
-            MacroArgKind::MetaVariable(ty, ref name) => Some(format!("${name}:{ty}")),
+            MacroArgKind::MetaVariable(ty, ref name) => Ok(format!("${name}:{ty}")),
             MacroArgKind::Repeat(delim_tok, ref args, ref another, ref tok) => {
                 let (lhs, inner, rhs) = rewrite_delimited_inner(delim_tok, args)?;
                 let another = another
                     .as_ref()
-                    .and_then(|a| a.rewrite(context, shape, use_multiple_lines))
+                    .and_then(|a| a.rewrite(context, shape, use_multiple_lines).ok())
                     .unwrap_or_else(|| "".to_owned());
                 let repeat_tok = pprust::token_to_string(tok);
 
-                Some(format!("${lhs}{inner}{rhs}{another}{repeat_tok}"))
+                Ok(format!("${lhs}{inner}{rhs}{another}{repeat_tok}"))
             }
             MacroArgKind::Delimited(delim_tok, ref args) => {
                 rewrite_delimited_inner(delim_tok, args)
                     .map(|(lhs, inner, rhs)| format!("{}{}{}", lhs, inner, rhs))
             }
-            MacroArgKind::Separator(ref sep, ref prefix) => Some(format!("{prefix}{sep} ")),
-            MacroArgKind::Other(ref inner, ref prefix) => Some(format!("{prefix}{inner}")),
+            MacroArgKind::Separator(ref sep, ref prefix) => Ok(format!("{prefix}{sep} ")),
+            MacroArgKind::Other(ref inner, ref prefix) => Ok(format!("{prefix}{inner}")),
         }
     }
 }
@@ -689,7 +719,7 @@ impl ParsedMacroArg {
         context: &RewriteContext<'_>,
         shape: Shape,
         use_multiple_lines: bool,
-    ) -> Option<String> {
+    ) -> RewriteResult {
         self.kind.rewrite(context, shape, use_multiple_lines)
     }
 }
@@ -967,9 +997,9 @@ fn wrap_macro_args(
     context: &RewriteContext<'_>,
     args: &[ParsedMacroArg],
     shape: Shape,
-) -> Option<String> {
+) -> RewriteResult {
     wrap_macro_args_inner(context, args, shape, false)
-        .or_else(|| wrap_macro_args_inner(context, args, shape, true))
+        .or_else(|_| wrap_macro_args_inner(context, args, shape, true))
 }
 
 fn wrap_macro_args_inner(
@@ -977,7 +1007,7 @@ fn wrap_macro_args_inner(
     args: &[ParsedMacroArg],
     shape: Shape,
     use_multiple_lines: bool,
-) -> Option<String> {
+) -> RewriteResult {
     let mut result = String::with_capacity(128);
     let mut iter = args.iter().peekable();
     let indent_str = shape.indent.to_string_with_newline(context.config);
@@ -1003,9 +1033,9 @@ fn wrap_macro_args_inner(
     }
 
     if !use_multiple_lines && result.len() >= shape.width {
-        None
+        Err(RewriteError::Unknown)
     } else {
-        Some(result)
+        Ok(result)
     }
 }
 
@@ -1013,22 +1043,21 @@ fn wrap_macro_args_inner(
 // for some common cases. I hope the basic logic is sufficient. Note that the
 // meaning of some tokens is a bit different here from usual Rust, e.g., `*`
 // and `(`/`)` have special meaning.
-//
-// We always try and format on one line.
-// FIXME: Use multi-line when every thing does not fit on one line.
 fn format_macro_args(
     context: &RewriteContext<'_>,
     token_stream: TokenStream,
     shape: Shape,
-) -> Option<String> {
+) -> RewriteResult {
+    let span = span_for_token_stream(&token_stream);
     if !context.config.format_macro_matchers() {
-        let span = span_for_token_stream(&token_stream);
-        return Some(match span {
+        return Ok(match span {
             Some(span) => context.snippet(span).to_owned(),
             None => String::new(),
         });
     }
-    let parsed_args = MacroArgParser::new().parse(token_stream)?;
+    let parsed_args = MacroArgParser::new()
+        .parse(token_stream)
+        .macro_error(MacroErrorKind::ParseFailure, span.unwrap())?;
     wrap_macro_args(context, &parsed_args, shape)
 }
 
@@ -1241,11 +1270,14 @@ impl MacroBranch {
         context: &RewriteContext<'_>,
         shape: Shape,
         multi_branch_style: bool,
-    ) -> Option<String> {
+    ) -> RewriteResult {
         // Only attempt to format function-like macros.
         if self.args_paren_kind != Delimiter::Parenthesis {
             // FIXME(#1539): implement for non-sugared macros.
-            return None;
+            return Err(RewriteError::MacroFailure {
+                kind: MacroErrorKind::Unknown,
+                span: self.span,
+            });
         }
 
         let old_body = context.snippet(self.body).trim();
@@ -1256,8 +1288,13 @@ impl MacroBranch {
                 prefix_width = 6; // 6 = " => {{"
             }
         }
-        let mut result =
-            format_macro_args(context, self.args.clone(), shape.sub_width(prefix_width)?)?;
+        let mut result = format_macro_args(
+            context,
+            self.args.clone(),
+            shape
+                .sub_width(prefix_width)
+                .max_width_error(shape.width, self.span)?,
+        )?;
 
         if multi_branch_style {
             result += " =>";
@@ -1266,7 +1303,7 @@ impl MacroBranch {
         if !context.config.format_macro_bodies() {
             result += " ";
             result += context.snippet(self.whole_body);
-            return Some(result);
+            return Ok(result);
         }
 
         // The macro body is the most interesting part. It might end up as various
@@ -1275,7 +1312,8 @@ impl MacroBranch {
         // `$$`). We'll try and format like an AST node, but we'll substitute
         // variables for new names with the same length first.
 
-        let (body_str, substs) = replace_names(old_body)?;
+        let (body_str, substs) =
+            replace_names(old_body).macro_error(MacroErrorKind::ReplaceMacroVariable, self.span)?;
 
         let mut config = context.config.clone();
         config.set().show_parse_errors(false);
@@ -1298,13 +1336,21 @@ impl MacroBranch {
                 config.set().max_width(new_width);
                 match crate::format_code_block(&body_str, &config, true) {
                     Some(new_body) => new_body,
-                    None => return None,
+                    None => {
+                        return Err(RewriteError::MacroFailure {
+                            kind: MacroErrorKind::Unknown,
+                            span: self.span,
+                        });
+                    }
                 }
             }
         };
 
         if !filtered_str_fits(&new_body_snippet.snippet, config.max_width(), shape) {
-            return None;
+            return Err(RewriteError::ExceedsMaxWidth {
+                configured_width: shape.width,
+                span: self.span,
+            });
         }
 
         // Indent the body since it is in a block.
@@ -1330,7 +1376,10 @@ impl MacroBranch {
         for (old, new) in &substs {
             if old_body.contains(new) {
                 debug!("rewrite_macro_def: bailing matching variable: `{}`", new);
-                return None;
+                return Err(RewriteError::MacroFailure {
+                    kind: MacroErrorKind::ReplaceMacroVariable,
+                    span: self.span,
+                });
             }
             new_body = new_body.replace(new, old);
         }
@@ -1345,7 +1394,7 @@ impl MacroBranch {
 
         result += "}";
 
-        Some(result)
+        Ok(result)
     }
 }
 
@@ -1365,7 +1414,8 @@ fn format_lazy_static(
     context: &RewriteContext<'_>,
     shape: Shape,
     ts: TokenStream,
-) -> Option<String> {
+    span: Span,
+) -> RewriteResult {
     let mut result = String::with_capacity(1024);
     let nested_shape = shape
         .block_indent(context.config.tab_spaces())
@@ -1374,7 +1424,8 @@ fn format_lazy_static(
     result.push_str("lazy_static! {");
     result.push_str(&nested_shape.indent.to_string_with_newline(context.config));
 
-    let parsed_elems = parse_lazy_static(context, ts)?;
+    let parsed_elems =
+        parse_lazy_static(context, ts).macro_error(MacroErrorKind::ParseFailure, span)?;
     let last = parsed_elems.len() - 1;
     for (i, (vis, id, ty, expr)) in parsed_elems.iter().enumerate() {
         // Rewrite as a static item.
@@ -1384,15 +1435,20 @@ fn format_lazy_static(
             "{}static ref {}: {} =",
             vis,
             id,
-            ty.rewrite(context, nested_shape)?
+            ty.rewrite_result(context, nested_shape)?
         ));
-        result.push_str(&rewrite_assign_rhs(
-            context,
-            stmt,
-            &*expr,
-            &RhsAssignKind::Expr(&expr.kind, expr.span),
-            nested_shape.sub_width(1)?,
-        )?);
+        result.push_str(
+            &rewrite_assign_rhs(
+                context,
+                stmt,
+                &*expr,
+                &RhsAssignKind::Expr(&expr.kind, expr.span),
+                nested_shape
+                    .sub_width(1)
+                    .max_width_error(nested_shape.width, expr.span)?,
+            )
+            .unknown_error()?,
+        );
         result.push(';');
         if i != last {
             result.push_str(&nested_shape.indent.to_string_with_newline(context.config));
@@ -1402,7 +1458,7 @@ fn format_lazy_static(
     result.push_str(&shape.indent.to_string_with_newline(context.config));
     result.push('}');
 
-    Some(result)
+    Ok(result)
 }
 
 fn rewrite_macro_with_items(
@@ -1414,12 +1470,12 @@ fn rewrite_macro_with_items(
     original_style: Delimiter,
     position: MacroPosition,
     span: Span,
-) -> Option<String> {
+) -> RewriteResult {
     let style_to_delims = |style| match style {
-        Delimiter::Parenthesis => Some(("(", ")")),
-        Delimiter::Bracket => Some(("[", "]")),
-        Delimiter::Brace => Some((" {", "}")),
-        _ => None,
+        Delimiter::Parenthesis => Ok(("(", ")")),
+        Delimiter::Bracket => Ok(("[", "]")),
+        Delimiter::Brace => Ok((" {", "}")),
+        _ => Err(RewriteError::Unknown),
     };
 
     let (opener, closer) = style_to_delims(style)?;
@@ -1441,7 +1497,7 @@ fn rewrite_macro_with_items(
     for item in items {
         let item = match item {
             MacroArg::Item(item) => item,
-            _ => return None,
+            _ => return Err(RewriteError::Unknown),
         };
         visitor.visit_item(item);
     }
@@ -1454,5 +1510,5 @@ fn rewrite_macro_with_items(
     result.push_str(&shape.indent.to_string_with_newline(context.config));
     result.push_str(closer);
     result.push_str(trailing_semicolon);
-    Some(result)
+    Ok(result)
 }
diff --git a/src/patterns.rs b/src/patterns.rs
index 3ae0fbf161f..9a4f6528ce8 100644
--- a/src/patterns.rs
+++ b/src/patterns.rs
@@ -327,7 +327,7 @@ impl Rewrite for Pat {
                 shape,
             ),
             PatKind::MacCall(ref mac) => {
-                rewrite_macro(mac, None, context, shape, MacroPosition::Pat).unknown_error()
+                rewrite_macro(mac, None, context, shape, MacroPosition::Pat)
             }
             PatKind::Paren(ref pat) => pat
                 .rewrite_result(
diff --git a/src/rewrite.rs b/src/rewrite.rs
index 6644e4b27a8..8cefda1657f 100644
--- a/src/rewrite.rs
+++ b/src/rewrite.rs
@@ -30,6 +30,23 @@ impl<T: Rewrite> Rewrite for ptr::P<T> {
     }
 }
 
+#[derive(Clone, Debug, PartialEq)]
+pub(crate) enum MacroErrorKind {
+    ParseFailure,
+    ReplaceMacroVariable,
+    Unknown,
+}
+
+impl std::fmt::Display for MacroErrorKind {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            MacroErrorKind::ParseFailure => write!(f, "(parse failure)"),
+            MacroErrorKind::ReplaceMacroVariable => write!(f, "(replacing macro variables with $)"),
+            MacroErrorKind::Unknown => write!(f, ""),
+        }
+    }
+}
+
 #[derive(Clone, Error, Debug)]
 pub(crate) enum RewriteError {
     #[error("Formatting was skipped due to skip attribute or out of file range.")]
@@ -38,6 +55,9 @@ pub(crate) enum RewriteError {
     #[error("It exceeds the required width of {configured_width} for the span: {span:?}")]
     ExceedsMaxWidth { configured_width: usize, span: Span },
 
+    #[error("Failed to format given macro{} at: {span:?}", kind)]
+    MacroFailure { kind: MacroErrorKind, span: Span },
+
     /// Format failure that does not fit to above categories.
     #[error("An unknown error occurred during formatting.")]
     Unknown,
@@ -46,6 +66,7 @@ pub(crate) enum RewriteError {
 /// Extension trait used to conveniently convert to RewriteError
 pub(crate) trait RewriteErrorExt<T> {
     fn max_width_error(self, width: usize, span: Span) -> Result<T, RewriteError>;
+    fn macro_error(self, kind: MacroErrorKind, span: Span) -> Result<T, RewriteError>;
     fn unknown_error(self) -> Result<T, RewriteError>;
 }
 
@@ -57,6 +78,13 @@ impl<T> RewriteErrorExt<T> for Option<T> {
         })
     }
 
+    fn macro_error(self, kind: MacroErrorKind, span: Span) -> Result<T, RewriteError> {
+        self.ok_or_else(|| RewriteError::MacroFailure {
+            kind: kind,
+            span: span,
+        })
+    }
+
     fn unknown_error(self) -> Result<T, RewriteError> {
         self.ok_or_else(|| RewriteError::Unknown)
     }
diff --git a/src/types.rs b/src/types.rs
index f9dafe7d625..76eb0ea0529 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -958,7 +958,7 @@ impl Rewrite for ast::Ty {
             ast::TyKind::BareFn(ref bare_fn) => rewrite_bare_fn(bare_fn, self.span, context, shape),
             ast::TyKind::Never => Ok(String::from("!")),
             ast::TyKind::MacCall(ref mac) => {
-                rewrite_macro(mac, None, context, shape, MacroPosition::Expression).unknown_error()
+                rewrite_macro(mac, None, context, shape, MacroPosition::Expression)
             }
             ast::TyKind::ImplicitSelf => Ok(String::from("")),
             ast::TyKind::ImplTrait(_, ref it) => {
diff --git a/src/visitor.rs b/src/visitor.rs
index b08aa35f8f8..9859100a038 100644
--- a/src/visitor.rs
+++ b/src/visitor.rs
@@ -584,7 +584,8 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
                         item.ident,
                         &item.vis,
                         item.span,
-                    );
+                    )
+                    .ok();
                     self.push_rewrite(item.span, rewrite);
                 }
                 ast::ItemKind::Delegation(..) | ast::ItemKind::DelegationMac(..) => {
@@ -683,7 +684,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
 
         // 1 = ;
         let shape = self.shape().saturating_sub_width(1);
-        let rewrite = self.with_context(|ctx| rewrite_macro(mac, ident, ctx, shape, pos));
+        let rewrite = self.with_context(|ctx| rewrite_macro(mac, ident, ctx, shape, pos).ok());
         // As of v638 of the rustc-ap-* crates, the associated span no longer includes
         // the trailing semicolon. This determines the correct span to ensure scenarios
         // with whitespace between the delimiters and trailing semi (i.e. `foo!(abc)     ;`)