From fcd6d93cd975a8bd18a5c90b1687def7d9f88e0e Mon Sep 17 00:00:00 2001 From: ding-young Date: Mon, 22 Jul 2024 14:55:54 +0900 Subject: [PATCH] update macro rewrite functions to return RewriteResult --- src/expr.rs | 17 ++-- src/items.rs | 2 +- src/macros.rs | 251 +++++++++++++++++++++++++++++------------------- src/patterns.rs | 2 +- src/rewrite.rs | 32 ++++++ src/types.rs | 2 +- src/visitor.rs | 5 +- 7 files changed, 199 insertions(+), 112 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..18ba4f19ad7 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 { + 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 { + 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 { +) -> 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) + .unknown_error(); } 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 { +) -> 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 { + macro_error_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 { +) -> 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,20 +235,18 @@ 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()) { + if let success @ Ok(..) = format_lazy_static(context, shape, ts.clone(), mac.span()) { return success; } } @@ -266,7 +284,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 +301,6 @@ fn rewrite_macro_inner( Some(SeparatorTactic::Never) }, ) - .ok() .map(|rw| match position { MacroPosition::Item => format!("{};", rw), _ => rw, @@ -293,7 +310,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 +334,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 +349,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 +363,32 @@ fn handle_vec_semi( arg_vec: Vec, macro_name: String, delim_token: Delimiter, -) -> Option { + 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 +406,7 @@ fn rewrite_empty_macro_def_body( context: &RewriteContext<'_>, span: Span, shape: Shape, -) -> Option { +) -> RewriteResult { // Create an empty, dummy `ast::Block` representing an empty macro body let block = ast::Block { stmts: vec![].into(), @@ -396,7 +416,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 +427,8 @@ pub(crate) fn rewrite_macro_def( ident: symbol::Ident, vis: &ast::Visibility, span: Span, -) -> Option { - 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; } @@ -417,7 +437,9 @@ pub(crate) fn rewrite_macro_def( let mut parser = MacroParser::new(ts.trees()); let parsed_def = match parser.parse() { Some(def) => def, - None => return snippet, + None => { + return snippet; + } }; let mut result = if def.macro_rules { @@ -443,7 +465,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 +476,12 @@ 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), - // if the rewrite returned None because a macro could not be rewritten, then return the - // original body - None if context.macro_rewrite_failure.get() => { + Ok(v) => Ok(v), + // 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 +509,7 @@ pub(crate) fn rewrite_macro_def( result += "}"; } - Some(result) + Ok(result) } fn register_metavariable( @@ -640,12 +661,14 @@ impl MacroArgKind { context: &RewriteContext<'_>, shape: Shape, use_multiple_lines: bool, - ) -> Option { - let rewrite_delimited_inner = |delim_tok, args| -> Option<(String, String, String)> { + ) -> RewriteResult { + let rewrite_delimited_inner = |delim_tok, + args| + -> Result<(String, String, String), RewriteError> { 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 +676,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 +712,7 @@ impl ParsedMacroArg { context: &RewriteContext<'_>, shape: Shape, use_multiple_lines: bool, - ) -> Option { + ) -> RewriteResult { self.kind.rewrite(context, shape, use_multiple_lines) } } @@ -967,9 +990,9 @@ fn wrap_macro_args( context: &RewriteContext<'_>, args: &[ParsedMacroArg], shape: Shape, -) -> Option { +) -> 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 +1000,7 @@ fn wrap_macro_args_inner( args: &[ParsedMacroArg], shape: Shape, use_multiple_lines: bool, -) -> Option { +) -> 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 +1026,10 @@ fn wrap_macro_args_inner( } if !use_multiple_lines && result.len() >= shape.width { - None + // This error won't be propagated since we will retry wrapping args in multiple lines + Err(RewriteError::Unknown) } else { - Some(result) + Ok(result) } } @@ -1013,22 +1037,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 { +) -> 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 +1264,14 @@ impl MacroBranch { context: &RewriteContext<'_>, shape: Shape, multi_branch_style: bool, - ) -> Option { + ) -> 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 { + macro_error_kind: MacroErrorKind::Unknown, + span: self.span, + }); } let old_body = context.snippet(self.body).trim(); @@ -1256,8 +1282,14 @@ impl MacroBranch { prefix_width = 6; // 6 = " => {{" } } - let mut result = - format_macro_args(context, self.args.clone(), shape.sub_width(prefix_width)?)?; + // TODO (1) which span to use? (2) Is it max width err or macro failure? + 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 +1298,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 +1307,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 +1331,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 { + macro_error_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 +1371,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 { + macro_error_kind: MacroErrorKind::ReplaceMacroVariable, + span: self.span, + }); } new_body = new_body.replace(new, old); } @@ -1345,7 +1389,7 @@ impl MacroBranch { result += "}"; - Some(result) + Ok(result) } } @@ -1365,7 +1409,8 @@ fn format_lazy_static( context: &RewriteContext<'_>, shape: Shape, ts: TokenStream, -) -> Option { + span: Span, +) -> RewriteResult { let mut result = String::with_capacity(1024); let nested_shape = shape .block_indent(context.config.tab_spaces()) @@ -1374,7 +1419,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 +1430,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 +1453,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 +1465,12 @@ fn rewrite_macro_with_items( original_style: Delimiter, position: MacroPosition, span: Span, -) -> Option { +) -> 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 +1492,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 +1505,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..db97ca2c567 100644 --- a/src/rewrite.rs +++ b/src/rewrite.rs @@ -1,6 +1,7 @@ // A generic trait to abstract the rewriting of an element (of the AST). use std::cell::{Cell, RefCell}; +use std::fmt::{self}; use std::rc::Rc; use rustc_ast::ptr; @@ -30,6 +31,23 @@ impl Rewrite for ptr::P { } } +#[derive(Clone, Debug)] +pub(crate) enum MacroErrorKind { + ParseFailure, + ReplaceMacroVariable, + Unknown, +} + +impl fmt::Display for MacroErrorKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> 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 +56,12 @@ 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:?}", macro_error_kind)] + MacroFailure { + macro_error_kind: MacroErrorKind, + span: Span, + }, + /// Format failure that does not fit to above categories. #[error("An unknown error occurred during formatting.")] Unknown, @@ -46,6 +70,7 @@ pub(crate) enum RewriteError { /// Extension trait used to conveniently convert to RewriteError pub(crate) trait RewriteErrorExt { fn max_width_error(self, width: usize, span: Span) -> Result; + fn macro_error(self, kind: MacroErrorKind, span: Span) -> Result; fn unknown_error(self) -> Result; } @@ -57,6 +82,13 @@ impl RewriteErrorExt for Option { }) } + fn macro_error(self, kind: MacroErrorKind, span: Span) -> Result { + self.ok_or_else(|| RewriteError::MacroFailure { + macro_error_kind: kind, + span: span, + }) + } + fn unknown_error(self) -> Result { 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) ;`)